diff --git a/src/ast.d.ts b/src/ast.d.ts index 94182af46..bd905b33c 100644 --- a/src/ast.d.ts +++ b/src/ast.d.ts @@ -39,30 +39,29 @@ export const enum SyntaxKind { BoltBracketed = 43, BoltSourceFile = 44, BoltQualName = 45, - BoltSentence = 46, - BoltReferenceTypeExpression = 48, - BoltTypeParameter = 49, - BoltBindPattern = 51, - BoltTypePattern = 52, - BoltExpressionPattern = 53, - BoltTuplePatternElement = 54, - BoltTuplePattern = 55, - BoltRecordPatternField = 56, - BoltRecordPattern = 57, - BoltReferenceExpression = 59, - BoltCallExpression = 60, - BoltYieldExpression = 61, - BoltMatchArm = 62, - BoltMatchExpression = 63, - BoltCase = 64, - BoltCaseExpression = 65, - BoltBlockExpression = 66, - BoltConstantExpression = 67, - BoltReturnStatement = 69, - BoltResumeStatement = 70, - BoltExpressionStatement = 71, - BoltParameter = 72, - BoltModule = 75, + BoltReferenceTypeExpression = 47, + BoltTypeParameter = 48, + BoltBindPattern = 50, + BoltTypePattern = 51, + BoltExpressionPattern = 52, + BoltTuplePatternElement = 53, + BoltTuplePattern = 54, + BoltRecordPatternField = 55, + BoltRecordPattern = 56, + BoltReferenceExpression = 58, + BoltCallExpression = 59, + BoltYieldExpression = 60, + BoltMatchArm = 61, + BoltMatchExpression = 62, + BoltCase = 63, + BoltCaseExpression = 64, + BoltBlockExpression = 65, + BoltConstantExpression = 66, + BoltReturnStatement = 68, + BoltResumeStatement = 69, + BoltExpressionStatement = 70, + BoltParameter = 71, + BoltModule = 74, BoltFunctionDeclaration = 76, BoltVariableDeclaration = 77, BoltPlainImportSymbol = 79, @@ -70,70 +69,71 @@ export const enum SyntaxKind { BoltTraitDeclaration = 81, BoltImplDeclaration = 82, BoltTypeAliasDeclaration = 83, - BoltRecordDeclarationField = 84, - BoltRecordDeclaration = 85, - JSOperator = 89, - JSIdentifier = 90, - JSString = 91, - JSInteger = 92, - JSFromKeyword = 93, - JSReturnKeyword = 94, - JSTryKeyword = 95, - JSFinallyKeyword = 96, - JSCatchKeyword = 97, - JSImportKeyword = 98, - JSAsKeyword = 99, - JSConstKeyword = 100, - JSLetKeyword = 101, - JSExportKeyword = 102, - JSFunctionKeyword = 103, - JSWhileKeyword = 104, - JSForKeyword = 105, - JSCloseBrace = 106, - JSCloseBracket = 107, - JSCloseParen = 108, - JSOpenBrace = 109, - JSOpenBracket = 110, - JSOpenParen = 111, - JSSemi = 112, - JSComma = 113, - JSDot = 114, - JSDotDotDot = 115, - JSMulOp = 116, - JSAddOp = 117, - JSDivOp = 118, - JSSubOp = 119, - JSLtOp = 120, - JSGtOp = 121, - JSBOrOp = 122, - JSBXorOp = 123, - JSBAndOp = 124, - JSBNotOp = 125, - JSNotOp = 126, - JSBindPattern = 128, - JSConstantExpression = 130, - JSMemberExpression = 131, - JSCallExpression = 132, - JSBinaryExpression = 133, - JSUnaryExpression = 134, - JSNewExpression = 135, - JSSequenceExpression = 136, - JSConditionalExpression = 137, - JSLiteralExpression = 139, - JSReferenceExpression = 140, - JSCatchBlock = 143, - JSTryCatchStatement = 144, - JSExpressionStatement = 145, - JSConditionalStatement = 146, - JSReturnStatement = 147, - JSParameter = 148, - JSImportStarBinding = 152, - JSImportAsBinding = 153, - JSImportDeclaration = 154, - JSFunctionDeclaration = 155, - JSArrowFunctionDeclaration = 156, - JSLetDeclaration = 157, - JSSourceFile = 158, + BoltRecordField = 85, + BoltRecordDeclaration = 86, + BoltMacroCall = 88, + JSOperator = 91, + JSIdentifier = 92, + JSString = 93, + JSInteger = 94, + JSFromKeyword = 95, + JSReturnKeyword = 96, + JSTryKeyword = 97, + JSFinallyKeyword = 98, + JSCatchKeyword = 99, + JSImportKeyword = 100, + JSAsKeyword = 101, + JSConstKeyword = 102, + JSLetKeyword = 103, + JSExportKeyword = 104, + JSFunctionKeyword = 105, + JSWhileKeyword = 106, + JSForKeyword = 107, + JSCloseBrace = 108, + JSCloseBracket = 109, + JSCloseParen = 110, + JSOpenBrace = 111, + JSOpenBracket = 112, + JSOpenParen = 113, + JSSemi = 114, + JSComma = 115, + JSDot = 116, + JSDotDotDot = 117, + JSMulOp = 118, + JSAddOp = 119, + JSDivOp = 120, + JSSubOp = 121, + JSLtOp = 122, + JSGtOp = 123, + JSBOrOp = 124, + JSBXorOp = 125, + JSBAndOp = 126, + JSBNotOp = 127, + JSNotOp = 128, + JSBindPattern = 130, + JSConstantExpression = 132, + JSMemberExpression = 133, + JSCallExpression = 134, + JSBinaryExpression = 135, + JSUnaryExpression = 136, + JSNewExpression = 137, + JSSequenceExpression = 138, + JSConditionalExpression = 139, + JSLiteralExpression = 141, + JSReferenceExpression = 142, + JSCatchBlock = 145, + JSTryCatchStatement = 146, + JSExpressionStatement = 147, + JSConditionalStatement = 148, + JSReturnStatement = 149, + JSParameter = 150, + JSImportStarBinding = 154, + JSImportAsBinding = 155, + JSImportDeclaration = 156, + JSFunctionDeclaration = 157, + JSArrowFunctionDeclaration = 158, + JSLetDeclaration = 159, + JSSourceFile = 160, } @@ -144,16 +144,21 @@ export function setParents(node: Syntax): void; export type SyntaxRange = [Syntax, Syntax]; -interface SyntaxBase { - kind: SyntaxKind; - parentNode: Syntax | null; +interface SyntaxBase { + kind: K; + parentNode: ParentTypesOf | null; span: TextSpan | null; + getChildNodes(): IterableIterator>, + findAllChildrenOfKind(kind: K1): IterableIterator>; } -export interface EndOfFile extends SyntaxBase { + +export type ResolveSyntaxKind = Extract; + +export interface EndOfFile extends SyntaxBase { kind: SyntaxKind.EndOfFile; } -export interface FunctionBody extends SyntaxBase { +export interface FunctionBody extends SyntaxBase { kind: SyntaxKind.FunctionBody; } @@ -196,12 +201,12 @@ export type BoltToken | BoltBracketed -export interface BoltStringLiteral extends SyntaxBase { +export interface BoltStringLiteral extends SyntaxBase { kind: SyntaxKind.BoltStringLiteral; value: string; } -export interface BoltIntegerLiteral extends SyntaxBase { +export interface BoltIntegerLiteral extends SyntaxBase { kind: SyntaxKind.BoltIntegerLiteral; value: bigint; } @@ -211,58 +216,58 @@ export type BoltSymbol | BoltOperator -export interface BoltIdentifier extends SyntaxBase { +export interface BoltIdentifier extends SyntaxBase { kind: SyntaxKind.BoltIdentifier; text: string; } -export interface BoltOperator extends SyntaxBase { +export interface BoltOperator extends SyntaxBase { kind: SyntaxKind.BoltOperator; text: string; } -export interface BoltAssignment extends SyntaxBase { +export interface BoltAssignment extends SyntaxBase { kind: SyntaxKind.BoltAssignment; operator: string | null; } -export interface BoltComma extends SyntaxBase { +export interface BoltComma extends SyntaxBase { kind: SyntaxKind.BoltComma; } -export interface BoltSemi extends SyntaxBase { +export interface BoltSemi extends SyntaxBase { kind: SyntaxKind.BoltSemi; } -export interface BoltColon extends SyntaxBase { +export interface BoltColon extends SyntaxBase { kind: SyntaxKind.BoltColon; } -export interface BoltDot extends SyntaxBase { +export interface BoltDot extends SyntaxBase { kind: SyntaxKind.BoltDot; } -export interface BoltDotDot extends SyntaxBase { +export interface BoltDotDot extends SyntaxBase { kind: SyntaxKind.BoltDotDot; } -export interface BoltRArrow extends SyntaxBase { +export interface BoltRArrow extends SyntaxBase { kind: SyntaxKind.BoltRArrow; } -export interface BoltLArrow extends SyntaxBase { +export interface BoltLArrow extends SyntaxBase { kind: SyntaxKind.BoltLArrow; } -export interface BoltEqSign extends SyntaxBase { +export interface BoltEqSign extends SyntaxBase { kind: SyntaxKind.BoltEqSign; } -export interface BoltGtSign extends SyntaxBase { +export interface BoltGtSign extends SyntaxBase { kind: SyntaxKind.BoltGtSign; } -export interface BoltLtSign extends SyntaxBase { +export interface BoltLtSign extends SyntaxBase { kind: SyntaxKind.BoltLtSign; } @@ -286,71 +291,71 @@ export type BoltKeyword | BoltImplKeyword -export interface BoltFnKeyword extends SyntaxBase { +export interface BoltFnKeyword extends SyntaxBase { kind: SyntaxKind.BoltFnKeyword; } -export interface BoltForeignKeyword extends SyntaxBase { +export interface BoltForeignKeyword extends SyntaxBase { kind: SyntaxKind.BoltForeignKeyword; } -export interface BoltForKeyword extends SyntaxBase { +export interface BoltForKeyword extends SyntaxBase { kind: SyntaxKind.BoltForKeyword; } -export interface BoltLetKeyword extends SyntaxBase { +export interface BoltLetKeyword extends SyntaxBase { kind: SyntaxKind.BoltLetKeyword; } -export interface BoltReturnKeyword extends SyntaxBase { +export interface BoltReturnKeyword extends SyntaxBase { kind: SyntaxKind.BoltReturnKeyword; } -export interface BoltLoopKeyword extends SyntaxBase { +export interface BoltLoopKeyword extends SyntaxBase { kind: SyntaxKind.BoltLoopKeyword; } -export interface BoltYieldKeyword extends SyntaxBase { +export interface BoltYieldKeyword extends SyntaxBase { kind: SyntaxKind.BoltYieldKeyword; } -export interface BoltMatchKeyword extends SyntaxBase { +export interface BoltMatchKeyword extends SyntaxBase { kind: SyntaxKind.BoltMatchKeyword; } -export interface BoltImportKeyword extends SyntaxBase { +export interface BoltImportKeyword extends SyntaxBase { kind: SyntaxKind.BoltImportKeyword; } -export interface BoltPubKeyword extends SyntaxBase { +export interface BoltPubKeyword extends SyntaxBase { kind: SyntaxKind.BoltPubKeyword; } -export interface BoltModKeyword extends SyntaxBase { +export interface BoltModKeyword extends SyntaxBase { kind: SyntaxKind.BoltModKeyword; } -export interface BoltMutKeyword extends SyntaxBase { +export interface BoltMutKeyword extends SyntaxBase { kind: SyntaxKind.BoltMutKeyword; } -export interface BoltEnumKeyword extends SyntaxBase { +export interface BoltEnumKeyword extends SyntaxBase { kind: SyntaxKind.BoltEnumKeyword; } -export interface BoltStructKeyword extends SyntaxBase { +export interface BoltStructKeyword extends SyntaxBase { kind: SyntaxKind.BoltStructKeyword; } -export interface BoltTypeKeyword extends SyntaxBase { +export interface BoltTypeKeyword extends SyntaxBase { kind: SyntaxKind.BoltTypeKeyword; } -export interface BoltTraitKeyword extends SyntaxBase { +export interface BoltTraitKeyword extends SyntaxBase { kind: SyntaxKind.BoltTraitKeyword; } -export interface BoltImplKeyword extends SyntaxBase { +export interface BoltImplKeyword extends SyntaxBase { kind: SyntaxKind.BoltImplKeyword; } @@ -360,48 +365,43 @@ export type BoltPunctuated | BoltBracketed -export interface BoltParenthesized extends SyntaxBase { +export interface BoltParenthesized extends SyntaxBase { kind: SyntaxKind.BoltParenthesized; text: string; } -export interface BoltBraced extends SyntaxBase { +export interface BoltBraced extends SyntaxBase { kind: SyntaxKind.BoltBraced; text: string; } -export interface BoltBracketed extends SyntaxBase { +export interface BoltBracketed extends SyntaxBase { kind: SyntaxKind.BoltBracketed; text: string; } -export interface BoltSourceFile extends SyntaxBase { +export interface BoltSourceFile extends SyntaxBase { kind: SyntaxKind.BoltSourceFile; elements: BoltSourceElement[]; } -export interface BoltQualName extends SyntaxBase { +export interface BoltQualName extends SyntaxBase { kind: SyntaxKind.BoltQualName; modulePath: BoltIdentifier[]; name: BoltSymbol; } -export interface BoltSentence extends SyntaxBase { - kind: SyntaxKind.BoltSentence; - tokens: BoltToken[]; -} - export type BoltTypeExpression = BoltReferenceTypeExpression -export interface BoltReferenceTypeExpression extends SyntaxBase { +export interface BoltReferenceTypeExpression extends SyntaxBase { kind: SyntaxKind.BoltReferenceTypeExpression; name: BoltQualName; arguments: BoltTypeExpression[] | null; } -export interface BoltTypeParameter extends SyntaxBase { +export interface BoltTypeParameter extends SyntaxBase { kind: SyntaxKind.BoltTypeParameter; index: number; name: BoltIdentifier; @@ -416,40 +416,40 @@ export type BoltPattern | BoltRecordPattern -export interface BoltBindPattern extends SyntaxBase { +export interface BoltBindPattern extends SyntaxBase { kind: SyntaxKind.BoltBindPattern; name: BoltIdentifier; } -export interface BoltTypePattern extends SyntaxBase { +export interface BoltTypePattern extends SyntaxBase { kind: SyntaxKind.BoltTypePattern; type: BoltTypeExpression; nestedPattern: BoltPattern; } -export interface BoltExpressionPattern extends SyntaxBase { +export interface BoltExpressionPattern extends SyntaxBase { kind: SyntaxKind.BoltExpressionPattern; expression: BoltExpression; } -export interface BoltTuplePatternElement extends SyntaxBase { +export interface BoltTuplePatternElement extends SyntaxBase { kind: SyntaxKind.BoltTuplePatternElement; index: number; pattern: BoltPattern; } -export interface BoltTuplePattern extends SyntaxBase { +export interface BoltTuplePattern extends SyntaxBase { kind: SyntaxKind.BoltTuplePattern; elements: BoltTuplePatternElement[]; } -export interface BoltRecordPatternField extends SyntaxBase { +export interface BoltRecordPatternField extends SyntaxBase { kind: SyntaxKind.BoltRecordPatternField; name: BoltIdentifier; pattern: BoltPattern; } -export interface BoltRecordPattern extends SyntaxBase { +export interface BoltRecordPattern extends SyntaxBase { kind: SyntaxKind.BoltRecordPattern; name: BoltTypeExpression; fields: BoltRecordPatternField[]; @@ -463,53 +463,54 @@ export type BoltExpression | BoltCaseExpression | BoltBlockExpression | BoltConstantExpression + | BoltMacroCall -export interface BoltReferenceExpression extends SyntaxBase { +export interface BoltReferenceExpression extends SyntaxBase { kind: SyntaxKind.BoltReferenceExpression; name: BoltQualName; } -export interface BoltCallExpression extends SyntaxBase { +export interface BoltCallExpression extends SyntaxBase { kind: SyntaxKind.BoltCallExpression; operator: BoltExpression; operands: BoltExpression[]; } -export interface BoltYieldExpression extends SyntaxBase { +export interface BoltYieldExpression extends SyntaxBase { kind: SyntaxKind.BoltYieldExpression; value: BoltExpression; } -export interface BoltMatchArm extends SyntaxBase { +export interface BoltMatchArm extends SyntaxBase { kind: SyntaxKind.BoltMatchArm; pattern: BoltPattern; body: BoltExpression; } -export interface BoltMatchExpression extends SyntaxBase { +export interface BoltMatchExpression extends SyntaxBase { kind: SyntaxKind.BoltMatchExpression; value: BoltExpression; arms: BoltMatchArm[]; } -export interface BoltCase extends SyntaxBase { +export interface BoltCase extends SyntaxBase { kind: SyntaxKind.BoltCase; test: BoltExpression; result: BoltExpression; } -export interface BoltCaseExpression extends SyntaxBase { +export interface BoltCaseExpression extends SyntaxBase { kind: SyntaxKind.BoltCaseExpression; cases: BoltCase[]; } -export interface BoltBlockExpression extends SyntaxBase { +export interface BoltBlockExpression extends SyntaxBase { kind: SyntaxKind.BoltBlockExpression; statements: BoltStatement[]; } -export interface BoltConstantExpression extends SyntaxBase { +export interface BoltConstantExpression extends SyntaxBase { kind: SyntaxKind.BoltConstantExpression; value: BoltValue; } @@ -518,24 +519,25 @@ export type BoltStatement = BoltReturnStatement | BoltResumeStatement | BoltExpressionStatement + | BoltMacroCall -export interface BoltReturnStatement extends SyntaxBase { +export interface BoltReturnStatement extends SyntaxBase { kind: SyntaxKind.BoltReturnStatement; value: BoltExpression | null; } -export interface BoltResumeStatement extends SyntaxBase { +export interface BoltResumeStatement extends SyntaxBase { kind: SyntaxKind.BoltResumeStatement; value: BoltExpression; } -export interface BoltExpressionStatement extends SyntaxBase { +export interface BoltExpressionStatement extends SyntaxBase { kind: SyntaxKind.BoltExpressionStatement; expression: BoltExpression; } -export interface BoltParameter extends SyntaxBase { +export interface BoltParameter extends SyntaxBase { kind: SyntaxKind.BoltParameter; index: number; bindings: BoltPattern; @@ -552,19 +554,29 @@ export type BoltDeclaration | BoltImplDeclaration | BoltTypeAliasDeclaration | BoltRecordDeclaration + | BoltMacroCall export const enum BoltDeclarationModifiers { Mutable = 1,Public = 2,IsType = 4,IsForeign = 8,} -export interface BoltModule extends SyntaxBase { +export interface BoltModule extends SyntaxBase { kind: SyntaxKind.BoltModule; modifiers: BoltDeclarationModifiers; name: BoltQualName; elements: BoltSourceElement[]; } -export interface BoltFunctionDeclaration extends SyntaxBase { +export type BoltFunctionBodyElement + = BoltReturnStatement + | BoltResumeStatement + | BoltExpressionStatement + | BoltMacroCall + | BoltFunctionDeclaration + | BoltVariableDeclaration + + +export interface BoltFunctionDeclaration extends SyntaxBase { kind: SyntaxKind.BoltFunctionDeclaration; modifiers: BoltDeclarationModifiers; target: string; @@ -574,7 +586,7 @@ export interface BoltFunctionDeclaration extends SyntaxBase { body: BoltStatement[]; } -export interface BoltVariableDeclaration extends SyntaxBase { +export interface BoltVariableDeclaration extends SyntaxBase { kind: SyntaxKind.BoltVariableDeclaration; modifiers: BoltDeclarationModifiers; bindings: BoltPattern; @@ -586,18 +598,18 @@ export type BoltImportSymbol = BoltPlainImportSymbol -export interface BoltPlainImportSymbol extends SyntaxBase { +export interface BoltPlainImportSymbol extends SyntaxBase { kind: SyntaxKind.BoltPlainImportSymbol; name: BoltQualName; } -export interface BoltImportDeclaration extends SyntaxBase { +export interface BoltImportDeclaration extends SyntaxBase { kind: SyntaxKind.BoltImportDeclaration; file: string; symbols: BoltImportSymbol[]; } -export interface BoltTraitDeclaration extends SyntaxBase { +export interface BoltTraitDeclaration extends SyntaxBase { kind: SyntaxKind.BoltTraitDeclaration; modifiers: BoltDeclarationModifiers; name: BoltIdentifier; @@ -605,7 +617,7 @@ export interface BoltTraitDeclaration extends SyntaxBase { elements: BoltDeclaration[]; } -export interface BoltImplDeclaration extends SyntaxBase { +export interface BoltImplDeclaration extends SyntaxBase { kind: SyntaxKind.BoltImplDeclaration; modifiers: BoltDeclarationModifiers; name: BoltIdentifier; @@ -614,7 +626,7 @@ export interface BoltImplDeclaration extends SyntaxBase { elements: BoltDeclaration[]; } -export interface BoltTypeAliasDeclaration extends SyntaxBase { +export interface BoltTypeAliasDeclaration extends SyntaxBase { kind: SyntaxKind.BoltTypeAliasDeclaration; modifiers: BoltDeclarationModifiers; name: BoltIdentifier; @@ -622,25 +634,30 @@ export interface BoltTypeAliasDeclaration extends SyntaxBase { typeExpr: BoltTypeExpression; } -export interface BoltRecordDeclarationField extends SyntaxBase { - kind: SyntaxKind.BoltRecordDeclarationField; +export type BoltRecordMember + = BoltRecordField + | BoltMacroCall + + +export interface BoltRecordField extends SyntaxBase { + kind: SyntaxKind.BoltRecordField; name: BoltIdentifier; type: BoltTypeExpression; } -export interface BoltRecordDeclaration extends SyntaxBase { +export interface BoltRecordDeclaration extends SyntaxBase { kind: SyntaxKind.BoltRecordDeclaration; modifiers: BoltDeclarationModifiers; name: BoltQualName; typeParms: BoltTypeParameter[] | null; - fields: BoltRecordDeclarationField[]; + members: BoltRecordMember[] | null; } export type BoltSourceElement - = BoltSentence - | BoltReturnStatement + = BoltReturnStatement | BoltResumeStatement | BoltExpressionStatement + | BoltMacroCall | BoltModule | BoltFunctionDeclaration | BoltVariableDeclaration @@ -649,8 +666,15 @@ export type BoltSourceElement | BoltImplDeclaration | BoltTypeAliasDeclaration | BoltRecordDeclaration + | BoltMacroCall +export interface BoltMacroCall extends SyntaxBase { + kind: SyntaxKind.BoltMacroCall; + name: BoltIdentifier; + text: string; +} + export type JSToken = EndOfFile | JSOperator @@ -693,159 +717,159 @@ export type JSToken | JSNotOp -export interface JSOperator extends SyntaxBase { +export interface JSOperator extends SyntaxBase { kind: SyntaxKind.JSOperator; text: string; } -export interface JSIdentifier extends SyntaxBase { +export interface JSIdentifier extends SyntaxBase { kind: SyntaxKind.JSIdentifier; text: string; } -export interface JSString extends SyntaxBase { +export interface JSString extends SyntaxBase { kind: SyntaxKind.JSString; value: string; } -export interface JSInteger extends SyntaxBase { +export interface JSInteger extends SyntaxBase { kind: SyntaxKind.JSInteger; value: bigint; } -export interface JSFromKeyword extends SyntaxBase { +export interface JSFromKeyword extends SyntaxBase { kind: SyntaxKind.JSFromKeyword; } -export interface JSReturnKeyword extends SyntaxBase { +export interface JSReturnKeyword extends SyntaxBase { kind: SyntaxKind.JSReturnKeyword; } -export interface JSTryKeyword extends SyntaxBase { +export interface JSTryKeyword extends SyntaxBase { kind: SyntaxKind.JSTryKeyword; } -export interface JSFinallyKeyword extends SyntaxBase { +export interface JSFinallyKeyword extends SyntaxBase { kind: SyntaxKind.JSFinallyKeyword; } -export interface JSCatchKeyword extends SyntaxBase { +export interface JSCatchKeyword extends SyntaxBase { kind: SyntaxKind.JSCatchKeyword; } -export interface JSImportKeyword extends SyntaxBase { +export interface JSImportKeyword extends SyntaxBase { kind: SyntaxKind.JSImportKeyword; } -export interface JSAsKeyword extends SyntaxBase { +export interface JSAsKeyword extends SyntaxBase { kind: SyntaxKind.JSAsKeyword; } -export interface JSConstKeyword extends SyntaxBase { +export interface JSConstKeyword extends SyntaxBase { kind: SyntaxKind.JSConstKeyword; } -export interface JSLetKeyword extends SyntaxBase { +export interface JSLetKeyword extends SyntaxBase { kind: SyntaxKind.JSLetKeyword; } -export interface JSExportKeyword extends SyntaxBase { +export interface JSExportKeyword extends SyntaxBase { kind: SyntaxKind.JSExportKeyword; } -export interface JSFunctionKeyword extends SyntaxBase { +export interface JSFunctionKeyword extends SyntaxBase { kind: SyntaxKind.JSFunctionKeyword; } -export interface JSWhileKeyword extends SyntaxBase { +export interface JSWhileKeyword extends SyntaxBase { kind: SyntaxKind.JSWhileKeyword; } -export interface JSForKeyword extends SyntaxBase { +export interface JSForKeyword extends SyntaxBase { kind: SyntaxKind.JSForKeyword; } -export interface JSCloseBrace extends SyntaxBase { +export interface JSCloseBrace extends SyntaxBase { kind: SyntaxKind.JSCloseBrace; } -export interface JSCloseBracket extends SyntaxBase { +export interface JSCloseBracket extends SyntaxBase { kind: SyntaxKind.JSCloseBracket; } -export interface JSCloseParen extends SyntaxBase { +export interface JSCloseParen extends SyntaxBase { kind: SyntaxKind.JSCloseParen; } -export interface JSOpenBrace extends SyntaxBase { +export interface JSOpenBrace extends SyntaxBase { kind: SyntaxKind.JSOpenBrace; } -export interface JSOpenBracket extends SyntaxBase { +export interface JSOpenBracket extends SyntaxBase { kind: SyntaxKind.JSOpenBracket; } -export interface JSOpenParen extends SyntaxBase { +export interface JSOpenParen extends SyntaxBase { kind: SyntaxKind.JSOpenParen; } -export interface JSSemi extends SyntaxBase { +export interface JSSemi extends SyntaxBase { kind: SyntaxKind.JSSemi; } -export interface JSComma extends SyntaxBase { +export interface JSComma extends SyntaxBase { kind: SyntaxKind.JSComma; } -export interface JSDot extends SyntaxBase { +export interface JSDot extends SyntaxBase { kind: SyntaxKind.JSDot; } -export interface JSDotDotDot extends SyntaxBase { +export interface JSDotDotDot extends SyntaxBase { kind: SyntaxKind.JSDotDotDot; } -export interface JSMulOp extends SyntaxBase { +export interface JSMulOp extends SyntaxBase { kind: SyntaxKind.JSMulOp; } -export interface JSAddOp extends SyntaxBase { +export interface JSAddOp extends SyntaxBase { kind: SyntaxKind.JSAddOp; } -export interface JSDivOp extends SyntaxBase { +export interface JSDivOp extends SyntaxBase { kind: SyntaxKind.JSDivOp; } -export interface JSSubOp extends SyntaxBase { +export interface JSSubOp extends SyntaxBase { kind: SyntaxKind.JSSubOp; } -export interface JSLtOp extends SyntaxBase { +export interface JSLtOp extends SyntaxBase { kind: SyntaxKind.JSLtOp; } -export interface JSGtOp extends SyntaxBase { +export interface JSGtOp extends SyntaxBase { kind: SyntaxKind.JSGtOp; } -export interface JSBOrOp extends SyntaxBase { +export interface JSBOrOp extends SyntaxBase { kind: SyntaxKind.JSBOrOp; } -export interface JSBXorOp extends SyntaxBase { +export interface JSBXorOp extends SyntaxBase { kind: SyntaxKind.JSBXorOp; } -export interface JSBAndOp extends SyntaxBase { +export interface JSBAndOp extends SyntaxBase { kind: SyntaxKind.JSBAndOp; } -export interface JSBNotOp extends SyntaxBase { +export interface JSBNotOp extends SyntaxBase { kind: SyntaxKind.JSBNotOp; } -export interface JSNotOp extends SyntaxBase { +export interface JSNotOp extends SyntaxBase { kind: SyntaxKind.JSNotOp; } @@ -853,7 +877,7 @@ export type JSPattern = JSBindPattern -export interface JSBindPattern extends SyntaxBase { +export interface JSBindPattern extends SyntaxBase { kind: SyntaxKind.JSBindPattern; name: JSIdentifier; } @@ -871,60 +895,60 @@ export type JSExpression | JSReferenceExpression -export interface JSConstantExpression extends SyntaxBase { +export interface JSConstantExpression extends SyntaxBase { kind: SyntaxKind.JSConstantExpression; value: BoltValue; } -export interface JSMemberExpression extends SyntaxBase { +export interface JSMemberExpression extends SyntaxBase { kind: SyntaxKind.JSMemberExpression; value: JSExpression; property: JSIdentifier; } -export interface JSCallExpression extends SyntaxBase { +export interface JSCallExpression extends SyntaxBase { kind: SyntaxKind.JSCallExpression; operator: JSExpression; operands: JSExpression[]; } -export interface JSBinaryExpression extends SyntaxBase { +export interface JSBinaryExpression extends SyntaxBase { kind: SyntaxKind.JSBinaryExpression; left: JSExpression; operator: JSOperator; right: JSExpression; } -export interface JSUnaryExpression extends SyntaxBase { +export interface JSUnaryExpression extends SyntaxBase { kind: SyntaxKind.JSUnaryExpression; operator: JSOperator; operand: JSExpression; } -export interface JSNewExpression extends SyntaxBase { +export interface JSNewExpression extends SyntaxBase { kind: SyntaxKind.JSNewExpression; target: JSExpression; arguments: JSExpression[]; } -export interface JSSequenceExpression extends SyntaxBase { +export interface JSSequenceExpression extends SyntaxBase { kind: SyntaxKind.JSSequenceExpression; expressions: JSExpression[]; } -export interface JSConditionalExpression extends SyntaxBase { +export interface JSConditionalExpression extends SyntaxBase { kind: SyntaxKind.JSConditionalExpression; test: JSExpression; consequent: JSExpression; alternate: JSExpression; } -export interface JSLiteralExpression extends SyntaxBase { +export interface JSLiteralExpression extends SyntaxBase { kind: SyntaxKind.JSLiteralExpression; value: JSValue; } -export interface JSReferenceExpression extends SyntaxBase { +export interface JSReferenceExpression extends SyntaxBase { kind: SyntaxKind.JSReferenceExpression; name: string; } @@ -945,37 +969,37 @@ export type JSStatement | JSReturnStatement -export interface JSCatchBlock extends SyntaxBase { +export interface JSCatchBlock extends SyntaxBase { kind: SyntaxKind.JSCatchBlock; bindings: JSPattern | null; elements: JSSourceElement[]; } -export interface JSTryCatchStatement extends SyntaxBase { +export interface JSTryCatchStatement extends SyntaxBase { kind: SyntaxKind.JSTryCatchStatement; tryBlock: JSSourceElement[]; catchBlock: JSCatchBlock | null; finalBlock: JSSourceElement[] | null; } -export interface JSExpressionStatement extends SyntaxBase { +export interface JSExpressionStatement extends SyntaxBase { kind: SyntaxKind.JSExpressionStatement; expression: JSExpression; } -export interface JSConditionalStatement extends SyntaxBase { +export interface JSConditionalStatement extends SyntaxBase { kind: SyntaxKind.JSConditionalStatement; test: JSExpression; consequent: JSStatement[]; alternate: JSStatement[]; } -export interface JSReturnStatement extends SyntaxBase { +export interface JSReturnStatement extends SyntaxBase { kind: SyntaxKind.JSReturnStatement; value: JSExpression | null; } -export interface JSParameter extends SyntaxBase { +export interface JSParameter extends SyntaxBase { kind: SyntaxKind.JSParameter; index: number; bindings: JSPattern; @@ -997,24 +1021,24 @@ export type JSImportBinding | JSImportAsBinding -export interface JSImportStarBinding extends SyntaxBase { +export interface JSImportStarBinding extends SyntaxBase { kind: SyntaxKind.JSImportStarBinding; local: JSIdentifier; } -export interface JSImportAsBinding extends SyntaxBase { +export interface JSImportAsBinding extends SyntaxBase { kind: SyntaxKind.JSImportAsBinding; remote: JSIdentifier; local: JSIdentifier | null; } -export interface JSImportDeclaration extends SyntaxBase { +export interface JSImportDeclaration extends SyntaxBase { kind: SyntaxKind.JSImportDeclaration; bindings: JSImportBinding[]; filename: JSString; } -export interface JSFunctionDeclaration extends SyntaxBase { +export interface JSFunctionDeclaration extends SyntaxBase { kind: SyntaxKind.JSFunctionDeclaration; modifiers: JSDeclarationModifiers; name: JSIdentifier; @@ -1022,20 +1046,20 @@ export interface JSFunctionDeclaration extends SyntaxBase { body: JSStatement[]; } -export interface JSArrowFunctionDeclaration extends SyntaxBase { +export interface JSArrowFunctionDeclaration extends SyntaxBase { kind: SyntaxKind.JSArrowFunctionDeclaration; name: JSIdentifier; params: JSParameter[]; body: JSExpression; } -export interface JSLetDeclaration extends SyntaxBase { +export interface JSLetDeclaration extends SyntaxBase { kind: SyntaxKind.JSLetDeclaration; bindings: JSPattern; value: JSExpression | null; } -export interface JSSourceFile extends SyntaxBase { +export interface JSSourceFile extends SyntaxBase { kind: SyntaxKind.JSSourceFile; elements: JSSourceElement[]; } @@ -1078,7 +1102,6 @@ export type BoltSyntax | BoltBracketed | BoltSourceFile | BoltQualName - | BoltSentence | BoltReferenceTypeExpression | BoltTypeParameter | BoltBindPattern @@ -1109,8 +1132,9 @@ export type BoltSyntax | BoltTraitDeclaration | BoltImplDeclaration | BoltTypeAliasDeclaration - | BoltRecordDeclarationField + | BoltRecordField | BoltRecordDeclaration + | BoltMacroCall export type JSSyntax @@ -1218,7 +1242,6 @@ export type Syntax | BoltBracketed | BoltSourceFile | BoltQualName - | BoltSentence | BoltReferenceTypeExpression | BoltTypeParameter | BoltBindPattern @@ -1249,8 +1272,9 @@ export type Syntax | BoltTraitDeclaration | BoltImplDeclaration | BoltTypeAliasDeclaration - | BoltRecordDeclarationField + | BoltRecordField | BoltRecordDeclaration + | BoltMacroCall | JSOperator | JSIdentifier | JSString @@ -1356,7 +1380,6 @@ export function createBoltBraced(text: string, span?: TextSpan | null): BoltBrac export function createBoltBracketed(text: string, span?: TextSpan | null): BoltBracketed; export function createBoltSourceFile(elements: BoltSourceElement[], span?: TextSpan | null): BoltSourceFile; export function createBoltQualName(modulePath: BoltIdentifier[], name: BoltSymbol, span?: TextSpan | null): BoltQualName; -export function createBoltSentence(tokens: BoltToken[], span?: TextSpan | null): BoltSentence; export function createBoltReferenceTypeExpression(name: BoltQualName, arguments: BoltTypeExpression[] | null, span?: TextSpan | null): BoltReferenceTypeExpression; export function createBoltTypeParameter(index: number, name: BoltIdentifier, defaultType: BoltTypeExpression | null, span?: TextSpan | null): BoltTypeParameter; export function createBoltBindPattern(name: BoltIdentifier, span?: TextSpan | null): BoltBindPattern; @@ -1387,8 +1410,9 @@ export function createBoltImportDeclaration(file: string, symbols: BoltImportSym export function createBoltTraitDeclaration(modifiers: BoltDeclarationModifiers, name: BoltIdentifier, typeParams: BoltTypeParameter[] | null, elements: BoltDeclaration[], span?: TextSpan | null): BoltTraitDeclaration; export function createBoltImplDeclaration(modifiers: BoltDeclarationModifiers, name: BoltIdentifier, trait: BoltTypeExpression, typeParams: BoltTypeParameter[] | null, elements: BoltDeclaration[], span?: TextSpan | null): BoltImplDeclaration; export function createBoltTypeAliasDeclaration(modifiers: BoltDeclarationModifiers, name: BoltIdentifier, typeParams: BoltTypeParameter[] | null, typeExpr: BoltTypeExpression, span?: TextSpan | null): BoltTypeAliasDeclaration; -export function createBoltRecordDeclarationField(name: BoltIdentifier, type: BoltTypeExpression, span?: TextSpan | null): BoltRecordDeclarationField; -export function createBoltRecordDeclaration(modifiers: BoltDeclarationModifiers, name: BoltQualName, typeParms: BoltTypeParameter[] | null, fields: BoltRecordDeclarationField[], span?: TextSpan | null): BoltRecordDeclaration; +export function createBoltRecordField(name: BoltIdentifier, type: BoltTypeExpression, span?: TextSpan | null): BoltRecordField; +export function createBoltRecordDeclaration(modifiers: BoltDeclarationModifiers, name: BoltQualName, typeParms: BoltTypeParameter[] | null, members: BoltRecordMember[] | null, span?: TextSpan | null): BoltRecordDeclaration; +export function createBoltMacroCall(name: BoltIdentifier, text: string, span?: TextSpan | null): BoltMacroCall; export function createJSOperator(text: string, span?: TextSpan | null): JSOperator; export function createJSIdentifier(text: string, span?: TextSpan | null): JSIdentifier; export function createJSString(value: string, span?: TextSpan | null): JSString; @@ -1495,7 +1519,6 @@ export function isBoltBraced(value: any): value is BoltBraced; export function isBoltBracketed(value: any): value is BoltBracketed; export function isBoltSourceFile(value: any): value is BoltSourceFile; export function isBoltQualName(value: any): value is BoltQualName; -export function isBoltSentence(value: any): value is BoltSentence; export function isBoltTypeExpression(value: any): value is BoltTypeExpression; export function isBoltReferenceTypeExpression(value: any): value is BoltReferenceTypeExpression; export function isBoltTypeParameter(value: any): value is BoltTypeParameter; @@ -1524,6 +1547,7 @@ export function isBoltExpressionStatement(value: any): value is BoltExpressionSt export function isBoltParameter(value: any): value is BoltParameter; export function isBoltDeclaration(value: any): value is BoltDeclaration; export function isBoltModule(value: any): value is BoltModule; +export function isBoltFunctionBodyElement(value: any): value is BoltFunctionBodyElement; export function isBoltFunctionDeclaration(value: any): value is BoltFunctionDeclaration; export function isBoltVariableDeclaration(value: any): value is BoltVariableDeclaration; export function isBoltImportSymbol(value: any): value is BoltImportSymbol; @@ -1532,9 +1556,11 @@ export function isBoltImportDeclaration(value: any): value is BoltImportDeclarat export function isBoltTraitDeclaration(value: any): value is BoltTraitDeclaration; export function isBoltImplDeclaration(value: any): value is BoltImplDeclaration; export function isBoltTypeAliasDeclaration(value: any): value is BoltTypeAliasDeclaration; -export function isBoltRecordDeclarationField(value: any): value is BoltRecordDeclarationField; +export function isBoltRecordMember(value: any): value is BoltRecordMember; +export function isBoltRecordField(value: any): value is BoltRecordField; export function isBoltRecordDeclaration(value: any): value is BoltRecordDeclaration; export function isBoltSourceElement(value: any): value is BoltSourceElement; +export function isBoltMacroCall(value: any): value is BoltMacroCall; export function isJSToken(value: any): value is JSToken; export function isJSOperator(value: any): value is JSOperator; export function isJSIdentifier(value: any): value is JSIdentifier; diff --git a/src/bin/bolt.ts b/src/bin/bolt.ts index 1ba5de822..6fa1fa53d 100644 --- a/src/bin/bolt.ts +++ b/src/bin/bolt.ts @@ -6,7 +6,9 @@ import "source-map-support/register" import yargs from "yargs" import { Program } from "../program" -import { TextFile } from "../text" +import { parseSourceFile } from "../parser" +import { BoltSourceFile} from "../ast" +import { Frontend } from "../frontend" global.debug = function (value: any) { console.error(require('util').inspect(value, { depth: Infinity, colors: true })) @@ -64,17 +66,16 @@ yargs .string('work-dir') .describe('work-dir', 'The working directory where files will be resolved against.') .default('work-dir', '.') - .string('inspect-server'), + .string('target') + .describe('target', 'The target language to compile to.') + .default('target', 'JS') - args => { + , args => { - const files = toArray(args.files as string[] | string); - const opts = {}; - if (args['inspect-server'] !== undefined) { - opts.inspector = connectToInspector(args['inspect-server'] as string); - } - const program = new Program(files, opts); - program.compile("JS"); + const sourceFiles = toArray(args.files as string[] | string).map(parseSourceFile); + const program = new Program(sourceFiles); + const frontend = new Frontend(); + frontend.compile(program, args.target); }) @@ -90,22 +91,16 @@ yargs args => { - const files = toArray(args.files as string | string[]).map(p => new TextFile(p)); - - if (files.length > 0) { - - const program = new Program(files); - - for (const file of files) { - program.eval(file) - } - - } else { + const sourceFiles = toArray(args.files as string | string[]).map(parseSourceFile); + if (sourceFiles.length === 0) { throw new Error(`Executing packages is not yet supported.`) - } + const program = new Program(sourceFiles); + const frontend = new Frontend(); + frontend.eval(program); + } ) diff --git a/src/compiler.ts b/src/compiler.ts deleted file mode 100644 index dcaa7c0a3..000000000 --- a/src/compiler.ts +++ /dev/null @@ -1,177 +0,0 @@ - -import acorn from "acorn" - -import { - TypeChecker, - Scope -} from "./checker" - -import { - Syntax, - SyntaxKind, - kindToString, - BoltSourceFile, - BoltStatement, - BoltExpression, - BoltDeclaration, - BoltBindPattern, - JSExpression, - JSStatement, - JSSourceElement, - createJSExpressionStatement, - createJSSourceFile, - createJSCallExpression, - createJSReferenceExpression, - createJSConstantExpression, - createJSLetDeclaration, - createJSIdentifier, - createJSFunctionDeclaration, - isBoltExpression, - createJSBindPattern, - JSDeclarationModifiers, - JSParameter, - BoltSyntax, - BoltPattern, -} from "./ast" - -import { getFullTextOfQualName, hasPublicModifier } from "./util" - -import { Program } from "./program" - -export interface CompilerOptions { - target: string; -} - -function pushAll(arr: T[], els: T[]) { - for (const el of els) { - arr.push(el) - } -} - -export class Compiler { - - readonly target: string; - - constructor(public program: Program, public checker: TypeChecker, options: CompilerOptions) { - this.target = options.target; - } - - compile(files: BoltSourceFile[]) { - return files.map(s => { - const body: JSSourceElement[] = []; - for (const element of s.elements) { - this.compileDecl(element, body); - } - return createJSSourceFile(body, s.span); - }); - } - - protected compileExpr(node: Syntax, preamble: Syntax[]): JSExpression { - - switch (node.kind) { - - case SyntaxKind.BoltCallExpression: - const compiledOperator = this.compileExpr(node.operator, preamble); - const compiledArgs = node.operands.map(a => this.compileExpr(a, preamble)) - return createJSCallExpression( - compiledOperator, - compiledArgs, - node.span, - ); - - case SyntaxKind.BoltReferenceExpression: - return createJSReferenceExpression( - getFullTextOfQualName(node.name), - node.span, - ); - - case SyntaxKind.BoltConstantExpression: - return createJSConstantExpression( - node.value, - node.span, - ); - - default: - throw new Error(`Could not compile expression node ${kindToString(node.kind)}`) - } - - } - - private compilePattern(node: BoltPattern) { - - } - - protected compileDecl(node: BoltSyntax, preamble: Syntax[]) { - - //if (isBoltExpression(node)) { - // const compiled = this.compileExpr(node, preamble); - // preamble.push(createJSExpressionStatement(compiled)); - // return; - //} - - switch (node.kind) { - - case SyntaxKind.BoltModule: - for (const element of node.elements) { - this.compileDecl(element, preamble); - } - break; - - case SyntaxKind.BoltExpressionStatement: - preamble.push(this.compileExpr(node.expression, preamble)); - break; - - case SyntaxKind.BoltImportDeclaration: - // TODO - break; - - case SyntaxKind.BoltTypeAliasDeclaration: - break; - - case SyntaxKind.BoltVariableDeclaration: - const compiledValue = node.value !== null ? this.compileExpr(node.value, preamble) : null; - preamble.push( - createJSLetDeclaration( - createJSBindPattern((node.bindings as BoltBindPattern).name, node.bindings.span), - compiledValue, - node.span, - ), - ); - break; - - case SyntaxKind.BoltFunctionDeclaration: - if (node.target === this.target) { - if (node.body === null) { - break; - } - const params: JSParameter[] = []; - let body: JSStatement[] = []; - for (const param of node.params) { - params.push(this.compilePattern(param.bindings, body)); - } - let result = createJSFunctionDeclaration( - 0, - createJSIdentifier(node.name.text, node.name.span), - params, - body, - node.span, - ); - if (hasPublicModifier(node)) { - result.modifiers |= JSDeclarationModifiers.IsExported;; - } - preamble.push(result) - } else { - // TODO - throw new Error(`Compiling native functions is not yet implemented.`); - } - break; - - default: - throw new Error(`Could not compile node ${kindToString(node.kind)}`); - - } - - } - -} - diff --git a/src/constants.ts b/src/constants.ts index 0074255d4..8b1378917 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,7 +1 @@ -export const TYPES = { - Program: Symbol('a Bolt program'), - TypeChecker: Symbol('the Bolt type checking system'), - FileManager: Symbol('the file manager'), -} - diff --git a/src/di.ts b/src/di.ts index 42827b0d7..cdbd82f78 100644 --- a/src/di.ts +++ b/src/di.ts @@ -14,10 +14,11 @@ function isFactory(value: any): boolean { } export function inject(target: any, key: PropertyKey, index: number) { - //return function(target: any) { - // This is a no-op because adding the decorator - // is enough for TypeScript to emit metadata - //} + if (!Reflect.hasMetadata('di:paramindices', target)) { + Reflect.defineMetadata('di:paramindices', [], target) + } + const indices = Reflect.getMetadata('di:paramindices', target); + indices.push(index); } function describeFactory(factory: Factory): string { @@ -37,10 +38,6 @@ export class Container { } } - private canResolve(serviceId: ServiceID): boolean { - return this.singletons.has(serviceId); - } - private resolve(factory: Factory): T; private resolve(serviceId: ServiceID): any { return this.singletons.get(serviceId); @@ -49,12 +46,13 @@ export class Container { public createInstance(factory: Factory, ...args: any[]): T { const newArgs: any[] = []; const paramTypes = Reflect.getMetadata('design:paramtypes', factory); + const indices = Reflect.getMetadata('di:paramindices', factory); if (paramTypes === undefined) { return new factory(...args); } let i = 0; for (const paramType of paramTypes) { - if (this.canResolve(paramType)) { + if (indices.indexOf(i) !== -1) { newArgs.push(this.resolve(paramType)); } else { if (i >= args.length) { diff --git a/src/emitter.ts b/src/emitter.ts index b0ec8e967..404ce562f 100644 --- a/src/emitter.ts +++ b/src/emitter.ts @@ -9,6 +9,10 @@ export class Emitter { switch (node.kind) { + case SyntaxKind.JSExpressionStatement: + out += this.emit(node.expression) + ';\n'; + break; + case SyntaxKind.JSReferenceExpression: out += node.name; break; diff --git a/src/expander.ts b/src/expander.ts deleted file mode 100644 index 215e2a160..000000000 --- a/src/expander.ts +++ /dev/null @@ -1,240 +0,0 @@ - -// FIXME Actually, the syntax expander could make use of algebraic effects to -// easily specify how the next expansion should happen. Just a thought. - -import { - SyntaxKind, - setParents, - kindToString, - BoltSyntax, - BoltSentence, - createBoltRecordPattern, - createBoltExpressionPattern, - createBoltIdentifier, - createBoltReferenceTypeExpression, - createBoltConstantExpression, - createBoltTuplePattern, - createBoltQualName, - createBoltTypePattern, - createBoltBindPattern, - createBoltMatchExpression, - createBoltMatchArm, - createBoltModule, - createBoltSourceFile, - BoltPattern, - BoltSourceElement, - BoltReferenceTypeExpression, - createBoltRecordDeclaration, - createBoltRecordDeclarationField, - isBoltSourceElement, - createBoltExpressionStatement, - isBoltExpression, -} from "./ast" - -import { TextSpan } from "./text" -import { TypeChecker } from "./checker" -import { ParseError } from "./util" -import { Parser } from "./parser" -import { Evaluator, TRUE, FALSE } from "./evaluator" -import { StreamWrapper, setOrigNodeRange, BoltTokenStream, createTokenStream } from "./util" - -interface Transformer { - pattern: BoltPattern; - transform: (node: BoltTokenStream) => BoltSyntax; -} - -function createSimpleBoltReferenceTypeExpression(text: string): BoltReferenceTypeExpression { - const ids = text.split('.').map(name => createBoltIdentifier(name)) - return createBoltReferenceTypeExpression(createBoltQualName(ids.slice(0, -1), ids[ids.length-1]), []) -} - -/// This is actually a hand-parsed version of the following: -/// -/// Bolt.AST.Braced { -/// elements = [ -/// Bolt.AST.Identifier { text = "name" }, -/// Bolt.AST.Braced { -/// elements = [ -/// pattern: Bolt.AST.Pattern, -/// _: RArrow, -/// expression: Bolt.AST.Expr -/// ] -/// } -/// ], -/// } -//const PATTERN_SYNTAX: BoltPattern = -// createBoltRecordPattern( -// createSimpleBoltReferenceTypeExpression('Bolt.AST.Sentence'), -// [ -// createBoltRecordDeclarationField( -// createBoltIdentifier('elements'), -// createBoltTuplePattern([ -// createBoltRecordPattern( -// createSimpleBoltReferenceTypeExpression('Bolt.AST.Identifier'), -// [{ -// name: createBoltIdentifier('text'), -// pattern: createBoltConstantExpression('syntax') -// }] -// ), -// createBoltRecordPattern( -// createSimpleBoltReferenceTypeExpression('Bolt.AST.Braced'), -// [{ -// name: createBoltIdentifier('elements'), -// pattern: createBoltTuplePattern([ -// createBoltTypePattern(createSimpleBoltReferenceTypeExpression('Bolt.AST.Pattern'), createBoltBindPattern(createBoltIdentifier('pattern'))), -// createBoltTypePattern(createSimpleBoltReferenceTypeExpression('Bolt.AST.RArrow'), createBoltBindPattern(createBoltIdentifier('_'))), -// createBoltTypePattern(createSimpleBoltReferenceTypeExpression('Bolt.AST.Expr'), createBoltBindPattern(createBoltIdentifier('expression'))) -// ]) -// }] -// ) -// ]) -// )] -// ) - -export class Expander { - - protected transformers: Transformer[] = [] - - constructor(public parser: Parser, public evaluator: Evaluator, public checker: TypeChecker) { - // this.transformers.push({ - // pattern: PATTERN_SYNTAX, - // transform: this.parser.parseSyntax.bind(this.parser) - // }) - } - - getFullyExpanded(node: BoltSyntax): BoltSyntax { - - if (node.kind === SyntaxKind.BoltSourceFile) { - - const expanded: BoltSourceElement[] = []; - - let didExpand = false; - - for (const element of node.elements) { - - let newElement = this.getFullyExpanded(element); - - // Automatically lift top-level expressions into so that they are valid. - - if (isBoltExpression(newElement)) { - newElement = createBoltExpressionStatement(newElement); - } - - // From this point, newElement really should be a BoltSourceElement - - if (!isBoltSourceElement(newElement)) { - throw new Error(`Expanded element ${kindToString(newElement.kind)} is not valid in a top-level context.`); - } - - if (newElement !== element) { - didExpand = true; - } - - expanded.push(newElement); - } - - if (!didExpand) { - return node; - } - - const newSourceFile = createBoltSourceFile(expanded); - setOrigNodeRange(newSourceFile, node, node); - setParents(newSourceFile); - return newSourceFile; - - } else if (node.kind == SyntaxKind.BoltModule) { - - const expanded: BoltSourceElement[] = []; - - let didExpand = false; - - for (const element of node.elements) { - let newElement = this.getFullyExpanded(element); - if (!isBoltSourceElement(newElement)) { - throw new Error(`Expanded element is invalid in a module context.`); - } - if (newElement !== element) { - didExpand = true; - } - expanded.push(newElement); - } - - if (!didExpand) { - return node; - } - - const newModule = createBoltModule(0, node.name, expanded); - setOrigNodeRange(newModule, node, node); - setParents(newModule); - return newModule; - - } else if (node.kind === SyntaxKind.BoltSentence) { - - let newElement; - - const tokens = createTokenStream(node); - - try { - - newElement = this.parser.parseSourceElement(tokens) - setOrigNodeRange(newElement, node, node); - - } catch (e) { - - // Regular errors should be propagated. - - if (!(e instanceof ParseError)) { - throw e; - } - - // The following applies a user-defined transformer to the token tree. - - while (true) { - let didExpand = false; - const expanded: BoltSyntax[] = []; - const tokens = createTokenStream(node); - for (const transformer of this.transformers) { - if (this.evaluator.eval(createBoltMatchExpression(createBoltConstantExpression(this.evaluator.createValue(node)), [ - createBoltMatchArm( - transformer.pattern, - createBoltConstantExpression(TRUE) - ), - createBoltMatchArm( - createBoltExpressionPattern(createBoltConstantExpression(TRUE)), - createBoltConstantExpression(FALSE) - ) - ]))) { - expanded.push(transformer.transform(tokens)) - didExpand = true; - // break; // FIXME - } - } - if (!didExpand) { - break; - } - } - - // If no transformer matched, then throw the original parse error. - - if (!newElement) { - throw e; - } - - } - - // Perform a full expansion on the transformed element. - - return this.getFullyExpanded(newElement) - - } else { - - //this.checker.check(node); - - return node; - - } - - } - -} - diff --git a/src/frontend.ts b/src/frontend.ts new file mode 100644 index 000000000..72c097ccf --- /dev/null +++ b/src/frontend.ts @@ -0,0 +1,136 @@ + +import * as path from "path" +import * as fs from "fs-extra" +import { now } from "microtime" +import { EventEmitter } from "events" + +import { Program } from "./program" +import { TypeChecker } from "./checker" +import { Evaluator } from "./evaluator" +import { emit } from "./emitter" +import { Syntax } from "./ast" +import { upsearchSync, FastStringMap, getFileStem, getLanguage } from "./util" +import { Package } from "./package" +import { verbose, memoize } from "./util" +import { Container } from "./di" +import ExpandBoltTransform from "./transforms/expand" +import CompileBoltToJSTransform from "./transforms/boltToJS" +import ConstFoldTransform from "./transforms/constFold" +import EliminateModulesTransform from "./transforms/eliminateModules" +import { TransformManager } from "./transforms/index" + +const targetExtensions: MapLike = { + 'JS': '.mjs', + 'Bolt': '.bolt', + 'C': '.c', +}; + +interface TimingInfo { + timestamp: number; + refCount: number; +} + +class Timing extends EventEmitter { + + private runningTasks: FastStringMap = Object.create(null); + + public start(name: string) { + if (this.runningTasks[name] !== undefined) { + this.runningTasks[name].refCount++; + return; + } + this.runningTasks[name] = { timestamp: now(), refCount: 1 }; + this.emit(`start ${name}`); + } + + public end(name: string) { + if (this.runningTasks[name] === undefined) { + throw new Error(`Task '${name}' was never started.`); + } + const info = this.runningTasks[name]; + info.refCount--; + if (info.refCount === 0) { + const usecs = now() - info.timestamp; + verbose(`Task '${name}' completed after ${usecs} microseconds.`); + this.emit(`end ${name}`); + } + } + +} + +export class Frontend { + + public evaluator: Evaluator; + public checker: TypeChecker; + public timing: Timing; + + private container = new Container(); + + constructor() { + this.checker = new TypeChecker(); + this.evaluator = new Evaluator(this.checker); + this.timing = new Timing(); + this.container.bindSelf(this.evaluator); + this.container.bindSelf(this.checker); + } + + @memoize + public getPackage(filepath: string) { + const file = this.getTextFile(filepath) + const projectFile = upsearchSync('Boltfile', path.dirname(file.fullPath)); + if (projectFile === null) { + return null; + } + const projectDir = path.resolve(path.dirname(projectFile)); + return new Package(projectDir); + } + + public compile(program: Program, target: string) { + + switch (target) { + + case "JS": + const transforms = new TransformManager(this.container); + transforms.register(ExpandBoltTransform); + transforms.register(EliminateModulesTransform); + transforms.register(CompileBoltToJSTransform); + transforms.register(ConstFoldTransform); + transforms.apply(program); + break; + + default: + throw new Error(`"${target}" is an invalid compile target.`); + + } + + for (const sourceFile of program.getAllSourceFiles()) { + //const filepath = rootNode.span!.file.fullPath; + //const pkg = this.getPackage(filepath); + //if (pkg !== null) { + // + //} + fs.mkdirp('.bolt-work'); + fs.writeFileSync(this.mapToTargetFile(sourceFile), emit(sourceFile), 'utf8'); + } + + } + + private mapToTargetFile(node: Syntax) { + return path.join('.bolt-work', getFileStem(node.span!.file.fullPath) + getDefaultExtension(getLanguage(node))); + } + + public eval(program: Program) { + for (const sourceFile of program.getAllSourceFiles()) { + this.evaluator.eval(sourceFile) + } + } + +} + +function getDefaultExtension(target: string) { + if (targetExtensions[target] === undefined) { + throw new Error(`Could not derive an appropriate extension for target "${target}".`) + } + return targetExtensions[target]; +} + diff --git a/src/parser.ts b/src/parser.ts index 11bcceb67..c69b79b16 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -24,7 +24,7 @@ import { createBoltParameter, BoltBindPattern, createBoltRecordDeclaration, - createBoltRecordDeclarationField, + createBoltRecordField, createBoltImportDeclaration, BoltDeclarationModifiers, BoltStringLiteral, @@ -37,7 +37,7 @@ import { createBoltVariableDeclaration, BoltReturnStatement, createBoltReturnStatement, - BoltRecordDeclarationField, + BoltRecordMember, BoltModule, createBoltModule, BoltTypeAliasDeclaration, @@ -54,6 +54,10 @@ import { createBoltTraitDeclaration, createBoltImplDeclaration, BoltImplDeclaration, + BoltSourceFile, + BoltFunctionBodyElement, + createBoltSourceFile, + BoltRecordField, } from "./ast" import { parseForeignLanguage } from "./foreign" @@ -71,6 +75,11 @@ import { export type BoltTokenStream = Stream; +export function isModifierKeyword(kind: SyntaxKind) { + return kind === SyntaxKind.BoltPubKeyword + || kind === SyntaxKind.BoltForeignKeyword; +} + const KIND_EXPRESSION_T0 = [ SyntaxKind.BoltStringLiteral, SyntaxKind.BoltIntegerLiteral, @@ -525,36 +534,43 @@ export class Parser { t2 = tokens.peek(); } - if (t2.kind !== SyntaxKind.BoltBraced) { - throw new ParseError(t2, [SyntaxKind.BoltBraced]) + let members = null; + + if (t2.kind !== SyntaxKind.BoltSemi) { + + if (t2.kind !== SyntaxKind.BoltBraced) { + throw new ParseError(t2, [SyntaxKind.BoltBraced]) + } + + members = []; + + tokens.get(); + const innerTokens = createTokenStream(t2); + + while (true) { + const t3 = innerTokens.peek(); + if (t3.kind === SyntaxKind.EndOfFile) { + break; + } + assertToken(t3, SyntaxKind.BoltIdentifier); + innerTokens.get(); + const name = t3 as BoltIdentifier; + const t4 = innerTokens.get(); + assertToken(t4, SyntaxKind.BoltColon); + const type = this.parseTypeExpression(innerTokens); + const field = createBoltRecordField(name as BoltIdentifier, type); + const t5 = innerTokens.get(); + if (t5.kind === SyntaxKind.EndOfFile) { + break; + } + assertToken(t5, SyntaxKind.BoltComma); + setOrigNodeRange(field, name, type); + members.push(field); + } + } - let fields: BoltRecordDeclarationField[] = []; - tokens.get(); - const innerTokens = createTokenStream(t2); - - while (true) { - const t3 = innerTokens.peek(); - if (t3.kind === SyntaxKind.EndOfFile) { - break; - } - assertToken(t3, SyntaxKind.BoltIdentifier); - innerTokens.get(); - const name = t3 as BoltIdentifier; - const t4 = innerTokens.get(); - assertToken(t4, SyntaxKind.BoltColon); - const type = this.parseTypeExpression(innerTokens); - const field = createBoltRecordDeclarationField(name as BoltIdentifier, type); - const t5 = innerTokens.get(); - if (t5.kind === SyntaxKind.EndOfFile) { - break; - } - assertToken(t5, SyntaxKind.BoltComma); - setOrigNodeRange(field, name, type); - fields.push(field); - } - - const node = createBoltRecordDeclaration(modifiers, name, typeParams, fields); + const node = createBoltRecordDeclaration(modifiers, name, typeParams, members); setOrigNodeRange(node, firstToken, t2); return node; } @@ -594,7 +610,7 @@ export class Parser { if (t1.kind !== SyntaxKind.BoltBraced) { throw new ParseError(t1, [SyntaxKind.BoltBraced]) } - const sentences = this.parseSourceElementList(createTokenStream(t1)); + const sentences = this.parseSourceElements(createTokenStream(t1)); const node = createBoltModule(modifiers, name, sentences); setOrigNodeRange(node, firstToken, t1); @@ -816,7 +832,7 @@ export class Parser { } const t3 = tokens.get(); assertToken(t3, SyntaxKind.BoltBraced); - const elements = this.parseSourceElementList(createTokenStream(t3)); + const elements = this.parseSourceElements(createTokenStream(t3)); const result = createBoltTraitDeclaration(modifiers, t1 as BoltIdentifier, typeParams, elements as BoltDeclaration[]); setOrigNodeRange(result, firstToken, t3); return result; @@ -843,7 +859,7 @@ export class Parser { } const t4 = tokens.get(); assertToken(t4, SyntaxKind.BoltBraced); - const elements = this.parseSourceElementList(createTokenStream(t4)); + const elements = this.parseSourceElements(createTokenStream(t4)); const result = createBoltImplDeclaration(modifiers, t1 as BoltIdentifier, typeExpr, typeParams, elements as BoltDeclaration[]); setOrigNodeRange(result, firstToken, t4); return result; @@ -890,25 +906,69 @@ export class Parser { } } + private getFirstTokenAfterModifiers(tokens: BoltTokenStream): BoltToken { + let mustBeDecl = false; + let mustBeFunctionOrVariable = false; + let i = 1; + let t0 = tokens.peek(i); + if (t0.kind === SyntaxKind.BoltPubKeyword) { + mustBeDecl = true; + t0 = tokens.peek(++i); + } + if (t0.kind === SyntaxKind.BoltForeignKeyword) { + mustBeFunctionOrVariable = true; + i++; + t0 = tokens.peek(++i); + } + if (mustBeFunctionOrVariable + && t0.kind !== SyntaxKind.BoltStructKeyword + && t0.kind !== SyntaxKind.BoltFnKeyword) { + throw new ParseError(t0, [SyntaxKind.BoltStructKeyword, SyntaxKind.BoltFnKeyword]); + } + if (mustBeDecl && KIND_DECLARATION_T0.indexOf(t0.kind) === -1) { + throw new ParseError(t0, KIND_DECLARATION_KEYWORD); + } + return t0; + } + public parseSourceElement(tokens: BoltTokenStream): BoltSourceElement { - try { - return this.parseDeclaration(tokens) - } catch (e1) { - if (!(e1 instanceof ParseError)) { - throw e1; - } - try { - return this.parseStatement(tokens); - } catch (e2) { - if (!(e2 instanceof ParseError)) { - throw e2; - } - throw e1; - } + const t0 = this.getFirstTokenAfterModifiers(tokens); + if (KIND_STATEMENT_T0.indexOf(t0.kind) !== -1) { + return this.parseStatement(tokens); + } + return this.parseDeclaration(tokens) + } + + public parseFunctionBodyElement(tokens: BoltTokenStream): BoltFunctionBodyElement { + const t0 = this.getFirstTokenAfterModifiers(tokens); + if (KIND_STATEMENT_T0.indexOf(t0.kind) !== -1) { + return this.parseStatement(tokens); + } else if (t0.kind === SyntaxKind.BoltLetKeyword) { + return this.parseVariableDeclaration(tokens); + } else if (t0.kind === SyntaxKind.BoltFnKeyword) { + return this.parseFunctionDeclaration(tokens); + } else { + throw new ParseError(t0, [...KIND_STATEMENT_T0, SyntaxKind.BoltLetKeyword, SyntaxKind.BoltFnKeyword]); } } - public parseSourceElementList(tokens: BoltTokenStream): BoltSourceElement[] { + public parseFunctionBodyElements(tokens: BoltTokenStream): BoltFunctionBodyElement[] { + const elements: BoltFunctionBodyElement[] = [] + while (true) { + const t0 = tokens.peek(); + if (t0.kind === SyntaxKind.EndOfFile) { + break; + } + if (t0.kind === SyntaxKind.BoltSemi) { + tokens.get(); + continue; + } + elements.push(this.parseFunctionBodyElement(tokens)); + } + return elements + } + + public parseSourceElements(tokens: BoltTokenStream): BoltSourceElement[] { const elements: BoltSourceElement[] = [] while (true) { const t0 = tokens.peek(); @@ -983,5 +1043,155 @@ export class Parser { } + public parseSourceFile(tokens: BoltTokenStream): BoltSourceFile { + const elements = this.parseSourceElements(tokens); + const t1 = tokens.peek(); + assertToken(t1, SyntaxKind.EndOfFile); + return createBoltSourceFile( + elements, + new TextSpan(t1.span!.file, new TextPos(0,1,1), t1.span!.end.clone()) + ); + } + + private canParseExpression(tokens: BoltTokenStream): boolean { + // TODO + return false; + } + + private canParseReturnStatement(tokens: BoltTokenStream): boolean { + const t0 = tokens.get(); + if (t0.kind !== SyntaxKind.BoltReturnKeyword) { + return false; + } + const t1 = tokens.peek(); + if (t1.kind === SyntaxKind.EndOfFile) { + return true; + } + return this.canParseExpression(tokens); + } + + private canParseStatement(tokens: BoltTokenStream): boolean { + const t0 = tokens.peek(); + switch (t0.kind) { + case SyntaxKind.BoltReturnKeyword: + return this.canParseReturnStatement(tokens); + case SyntaxKind.BoltLoopKeyword: + return this.canParseLoopStatement(tokens); + default: + return this.canParseExpression(tokens) + } + } + + private canParseFunctionDeclaration(tokens: BoltTokenStream): boolean { + let t0 = tokens.peek(); + if (t0.kind === SyntaxKind.BoltPubKeyword) { + tokens.get(); + t0 = tokens.peek(); + } + if (t0.kind === SyntaxKind.BoltForeignKeyword) { + tokens.get(); + const t1 = tokens.get(); + if (t1.kind !== SyntaxKind.BoltStringLiteral) { + return false; + } + t0 = tokens.peek(); + } + // TODO + return true; + } + + private canParseRecordDeclaration(tokens: BoltTokenStream): boolean { + // TODO + return true; + } + + private canParseVariableDeclaration(tokens: BoltTokenStream): boolean { + // TODO + return true; + } + + private canParseDeclaration(tokens: BoltTokenStream): boolean { + let i = 0; + let t0 = tokens.peek(i); + while (isModifierKeyword(t0.kind)) { + t0 = tokens.peek(++i); + } + switch (t0.kind) { + case SyntaxKind.BoltFnKeyword: + return this.canParseFunctionDeclaration(tokens); + case SyntaxKind.BoltStructKeyword: + return this.canParseRecordDeclaration(tokens); + default: + return false; + } + } + + private canParseSourceElement(tokens: BoltTokenStream): boolean { + return this.canParseStatement(tokens) + || this.canParseDeclaration(tokens) + } + + private canParseRecordMember(tokens: BoltTokenStream): boolean { + // TODO + return true; + } + + private canParseFunctionBodyElement(tokens: BoltTokenStream): boolean { + return this.canParseFunctionDeclaration(tokens) + || this.canParseStatement(tokens) + || this.canParseVariableDeclaration(tokens); + } + + private canParseRecordMembers(tokens: BoltTokenStream): boolean { + while (true) { + const t0 = tokens.peek(); + if (t0.kind === SyntaxKind.EndOfFile) { + break; + } + if (!this.canParseRecordMember(tokens)) { + return false; + } + } + return true; + } + + private canParseSourceElements(tokens: BoltTokenStream): boolean { + while (true) { + const t0 = tokens.peek(); + if (t0.kind === SyntaxKind.EndOfFile) { + break; + } + if (!this.canParseSourceElement(tokens)) { + return false; + } + } + return true; + } + + private canParseFunctionBodyElements(tokens: BoltTokenStream): boolean { + while (true) { + const t0 = tokens.peek(); + if (t0.kind === SyntaxKind.EndOfFile) { + break; + } + if (!this.canParseFunctionBodyElement(tokens)) { + return false; + } + } + return true; + } + +} + +import { Scanner } from "./scanner" +import { TextFile, TextSpan, TextPos } from "./text" +import * as fs from "fs" + +export function parseSourceFile(filepath: string): BoltSourceFile { + const file = new TextFile(filepath); + const contents = fs.readFileSync(file.origPath, 'utf8'); + const scanner = new Scanner(file, contents) + const parser = new Parser(); + return parser.parseSourceFile(scanner); } diff --git a/src/program.ts b/src/program.ts index f82435eb2..c86598f4c 100644 --- a/src/program.ts +++ b/src/program.ts @@ -1,151 +1,34 @@ -import * as path from "path" -import * as fs from "fs-extra" -import { now } from "microtime" -import { EventEmitter } from "events" +import { BoltSourceFile, JSSourceFile } from "./ast" +import { FastStringMap } from "./util"; -import { Parser } from "./parser" -import { TypeChecker } from "./checker" -import { Evaluator } from "./evaluator" -import { Expander } from "./expander" -import { Scanner } from "./scanner" -import { Compiler } from "./compiler" -import { emit } from "./emitter" -import { TextFile } from "./text" -import { BoltSourceFile, Syntax, JSSourceFile } from "./ast" -import { upsearchSync, FastStringMap, getFileStem, getLanguage } from "./util" -import { Package } from "./package" -import { verbose, memoize } from "./util" - -const targetExtensions: FastStringMap = { - 'JS': '.mjs', - 'Bolt': '.bolt', - 'C': '.c', -}; - -export interface TransformationContext { - -} - -interface TimingInfo { - timestamp: number; - refCount: number; -} - -class Timing extends EventEmitter { - - private runningTasks: FastStringMap = Object.create(null); - - public start(name: string) { - if (this.runningTasks[name] !== undefined) { - this.runningTasks[name].refCount++; - return; - } - this.runningTasks[name] = { timestamp: now(), refCount: 1 }; - this.emit(`start ${name}`); - } - - public end(name: string) { - if (this.runningTasks[name] === undefined) { - throw new Error(`Task '${name}' was never started.`); - } - const info = this.runningTasks[name]; - info.refCount--; - if (info.refCount === 0) { - const usecs = now() - info.timestamp; - verbose(`Task '${name}' completed after ${usecs} microseconds.`); - this.emit(`end ${name}`); - } - } - -} +export type SourceFile + = BoltSourceFile + | JSSourceFile export class Program { - public parser: Parser - public evaluator: Evaluator; - public checker: TypeChecker; - public expander: Expander; - public timing: Timing; + private transformed = new FastStringMap(); - constructor(public files: string[]) { - this.checker = new TypeChecker(); - this.parser = new Parser(); - this.evaluator = new Evaluator(this.checker); - this.expander = new Expander(this.parser, this.evaluator, this.checker); - this.timing = new Timing(); - } - - @memoize - public getTextFile(filename: string): TextFile { - return new TextFile(filename); - } - - @memoize - public getSourceFile(file: TextFile): BoltSourceFile { - this.timing.start('read'); - const contents = fs.readFileSync(file.origPath, 'utf8'); - this.timing.end('read'); - const scanner = new Scanner(file, contents) - this.timing.start('scan'); - const sourceFile = scanner.scan(); - this.timing.end('scan'); - return sourceFile; - } - - @memoize - public getFullyExpandedSourceFile(file: TextFile): BoltSourceFile { - const sourceFile = this.getSourceFile(file); - this.timing.start('expand'); - const expanded = this.expander.getFullyExpanded(sourceFile) as BoltSourceFile; - this.timing.end('expand'); - return expanded; - } - - @memoize - public getPackage(filepath: string) { - const file = this.getTextFile(filepath) - const projectFile = upsearchSync('Boltfile', path.dirname(file.fullPath)); - if (projectFile === null) { - return null; - } - const projectDir = path.resolve(path.dirname(projectFile)); - return new Package(projectDir); - } - - public compile(target: string) { - const compiler = new Compiler(this, this.checker, { target }) - const expanded = this.files.map(filename => this.getFullyExpandedSourceFile(this.getTextFile(filename))); - const compiled = compiler.compile(expanded) as JSSourceFile[]; - for (const rootNode of compiled) { - //const filepath = rootNode.span!.file.fullPath; - //const pkg = this.getPackage(filepath); - //if (pkg !== null) { - // - //} - fs.mkdirp('.bolt-work'); - fs.writeFileSync(this.mapToTargetFile(rootNode), emit(rootNode), 'utf8'); + constructor( + sourceFiles: BoltSourceFile[] + ) { + for (const sourceFile of sourceFiles) { + this.transformed.set(sourceFile.span!.file.fullPath, sourceFile); } } - private mapToTargetFile(node: Syntax) { - return path.join('.bolt-work', getFileStem(node.span!.file.fullPath) + getDefaultExtension(getLanguage(node))); + public getAllSourceFiles() { + return this.transformed.values(); } - public eval() { - for (const filename of this.files) { - const file = this.getTextFile(filename); - const expanded = this.getFullyExpandedSourceFile(file); - this.evaluator.eval(expanded) + public updateSourceFile(oldSourceFile: SourceFile, newSourceFile: SourceFile): void { + if (!this.transformed.has(oldSourceFile.span!.file.fullPath)) { + throw new Error(`Could not update ${oldSourceFile.span!.file.origPath} because it was not found in this program.`); } + this.transformed.delete(oldSourceFile.span!.file.fullPath); + this.transformed.set(newSourceFile.span!.file.fullPath, newSourceFile); } } -function getDefaultExtension(target: string) { - if (targetExtensions[target] === undefined) { - throw new Error(`Could not derive an appropriate extension for target "${target}".`) - } - return targetExtensions[target]; -} - diff --git a/src/transforms/boltToJS.ts b/src/transforms/boltToJS.ts new file mode 100644 index 000000000..4da2b3758 --- /dev/null +++ b/src/transforms/boltToJS.ts @@ -0,0 +1,216 @@ + +import { + TypeChecker, + Scope +} from "../checker" + +import { + Syntax, + SyntaxKind, + kindToString, + BoltSourceFile, + BoltStatement, + BoltExpression, + BoltDeclaration, + BoltBindPattern, + JSExpression, + JSStatement, + JSSourceElement, + createJSExpressionStatement, + createJSSourceFile, + createJSCallExpression, + createJSReferenceExpression, + createJSConstantExpression, + createJSLetDeclaration, + createJSIdentifier, + createJSFunctionDeclaration, + createJSBindPattern, + JSDeclarationModifiers, + JSParameter, + BoltSyntax, + BoltPattern, + createJSImportDeclaration, + JSSyntax, + JSSourceFile, + isBoltSourceFile, + BoltImportDeclaration, + BoltIdentifier, + isBoltDeclaration, + isBoltStatement, + JSBindPattern, + BoltSourceElement, +} from "../ast" + +import { getFullTextOfQualName, hasPublicModifier, setOrigNodeRange, FastStringMap } from "../util" +import { Program, SourceFile } from "../program" +import { Transformer, TransformManager } from "./index" +import { assert } from "../util" +import { inject } from "../di" + +export interface JSCompilerOptions { + +} + +function toJSIdentifier(node: BoltIdentifier) { + const result = createJSIdentifier(node.text); + setOrigNodeRange(result, node, node); + return result; +} + +function pushAll(arr: T[], els: T[]) { + for (const el of els) { + arr.push(el) + } +} + +type Ref = { value: T }; + +class CompileContext { + + private generatedNodes: JSSyntax[] = []; + + constructor(public scope: Scope) { + + } + + public appendNode(node: JSSyntax): void { + this.generatedNodes.push(node); + } + + public getGeneratedNodes(): JSSyntax[] { + return this.generatedNodes; + } + +} + +export class BoltToJSTransform implements Transformer { + + constructor( + private transforms: TransformManager, + @inject private program: Program, + @inject private checker: TypeChecker, + ) { + + } + + public isApplicable(sourceFile: SourceFile): boolean { + return isBoltSourceFile(sourceFile); + } + + public transform(sourceFile: BoltSourceFile): JSSourceFile { + const ctx = new CompileContext(this.checker.getScope(sourceFile)) + for (const element of sourceFile.elements) { + this.compileSourceElement(element, ctx); + } + return createJSSourceFile(ctx.getGeneratedNodes() as JSSourceElement[], sourceFile.span); + } + + private compileExpression(node: Syntax, ctx: CompileContext): JSExpression { + + switch (node.kind) { + + case SyntaxKind.BoltCallExpression: + const compiledOperator = this.compileExpression(node.operator, ctx); + const compiledArgs = node.operands.map(arg => this.compileExpression(arg, ctx)) + return createJSCallExpression( + compiledOperator, + compiledArgs, + node.span, + ); + + case SyntaxKind.BoltReferenceExpression: + return createJSReferenceExpression( + getFullTextOfQualName(node.name), + node.span, + ); + + case SyntaxKind.BoltConstantExpression: + return createJSConstantExpression( + node.value, + node.span, + ); + + default: + throw new Error(`Could not compile expression node ${kindToString(node.kind)}`) + } + + } + + private convertPattern(node: BoltPattern): JSBindPattern { + if (node.kind !== SyntaxKind.BoltBindPattern) { + throw new Error(`The provided node should have been eliminated by a previous pass.`); + } + const jsIdent = toJSIdentifier((node as BoltBindPattern).name); + const jsBindPatt = createJSBindPattern(jsIdent); + setOrigNodeRange(jsBindPatt, node, node); + return jsBindPatt; + } + + protected compileSourceElement(node: BoltSourceElement, ctx: CompileContext) { + + switch (node.kind) { + + case SyntaxKind.BoltRecordDeclaration: + case SyntaxKind.BoltTypeAliasDeclaration: + break; + + case SyntaxKind.BoltExpressionStatement: + const jsExpr = this.compileExpression(node.expression, ctx) + const jsExprStmt = createJSExpressionStatement(jsExpr) + setOrigNodeRange(jsExprStmt, node, node); + ctx.appendNode(jsExprStmt); + break; + + case SyntaxKind.BoltImportDeclaration: + // TODO + break; + + case SyntaxKind.BoltVariableDeclaration: + const jsValue = node.value !== null ? this.compileExpression(node.value, ctx) : null; + const jsValueBindPatt = this.convertPattern(node.bindings); + const jsValueDecl = createJSLetDeclaration( + jsValueBindPatt, + jsValue, + ); + ctx.appendNode(jsValueDecl); + break; + + case SyntaxKind.BoltFunctionDeclaration: + if (node.body === null) { + break; + } + if (node.target === "JS") { + const params: JSParameter[] = []; + let body: JSStatement[] = []; + for (const param of node.params) { + assert(param.defaultValue === null); + const jsPatt = this.convertPattern(param.bindings) + params.push(jsPatt); + } + let result = createJSFunctionDeclaration( + 0, + createJSIdentifier(node.name.text, node.name.span), + params, + body, + node.span, + ); + if (hasPublicModifier(node)) { + result.modifiers |= JSDeclarationModifiers.IsExported;; + } + ctx.appendNode(result) + } else { + // TODO + throw new Error(`Compiling native functions is not yet implemented.`); + } + break; + + default: + throw new Error(`Could not compile node ${kindToString(node.kind)}`); + + } + + } + +} + +export default BoltToJSTransform; diff --git a/src/transforms/constFold.ts b/src/transforms/constFold.ts new file mode 100644 index 000000000..1cc9fdaf3 --- /dev/null +++ b/src/transforms/constFold.ts @@ -0,0 +1,22 @@ + +import { SourceFile } from "../program" +import { TransformManager } from "../transformers"; + +export class ConstFoldTransform { + + constructor(public transformers: TransformManager) { + + } + + public isApplicable(node: SourceFile): boolean { + return true; + } + + public transform(node: SourceFile): SourceFile { + return node; + } + +} + +export default ConstFoldTransform; + diff --git a/src/transforms/eliminateMatchExpressions.ts b/src/transforms/eliminateMatchExpressions.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/transforms/eliminateModules.ts b/src/transforms/eliminateModules.ts new file mode 100644 index 000000000..d994be649 --- /dev/null +++ b/src/transforms/eliminateModules.ts @@ -0,0 +1,55 @@ +import {TransformManager} from "."; +import {SourceFile} from "../program"; +import {isBoltSourceFile, createBoltSourceFile, BoltSourceElement, SyntaxKind, BoltModule, isBoltModule} from "../ast"; +import {setOrigNodeRange} from "../util"; + +export class EliminateModulesTransform { + + constructor(private transformers: TransformManager) { + + } + + public isApplicable(sourceFile: SourceFile) { + return isBoltSourceFile(sourceFile); + } + + public transform(sourceFile: SourceFile): SourceFile { + + let needsUpdate = false; + const elements: BoltSourceElement[] = []; + + for (const element of sourceFile.elements) { + if (element.kind === SyntaxKind.BoltModule) { + this.extractModuleElements(element, elements); + needsUpdate = true; + } else { + elements.push(element); + } + } + + if (!needsUpdate) { + return sourceFile; + } + + const newSourceFile = createBoltSourceFile(elements); + setOrigNodeRange(newSourceFile, sourceFile, sourceFile); + return newSourceFile; + } + + public extractModuleElements(node: BoltModule, out: BoltSourceElement[]) { + for (const element of node.elements) { + switch (element.kind) { + case SyntaxKind.BoltModule: + this.extractModuleElements(node, out); + break; + case SyntaxKind.BoltRecordDeclaration: + // TODO + break; + } + } + } + +} + +export default EliminateModulesTransform; + diff --git a/src/transforms/expand.ts b/src/transforms/expand.ts new file mode 100644 index 000000000..30cdcbb44 --- /dev/null +++ b/src/transforms/expand.ts @@ -0,0 +1,215 @@ + +// FIXME Actually, the syntax expander could make use of algebraic effects to +// easily specify how the next expansion should happen. Just a thought. + +import { + SyntaxKind, + BoltSyntax, + BoltPattern, + isBoltSourceFile, + BoltMacroCall, +} from "../ast" + +import { TextSpan } from "../text" +import { TypeChecker, Scope } from "../checker" +import { ParseError } from "../util" +import { BoltTokenStream, Parser, isModifierKeyword } from "../parser" +import { Evaluator, TRUE, FALSE } from "../evaluator" +import { setOrigNodeRange, createTokenStream } from "../util" +import { Transformer, TransformManager } from "./index" +import { inject } from "../di" +import {SourceFile} from "../program" + +interface SyntaxTransformer { + pattern: BoltPattern; + transform: (node: BoltTokenStream) => BoltSyntax; +} + +export class ExpandBoltTransform implements Transformer { + + private parser = new Parser(); + private syntaxTransformers: SyntaxTransformer[] = [] + + private toExpand: BoltMacroCall[] = []; + + constructor( + private transforms: TransformManager, + @inject private evaluator: Evaluator, + @inject private checker: TypeChecker + ) { + + } + + //private getRequiredMacros(node: BoltSentence): boolean { + // const scope = this.checker.getScope(node); + // const tokens = createTokenStream(node); + // if (node.parentNode === null || node.parentNode.kind === SyntaxKind.BoltModule) { + // return this.canParseSourceElements(tokens, scope) + // } else if (node.parentNode.kind === SyntaxKind.BoltFunctionDeclaration) { + // return this.canParseFunctionBodyElements(tokens, scope); + // } else if (node.parentNode.kind === SyntaxKind.BoltRecordDeclaration) { + // return this.canParseRecordMembers(tokens, scope); + // } else if (isBoltExpression(node.parentNode)) { + // return this.canParseExpression(node, scope); + // } else { + // throw new Error(`Could not auto-detect the context in which the node is declared.`); + // } + //} + + public isApplicable(node: SourceFile): boolean { + return isBoltSourceFile(node) + } + + public transform(node: BoltSyntax) { + return this.expand(node); + } + + private expand(node: BoltSyntax) { + + for (const identNode of node.findAllChildrenOfKind(SyntaxKind.BoltIdentifier)) { + if (identNode.text.endsWith('1')) { + this.toExpand.push(node.parentNode!); + } + } + + // FIXME + return node; + + } + + //private getFullyExpanded(node: BoltSyntax): BoltSyntax { + + // if (node.kind === SyntaxKind.BoltSourceFile) { + + // const expanded: BoltSourceElement[] = []; + + // let didExpand = false; + + // for (const element of node.elements) { + + // let newElement = this.getFullyExpanded(element); + + // // Automatically lift top-level expressions into so that they are valid. + + // if (isBoltExpression(newElement)) { + // newElement = createBoltExpressionStatement(newElement); + // } + + // // From this point, newElement really should be a BoltSourceElement + + // if (!isBoltSourceElement(newElement)) { + // throw new Error(`Expanded element ${kindToString(newElement.kind)} is not valid in a top-level context.`); + // } + + // if (newElement !== element) { + // didExpand = true; + // } + + // expanded.push(newElement); + // } + + // if (!didExpand) { + // return node; + // } + + // const newSourceFile = createBoltSourceFile(expanded); + // setOrigNodeRange(newSourceFile, node, node); + // setParents(newSourceFile); + // return newSourceFile; + + // } else if (node.kind == SyntaxKind.BoltModule) { + + // const expanded: BoltSourceElement[] = []; + + // let didExpand = false; + + // for (const element of node.elements) { + // let newElement = this.getFullyExpanded(element); + // if (!isBoltSourceElement(newElement)) { + // throw new Error(`Expanded element is invalid in a module context.`); + // } + // if (newElement !== element) { + // didExpand = true; + // } + // expanded.push(newElement); + // } + + // if (!didExpand) { + // return node; + // } + + // const newModule = createBoltModule(0, node.name, expanded); + // setOrigNodeRange(newModule, node, node); + // setParents(newModule); + // return newModule; + + // } else if (node.kind === SyntaxKind.BoltSentence) { + + // let newElement; + + // const tokens = createTokenStream(node); + + // try { + + // newElement = this.parser.parseSourceElement(tokens) + // setOrigNodeRange(newElement, node, node); + + // } catch (e) { + + // // Regular errors should be propagated. + + // if (!(e instanceof ParseError)) { + // throw e; + // } + + // // The following applies a user-defined transformer to the token tree. + + // while (true) { + // let didExpand = false; + // const expanded: BoltSyntax[] = []; + // const tokens = createTokenStream(node); + // for (const transformer of this.syntaxTransformers) { + // if (this.evaluator.eval(createBoltMatchExpression(createBoltConstantExpression(this.evaluator.createValue(node)), [ + // createBoltMatchArm( + // transformer.pattern, + // createBoltConstantExpression(TRUE) + // ), + // createBoltMatchArm( + // createBoltExpressionPattern(createBoltConstantExpression(TRUE)), + // createBoltConstantExpression(FALSE) + // ) + // ]))) { + // expanded.push(transformer.transform(tokens)) + // didExpand = true; + // // break; // FIXME + // } + // } + // if (!didExpand) { + // break; + // } + // } + + // // If no transformer matched, then throw the original parse error. + + // if (!newElement) { + // throw e; + // } + + // } + + // // Perform a full expansion on the transformed element. + + // return this.getFullyExpanded(newElement) + + // } else { + + // return node; + + // } + + //} + +} + +export default ExpandBoltTransform; + diff --git a/src/transforms/index.ts b/src/transforms/index.ts new file mode 100644 index 000000000..3a300f9a5 --- /dev/null +++ b/src/transforms/index.ts @@ -0,0 +1,47 @@ + +import { SourceFile, Program } from "./program" +import { Container } from "./di" +import {Evaluator} from "./evaluator"; +import {TypeChecker} from "./checker"; + +export interface Transformer { + isApplicable(node: SourceFile): boolean; + transform(node: SourceFile): SourceFile; +} + +export interface RegisterTransformerOptions { + +} + +function createInstance(factory: Factory, ...args: any[]): T { + return new factory(...args); +} + +export class TransformManager { + + private transformers: Transformer[] = []; + + constructor(private container: Container) { + + } + + public register(transformerFactory: Newable, options: RegisterTransformerOptions = {}) { + const transformer = this.container.createInstance(transformerFactory, this); + this.transformers.push(transformer); + } + + public apply(program: Program) { + for (const transformer of this.transformers) { + for (const sourceFile of program.getAllSourceFiles()) { + if (transformer.isApplicable(sourceFile)) { + const newSourceFile = transformer.transform(sourceFile); + if (newSourceFile !== sourceFile) { + program.updateSourceFile(sourceFile, newSourceFile); + } + } + } + } + } + +} + diff --git a/src/treegen/ast-template.js b/src/treegen/ast-template.js index 53e08f805..c10e38d73 100644 --- a/src/treegen/ast-template.js +++ b/src/treegen/ast-template.js @@ -2,9 +2,54 @@ const exported = {}; const nodeProto = { - preorder() { + *getChildNodes() { + for (const key of Object.keys(this)) { + if (key === 'span' || key === 'parentNode') { + continue + } + const value = this[key]; + if (Array.isArray(value)) { + for (const element of value) { + if (isSyntax(element)) { + yield element; + } + } + } else if (isSyntax(value)) { + if (isSyntax(value)) { + yield value; + } + } + } + }, + + *preorder() { + const stack = [this]; + while (stack.length > 0) { + const node = stack.pop(); + yield node + for (const childNode of node.getChildNodes()) { + stack.push(childNode); + } + } + }, + + mayContainKind(kind) { + // TODO + return true; + }, + + *findAllChildrenOfKind(kind) { + for (const node of this.preorder()) { + if (!node.mayContainKind(kind)) { + break; + } + if (node.kind === kind) { + yield node + } + } } + } function isSyntax(value) { @@ -13,26 +58,6 @@ function isSyntax(value) { && value.__NODE_TYPE !== undefined; } -function* getChildNodes(node) { - for (const key of Object.keys(node)) { - if (key === 'span' || key === 'parentNode') { - continue - } - const value = node[key]; - if (Array.isArray(value)) { - for (const element of value) { - if (isSyntax(element)) { - yield element; - } - } - } else if (isSyntax(value)) { - if (isSyntax(value)) { - yield value; - } - } - } -} - function createNode(nodeType) { const obj = Object.create(nodeProto); Object.defineProperty(obj, '__NODE_TYPE', { diff --git a/src/treegen/index.ts b/src/treegen/index.ts index 799547805..da1cf7fb1 100644 --- a/src/treegen/index.ts +++ b/src/treegen/index.ts @@ -110,17 +110,22 @@ export function setParents(node: Syntax): void; export type SyntaxRange = [Syntax, Syntax]; -interface SyntaxBase { - kind: SyntaxKind; - parentNode: Syntax | null; +interface SyntaxBase { + kind: K; + parentNode: ParentTypesOf | null; span: TextSpan | null; + getChildNodes(): IterableIterator>, + findAllChildrenOfKind(kind: K1): IterableIterator>; } + +export type ResolveSyntaxKind = Extract; + `); for (const decl of decls) { if (decl.type === 'NodeDeclaration') { if (isLeafNode(decl.name)) { - dtsFile.write(`export interface ${decl.name} extends SyntaxBase {\n`) + dtsFile.write(`export interface ${decl.name} extends SyntaxBase {\n`) dtsFile.indent() dtsFile.write(`kind: SyntaxKind.${decl.name};\n`); for (const field of getAllFields(decl)) { @@ -150,6 +155,19 @@ interface SyntaxBase { } } + //dtsFile.write('export type ResolveSyntaxKind\n'); + //{ + //let i = 0; + //for (const decl of leafNodes) { + //dtsFile.write(i === 0 ? ' =' : ' |'); + //dtsFile.write(` K extends SyntaxKind.${decl.name} ? ${decl.name}`); + //dtsFile.write(' :'); + //dtsFile.write('\n'); + //i++; + //} + //dtsFile.write(' never\n\n'); + //} + for (const langName of langNames) { dtsFile.write(`export type ${langName}Syntax\n`); let first = true; diff --git a/src/util.ts b/src/util.ts index edb4c4139..16201faad 100644 --- a/src/util.ts +++ b/src/util.ts @@ -8,6 +8,12 @@ import { TextFile, TextSpan, TextPos } from "./text" import { Scanner } from "./scanner" import { kindToString, Syntax, BoltQualName, BoltDeclaration, BoltDeclarationModifiers, createEndOfFile, SyntaxKind, isBoltPunctuated } from "./ast" +export function assert(test: boolean): void { + if (!test) { + throw new Error(`Invariant violation: an internal sanity check failed.`); + } +} + export function createTokenStream(node: Syntax) { if (isBoltPunctuated(node)) { const origPos = node.span!.start; @@ -52,6 +58,12 @@ export class FastStringMap { return this.mapping[key]; } + public *values(): IterableIterator { + for (const key of Object.keys(this.mapping)) { + yield this.mapping[key]; + } + } + public set(key: K, value: V): void { if (key in this.mapping) { throw new Error(`A value for key '${key}' already exists.`);