diff --git a/spec/ast.txt b/spec/ast.txt index 51df29f90..9a9576b04 100644 --- a/spec/ast.txt +++ b/spec/ast.txt @@ -2,6 +2,8 @@ @language Bolt; @language JS; +node EndOfFile > BoltToken, JSToken; + // Bolt language AST definitions type BoltValue = Integer | bool | String; @@ -34,8 +36,6 @@ node BoltAssignment > BoltToken { operator: Option, } -node BoltEOS > BoltToken; - node BoltComma > BoltToken; node BoltSemi > BoltToken; node BoltColon > BoltToken; @@ -62,7 +62,8 @@ node BoltModKeyword > BoltToken, BoltKeyword; node BoltMutKeyword > BoltToken, BoltKeyword; node BoltEnumKeyword > BoltToken, BoltKeyword; node BoltStructKeyword > BoltToken, BoltKeyword; -node BoltNewTypeKeyword > BoltToken, BoltKeyword; +node BoltTypeKeyword > BoltToken, BoltKeyword; +node BoltTraitKeyworkd > BoltToken, BoltKeyword; node BoltPunctuated > BoltToken { text: String, @@ -85,11 +86,17 @@ node BoltSentence > BoltSourceElement { tokens: Vec, } -node BoltTypeNode; +node BoltTypeExpression; -node BoltReferenceTypeNode > BoltTypeNode { +node BoltReferenceTypeExpression > BoltTypeExpression { name: BoltQualName, - arguments: Option>, + arguments: Option>, +} + +node BoltTypeParameter { + index: usize, + name: BoltIdentifier, + defaultType: Option, } node BoltPattern; @@ -99,7 +106,7 @@ node BoltBindPattern > BoltPattern { } node BoltTypePattern > BoltPattern { - type: BoltTypeNode, + type: BoltTypeExpression, nestedPattern: BoltPattern, } @@ -122,7 +129,7 @@ node BoltRecordPatternField { } node BoltRecordPattern > BoltPattern { - name: BoltTypeNode, + name: BoltTypeExpression, fields: Vec, } @@ -185,12 +192,14 @@ node BoltExpressionStatement > BoltStatement { node BoltParameter { index: usize, bindings: BoltPattern, - type: Option, + type: Option, defaultValue: Option, } node BoltDeclaration > BoltSourceElement; +node BoltTypeDeclaration > BoltDeclaration; + enum BoltDeclarationModifiers { Mutable = 0x1, Public = 0x2, @@ -198,10 +207,6 @@ enum BoltDeclarationModifiers { IsForeign = 0x8, } -node BoltNewTypeDeclaration > BoltDeclaration { - modifiers: BoltDeclarationModifiers, - name: BoltIdentifier, -} node BoltModule > BoltDeclaration { modifiers: BoltDeclarationModifiers, @@ -214,14 +219,14 @@ node BoltFunctionDeclaration > BoltDeclaration { target: String, name: BoltSymbol, params: Vec, - returnType: Option, + returnType: Option, body: Vec, } node BoltVariableDeclaration > BoltDeclaration { modifiers: BoltDeclarationModifiers, bindings: BoltPattern, - type: Option, + type: Option, value: Option, } @@ -238,14 +243,22 @@ node BoltImportDeclaration > BoltDeclaration { node BoltRecordDeclarationField { name: BoltIdentifier, - type: BoltTypeNode, + type: BoltTypeExpression, +} + +node BoltTypeAliasDeclaration > BoltTypeDeclaration { + modifiers: BoltDeclarationModifiers, + name: BoltIdentifier, + typeParams: Option>, + typeExpr: BoltTypeExpression, } node BoltSourceElement; -node BoltRecordDeclaration > BoltDeclaration { +node BoltRecordDeclaration > BoltTypeDeclaration { modifiers: BoltDeclarationModifiers, name: BoltQualName, + typeParms: Option>, fields: Vec, } @@ -263,6 +276,10 @@ node JSIdentifier > JSToken { text: String, } +node JSReturnKeyword > JSToken; +node JSTryKeyword > JSToken; +node JSCatchKeyword > JSToken; + node JSPattern; node JSBindPattern > JSPattern { @@ -320,7 +337,9 @@ node JSReferenceExpression > JSExpression { name: String, } -node JSStatement; +node JSSourceElement; + +node JSStatement > JSSourceElement; node JSExpressionStatement > JSStatement { expression: JSExpression, @@ -338,7 +357,7 @@ node JSParameter { defaultValue: Option, } -node JSDeclaration; +node JSDeclaration > JSSourceElement; enum JSDeclarationModifiers { IsExported = 0x1, @@ -366,5 +385,3 @@ node JSSourceFile { elements: Vec, } -node JSSourceElement > JSDeclaration, JSStatement; - diff --git a/src/ast.d.ts b/src/ast.d.ts index 4ccdd445e..e56fe28e0 100644 --- a/src/ast.d.ts +++ b/src/ast.d.ts @@ -1,12 +1,12 @@ export const enum SyntaxKind { - FunctionBody = 3, - BoltStringLiteral = 5, - BoltIntegerLiteral = 6, - BoltIdentifier = 8, - BoltOperator = 9, - BoltAssignment = 10, - BoltEOS = 11, + EndOfFile = 2, + FunctionBody = 4, + BoltStringLiteral = 6, + BoltIntegerLiteral = 7, + BoltIdentifier = 9, + BoltOperator = 10, + BoltAssignment = 11, BoltComma = 12, BoltSemi = 13, BoltColon = 14, @@ -30,62 +30,66 @@ export const enum SyntaxKind { BoltMutKeyword = 33, BoltEnumKeyword = 34, BoltStructKeyword = 35, - BoltNewTypeKeyword = 36, - BoltParenthesized = 38, - BoltBraced = 39, - BoltBracketed = 40, - BoltSourceFile = 41, - BoltQualName = 42, - BoltSentence = 43, - BoltReferenceTypeNode = 45, - BoltBindPattern = 47, - BoltTypePattern = 48, - BoltExpressionPattern = 49, - BoltTuplePatternElement = 50, - BoltTuplePattern = 51, - BoltRecordPatternField = 52, - BoltRecordPattern = 53, - BoltReferenceExpression = 55, - BoltCallExpression = 56, - BoltYieldExpression = 57, - BoltMatchArm = 58, - BoltMatchExpression = 59, - BoltCase = 60, - BoltCaseExpression = 61, - BoltBlockExpression = 62, - BoltConstantExpression = 63, - BoltReturnStatement = 65, - BoltResumeStatement = 66, - BoltExpressionStatement = 67, - BoltParameter = 68, - BoltNewTypeDeclaration = 71, - BoltModule = 72, - BoltFunctionDeclaration = 73, - BoltVariableDeclaration = 74, - BoltPlainImportSymbol = 76, - BoltImportDeclaration = 77, - BoltRecordDeclarationField = 78, - BoltRecordDeclaration = 80, - JSOperator = 83, - JSIdentifier = 84, - JSBindPattern = 86, - JSConstantExpression = 88, - JSMemberExpression = 90, - JSCallExpression = 91, - JSBinaryExpression = 92, - JSUnaryExpression = 93, - JSNewExpression = 94, - JSSequenceExpression = 95, - JSConditionalExpression = 96, - JSReferenceExpression = 97, - JSExpressionStatement = 99, - JSConditionalStatement = 100, - JSParameter = 101, - JSFunctionDeclaration = 104, - JSArrowFunctionDeclaration = 105, - JSLetDeclaration = 106, - JSSourceFile = 107, - JSSourceElement = 108, + BoltTypeKeyword = 36, + BoltTraitKeyworkd = 37, + BoltParenthesized = 39, + BoltBraced = 40, + BoltBracketed = 41, + BoltSourceFile = 42, + BoltQualName = 43, + BoltSentence = 44, + BoltReferenceTypeExpression = 46, + BoltTypeParameter = 47, + BoltBindPattern = 49, + BoltTypePattern = 50, + BoltExpressionPattern = 51, + BoltTuplePatternElement = 52, + BoltTuplePattern = 53, + BoltRecordPatternField = 54, + BoltRecordPattern = 55, + BoltReferenceExpression = 57, + BoltCallExpression = 58, + BoltYieldExpression = 59, + BoltMatchArm = 60, + BoltMatchExpression = 61, + BoltCase = 62, + BoltCaseExpression = 63, + BoltBlockExpression = 64, + BoltConstantExpression = 65, + BoltReturnStatement = 67, + BoltResumeStatement = 68, + BoltExpressionStatement = 69, + BoltParameter = 70, + BoltModule = 74, + BoltFunctionDeclaration = 75, + BoltVariableDeclaration = 76, + BoltPlainImportSymbol = 78, + BoltImportDeclaration = 79, + BoltRecordDeclarationField = 80, + BoltTypeAliasDeclaration = 81, + BoltRecordDeclaration = 83, + JSOperator = 86, + JSIdentifier = 87, + JSReturnKeyword = 88, + JSTryKeyword = 89, + JSCatchKeyword = 90, + JSBindPattern = 92, + JSConstantExpression = 94, + JSMemberExpression = 96, + JSCallExpression = 97, + JSBinaryExpression = 98, + JSUnaryExpression = 99, + JSNewExpression = 100, + JSSequenceExpression = 101, + JSConditionalExpression = 102, + JSReferenceExpression = 103, + JSExpressionStatement = 106, + JSConditionalStatement = 107, + JSParameter = 108, + JSFunctionDeclaration = 111, + JSArrowFunctionDeclaration = 112, + JSLetDeclaration = 113, + JSSourceFile = 114, } @@ -101,17 +105,21 @@ interface SyntaxBase { parentNode: Syntax | null; span: TextSpan | null; } +export interface EndOfFile extends SyntaxBase { + kind: SyntaxKind.EndOfFile; +} + export interface FunctionBody extends SyntaxBase { kind: SyntaxKind.FunctionBody; } export type BoltToken - = BoltStringLiteral + = EndOfFile + | BoltStringLiteral | BoltIntegerLiteral | BoltIdentifier | BoltOperator | BoltAssignment - | BoltEOS | BoltComma | BoltSemi | BoltColon @@ -135,7 +143,8 @@ export type BoltToken | BoltMutKeyword | BoltEnumKeyword | BoltStructKeyword - | BoltNewTypeKeyword + | BoltTypeKeyword + | BoltTraitKeyworkd | BoltParenthesized | BoltBraced | BoltBracketed @@ -171,10 +180,6 @@ export interface BoltAssignment extends SyntaxBase { operator: string | null; } -export interface BoltEOS extends SyntaxBase { - kind: SyntaxKind.BoltEOS; -} - export interface BoltComma extends SyntaxBase { kind: SyntaxKind.BoltComma; } @@ -229,7 +234,8 @@ export type BoltKeyword | BoltMutKeyword | BoltEnumKeyword | BoltStructKeyword - | BoltNewTypeKeyword + | BoltTypeKeyword + | BoltTraitKeyworkd export interface BoltFnKeyword extends SyntaxBase { @@ -284,8 +290,12 @@ export interface BoltStructKeyword extends SyntaxBase { kind: SyntaxKind.BoltStructKeyword; } -export interface BoltNewTypeKeyword extends SyntaxBase { - kind: SyntaxKind.BoltNewTypeKeyword; +export interface BoltTypeKeyword extends SyntaxBase { + kind: SyntaxKind.BoltTypeKeyword; +} + +export interface BoltTraitKeyworkd extends SyntaxBase { + kind: SyntaxKind.BoltTraitKeyworkd; } export type BoltPunctuated @@ -325,14 +335,21 @@ export interface BoltSentence extends SyntaxBase { tokens: BoltToken[]; } -export type BoltTypeNode - = BoltReferenceTypeNode +export type BoltTypeExpression + = BoltReferenceTypeExpression -export interface BoltReferenceTypeNode extends SyntaxBase { - kind: SyntaxKind.BoltReferenceTypeNode; +export interface BoltReferenceTypeExpression extends SyntaxBase { + kind: SyntaxKind.BoltReferenceTypeExpression; name: BoltQualName; - arguments: BoltTypeNode[] | null; + arguments: BoltTypeExpression[] | null; +} + +export interface BoltTypeParameter extends SyntaxBase { + kind: SyntaxKind.BoltTypeParameter; + index: number; + name: BoltIdentifier; + defaultType: BoltTypeExpression | null; } export type BoltPattern @@ -350,7 +367,7 @@ export interface BoltBindPattern extends SyntaxBase { export interface BoltTypePattern extends SyntaxBase { kind: SyntaxKind.BoltTypePattern; - type: BoltTypeNode; + type: BoltTypeExpression; nestedPattern: BoltPattern; } @@ -378,7 +395,7 @@ export interface BoltRecordPatternField extends SyntaxBase { export interface BoltRecordPattern extends SyntaxBase { kind: SyntaxKind.BoltRecordPattern; - name: BoltTypeNode; + name: BoltTypeExpression; fields: BoltRecordPatternField[]; } @@ -466,28 +483,27 @@ export interface BoltParameter extends SyntaxBase { kind: SyntaxKind.BoltParameter; index: number; bindings: BoltPattern; - type: BoltTypeNode | null; + type: BoltTypeExpression | null; defaultValue: BoltExpression | null; } export type BoltDeclaration - = BoltNewTypeDeclaration + = BoltTypeAliasDeclaration + | BoltRecordDeclaration | BoltModule | BoltFunctionDeclaration | BoltVariableDeclaration | BoltImportDeclaration + + +export type BoltTypeDeclaration + = BoltTypeAliasDeclaration | BoltRecordDeclaration export const enum BoltDeclarationModifiers { Mutable = 1,Public = 2,IsType = 4,IsForeign = 8,} -export interface BoltNewTypeDeclaration extends SyntaxBase { - kind: SyntaxKind.BoltNewTypeDeclaration; - modifiers: BoltDeclarationModifiers; - name: BoltIdentifier; -} - export interface BoltModule extends SyntaxBase { kind: SyntaxKind.BoltModule; modifiers: BoltDeclarationModifiers; @@ -501,7 +517,7 @@ export interface BoltFunctionDeclaration extends SyntaxBase { target: string; name: BoltSymbol; params: BoltParameter[]; - returnType: BoltTypeNode | null; + returnType: BoltTypeExpression | null; body: BoltStatement[]; } @@ -509,7 +525,7 @@ export interface BoltVariableDeclaration extends SyntaxBase { kind: SyntaxKind.BoltVariableDeclaration; modifiers: BoltDeclarationModifiers; bindings: BoltPattern; - type: BoltTypeNode | null; + type: BoltTypeExpression | null; value: BoltExpression | null; } @@ -531,7 +547,15 @@ export interface BoltImportDeclaration extends SyntaxBase { export interface BoltRecordDeclarationField extends SyntaxBase { kind: SyntaxKind.BoltRecordDeclarationField; name: BoltIdentifier; - type: BoltTypeNode; + type: BoltTypeExpression; +} + +export interface BoltTypeAliasDeclaration extends SyntaxBase { + kind: SyntaxKind.BoltTypeAliasDeclaration; + modifiers: BoltDeclarationModifiers; + name: BoltIdentifier; + typeParams: BoltTypeParameter[] | null; + typeExpr: BoltTypeExpression; } export type BoltSourceElement @@ -539,24 +563,29 @@ export type BoltSourceElement | BoltReturnStatement | BoltResumeStatement | BoltExpressionStatement - | BoltNewTypeDeclaration + | BoltTypeAliasDeclaration + | BoltRecordDeclaration | BoltModule | BoltFunctionDeclaration | BoltVariableDeclaration | BoltImportDeclaration - | BoltRecordDeclaration export interface BoltRecordDeclaration extends SyntaxBase { kind: SyntaxKind.BoltRecordDeclaration; modifiers: BoltDeclarationModifiers; name: BoltQualName; + typeParms: BoltTypeParameter[] | null; fields: BoltRecordDeclarationField[]; } export type JSToken - = JSOperator + = EndOfFile + | JSOperator | JSIdentifier + | JSReturnKeyword + | JSTryKeyword + | JSCatchKeyword export interface JSOperator extends SyntaxBase { @@ -569,6 +598,18 @@ export interface JSIdentifier extends SyntaxBase { text: string; } +export interface JSReturnKeyword extends SyntaxBase { + kind: SyntaxKind.JSReturnKeyword; +} + +export interface JSTryKeyword extends SyntaxBase { + kind: SyntaxKind.JSTryKeyword; +} + +export interface JSCatchKeyword extends SyntaxBase { + kind: SyntaxKind.JSCatchKeyword; +} + export type JSPattern = JSBindPattern @@ -647,10 +688,17 @@ export interface JSReferenceExpression extends SyntaxBase { name: string; } +export type JSSourceElement + = JSExpressionStatement + | JSConditionalStatement + | JSFunctionDeclaration + | JSArrowFunctionDeclaration + | JSLetDeclaration + + export type JSStatement = JSExpressionStatement | JSConditionalStatement - | JSSourceElement export interface JSExpressionStatement extends SyntaxBase { @@ -676,7 +724,6 @@ export type JSDeclaration = JSFunctionDeclaration | JSArrowFunctionDeclaration | JSLetDeclaration - | JSSourceElement export const enum JSDeclarationModifiers { @@ -708,17 +755,12 @@ export interface JSSourceFile extends SyntaxBase { elements: JSSourceElement[]; } -export interface JSSourceElement extends SyntaxBase { - kind: SyntaxKind.JSSourceElement; -} - export type BoltSyntax = BoltStringLiteral | BoltIntegerLiteral | BoltIdentifier | BoltOperator | BoltAssignment - | BoltEOS | BoltComma | BoltSemi | BoltColon @@ -742,14 +784,16 @@ export type BoltSyntax | BoltMutKeyword | BoltEnumKeyword | BoltStructKeyword - | BoltNewTypeKeyword + | BoltTypeKeyword + | BoltTraitKeyworkd | BoltParenthesized | BoltBraced | BoltBracketed | BoltSourceFile | BoltQualName | BoltSentence - | BoltReferenceTypeNode + | BoltReferenceTypeExpression + | BoltTypeParameter | BoltBindPattern | BoltTypePattern | BoltExpressionPattern @@ -770,19 +814,22 @@ export type BoltSyntax | BoltResumeStatement | BoltExpressionStatement | BoltParameter - | BoltNewTypeDeclaration | BoltModule | BoltFunctionDeclaration | BoltVariableDeclaration | BoltPlainImportSymbol | BoltImportDeclaration | BoltRecordDeclarationField + | BoltTypeAliasDeclaration | BoltRecordDeclaration export type JSSyntax = JSOperator | JSIdentifier + | JSReturnKeyword + | JSTryKeyword + | JSCatchKeyword | JSBindPattern | JSConstantExpression | JSMemberExpression @@ -800,17 +847,16 @@ export type JSSyntax | JSArrowFunctionDeclaration | JSLetDeclaration | JSSourceFile - | JSSourceElement export type Syntax - = FunctionBody + = EndOfFile + | FunctionBody | BoltStringLiteral | BoltIntegerLiteral | BoltIdentifier | BoltOperator | BoltAssignment - | BoltEOS | BoltComma | BoltSemi | BoltColon @@ -834,14 +880,16 @@ export type Syntax | BoltMutKeyword | BoltEnumKeyword | BoltStructKeyword - | BoltNewTypeKeyword + | BoltTypeKeyword + | BoltTraitKeyworkd | BoltParenthesized | BoltBraced | BoltBracketed | BoltSourceFile | BoltQualName | BoltSentence - | BoltReferenceTypeNode + | BoltReferenceTypeExpression + | BoltTypeParameter | BoltBindPattern | BoltTypePattern | BoltExpressionPattern @@ -862,16 +910,19 @@ export type Syntax | BoltResumeStatement | BoltExpressionStatement | BoltParameter - | BoltNewTypeDeclaration | BoltModule | BoltFunctionDeclaration | BoltVariableDeclaration | BoltPlainImportSymbol | BoltImportDeclaration | BoltRecordDeclarationField + | BoltTypeAliasDeclaration | BoltRecordDeclaration | JSOperator | JSIdentifier + | JSReturnKeyword + | JSTryKeyword + | JSCatchKeyword | JSBindPattern | JSConstantExpression | JSMemberExpression @@ -889,18 +940,17 @@ export type Syntax | JSArrowFunctionDeclaration | JSLetDeclaration | JSSourceFile - | JSSourceElement export function kindToString(kind: SyntaxKind): string; +export function createEndOfFile(span?: TextSpan | null): EndOfFile; export function createFunctionBody(span?: TextSpan | null): FunctionBody; export function createBoltStringLiteral(value: string, span?: TextSpan | null): BoltStringLiteral; export function createBoltIntegerLiteral(value: bigint, span?: TextSpan | null): BoltIntegerLiteral; export function createBoltIdentifier(text: string, span?: TextSpan | null): BoltIdentifier; export function createBoltOperator(text: string, span?: TextSpan | null): BoltOperator; export function createBoltAssignment(operator: string | null, span?: TextSpan | null): BoltAssignment; -export function createBoltEOS(span?: TextSpan | null): BoltEOS; export function createBoltComma(span?: TextSpan | null): BoltComma; export function createBoltSemi(span?: TextSpan | null): BoltSemi; export function createBoltColon(span?: TextSpan | null): BoltColon; @@ -924,21 +974,23 @@ export function createBoltModKeyword(span?: TextSpan | null): BoltModKeyword; export function createBoltMutKeyword(span?: TextSpan | null): BoltMutKeyword; export function createBoltEnumKeyword(span?: TextSpan | null): BoltEnumKeyword; export function createBoltStructKeyword(span?: TextSpan | null): BoltStructKeyword; -export function createBoltNewTypeKeyword(span?: TextSpan | null): BoltNewTypeKeyword; +export function createBoltTypeKeyword(span?: TextSpan | null): BoltTypeKeyword; +export function createBoltTraitKeyworkd(span?: TextSpan | null): BoltTraitKeyworkd; export function createBoltParenthesized(text: string, span?: TextSpan | null): BoltParenthesized; export function createBoltBraced(text: string, span?: TextSpan | null): BoltBraced; 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 createBoltReferenceTypeNode(name: BoltQualName, arguments: BoltTypeNode[] | null, span?: TextSpan | null): BoltReferenceTypeNode; +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; -export function createBoltTypePattern(type: BoltTypeNode, nestedPattern: BoltPattern, span?: TextSpan | null): BoltTypePattern; +export function createBoltTypePattern(type: BoltTypeExpression, nestedPattern: BoltPattern, span?: TextSpan | null): BoltTypePattern; export function createBoltExpressionPattern(expression: BoltExpression, span?: TextSpan | null): BoltExpressionPattern; export function createBoltTuplePatternElement(index: number, pattern: BoltPattern, span?: TextSpan | null): BoltTuplePatternElement; export function createBoltTuplePattern(elements: BoltTuplePatternElement[], span?: TextSpan | null): BoltTuplePattern; export function createBoltRecordPatternField(name: BoltIdentifier, pattern: BoltPattern, span?: TextSpan | null): BoltRecordPatternField; -export function createBoltRecordPattern(name: BoltTypeNode, fields: BoltRecordPatternField[], span?: TextSpan | null): BoltRecordPattern; +export function createBoltRecordPattern(name: BoltTypeExpression, fields: BoltRecordPatternField[], span?: TextSpan | null): BoltRecordPattern; export function createBoltReferenceExpression(name: BoltQualName, span?: TextSpan | null): BoltReferenceExpression; export function createBoltCallExpression(operator: BoltExpression, operands: BoltExpression[], span?: TextSpan | null): BoltCallExpression; export function createBoltYieldExpression(value: BoltExpression, span?: TextSpan | null): BoltYieldExpression; @@ -951,17 +1003,20 @@ export function createBoltConstantExpression(value: BoltValue, span?: TextSpan | export function createBoltReturnStatement(value: BoltExpression | null, span?: TextSpan | null): BoltReturnStatement; export function createBoltResumeStatement(value: BoltExpression, span?: TextSpan | null): BoltResumeStatement; export function createBoltExpressionStatement(expression: BoltExpression, span?: TextSpan | null): BoltExpressionStatement; -export function createBoltParameter(index: number, bindings: BoltPattern, type: BoltTypeNode | null, defaultValue: BoltExpression | null, span?: TextSpan | null): BoltParameter; -export function createBoltNewTypeDeclaration(modifiers: BoltDeclarationModifiers, name: BoltIdentifier, span?: TextSpan | null): BoltNewTypeDeclaration; +export function createBoltParameter(index: number, bindings: BoltPattern, type: BoltTypeExpression | null, defaultValue: BoltExpression | null, span?: TextSpan | null): BoltParameter; export function createBoltModule(modifiers: BoltDeclarationModifiers, name: BoltQualName, elements: BoltSourceElement[], span?: TextSpan | null): BoltModule; -export function createBoltFunctionDeclaration(modifiers: BoltDeclarationModifiers, target: string, name: BoltSymbol, params: BoltParameter[], returnType: BoltTypeNode | null, body: BoltStatement[], span?: TextSpan | null): BoltFunctionDeclaration; -export function createBoltVariableDeclaration(modifiers: BoltDeclarationModifiers, bindings: BoltPattern, type: BoltTypeNode | null, value: BoltExpression | null, span?: TextSpan | null): BoltVariableDeclaration; +export function createBoltFunctionDeclaration(modifiers: BoltDeclarationModifiers, target: string, name: BoltSymbol, params: BoltParameter[], returnType: BoltTypeExpression | null, body: BoltStatement[], span?: TextSpan | null): BoltFunctionDeclaration; +export function createBoltVariableDeclaration(modifiers: BoltDeclarationModifiers, bindings: BoltPattern, type: BoltTypeExpression | null, value: BoltExpression | null, span?: TextSpan | null): BoltVariableDeclaration; export function createBoltPlainImportSymbol(name: BoltQualName, span?: TextSpan | null): BoltPlainImportSymbol; export function createBoltImportDeclaration(file: string, symbols: BoltImportSymbol[], span?: TextSpan | null): BoltImportDeclaration; -export function createBoltRecordDeclarationField(name: BoltIdentifier, type: BoltTypeNode, span?: TextSpan | null): BoltRecordDeclarationField; -export function createBoltRecordDeclaration(modifiers: BoltDeclarationModifiers, name: BoltQualName, fields: BoltRecordDeclarationField[], span?: TextSpan | null): BoltRecordDeclaration; +export function createBoltRecordDeclarationField(name: BoltIdentifier, type: BoltTypeExpression, span?: TextSpan | null): BoltRecordDeclarationField; +export function createBoltTypeAliasDeclaration(modifiers: BoltDeclarationModifiers, name: BoltIdentifier, typeParams: BoltTypeParameter[] | null, typeExpr: BoltTypeExpression, span?: TextSpan | null): BoltTypeAliasDeclaration; +export function createBoltRecordDeclaration(modifiers: BoltDeclarationModifiers, name: BoltQualName, typeParms: BoltTypeParameter[] | null, fields: BoltRecordDeclarationField[], span?: TextSpan | null): BoltRecordDeclaration; export function createJSOperator(text: string, span?: TextSpan | null): JSOperator; export function createJSIdentifier(text: string, span?: TextSpan | null): JSIdentifier; +export function createJSReturnKeyword(span?: TextSpan | null): JSReturnKeyword; +export function createJSTryKeyword(span?: TextSpan | null): JSTryKeyword; +export function createJSCatchKeyword(span?: TextSpan | null): JSCatchKeyword; export function createJSBindPattern(name: JSIdentifier, span?: TextSpan | null): JSBindPattern; export function createJSConstantExpression(value: BoltValue, span?: TextSpan | null): JSConstantExpression; export function createJSMemberExpression(value: JSExpression, property: JSExpression, modifiers: JSMemberExpressionModifiers, span?: TextSpan | null): JSMemberExpression; @@ -979,8 +1034,8 @@ export function createJSFunctionDeclaration(modifiers: JSDeclarationModifiers, n export function createJSArrowFunctionDeclaration(name: JSIdentifier, params: JSParameter[], body: JSExpression, span?: TextSpan | null): JSArrowFunctionDeclaration; export function createJSLetDeclaration(bindings: JSPattern, value: JSExpression | null, span?: TextSpan | null): JSLetDeclaration; export function createJSSourceFile(elements: JSSourceElement[], span?: TextSpan | null): JSSourceFile; -export function createJSSourceElement(span?: TextSpan | null): JSSourceElement; +export function isEndOfFile(value: any): value is EndOfFile; export function isFunctionBody(value: any): value is FunctionBody; export function isBoltToken(value: any): value is BoltToken; export function isBoltStringLiteral(value: any): value is BoltStringLiteral; @@ -989,7 +1044,6 @@ export function isBoltSymbol(value: any): value is BoltSymbol; export function isBoltIdentifier(value: any): value is BoltIdentifier; export function isBoltOperator(value: any): value is BoltOperator; export function isBoltAssignment(value: any): value is BoltAssignment; -export function isBoltEOS(value: any): value is BoltEOS; export function isBoltComma(value: any): value is BoltComma; export function isBoltSemi(value: any): value is BoltSemi; export function isBoltColon(value: any): value is BoltColon; @@ -1014,7 +1068,8 @@ export function isBoltModKeyword(value: any): value is BoltModKeyword; export function isBoltMutKeyword(value: any): value is BoltMutKeyword; export function isBoltEnumKeyword(value: any): value is BoltEnumKeyword; export function isBoltStructKeyword(value: any): value is BoltStructKeyword; -export function isBoltNewTypeKeyword(value: any): value is BoltNewTypeKeyword; +export function isBoltTypeKeyword(value: any): value is BoltTypeKeyword; +export function isBoltTraitKeyworkd(value: any): value is BoltTraitKeyworkd; export function isBoltPunctuated(value: any): value is BoltPunctuated; export function isBoltParenthesized(value: any): value is BoltParenthesized; export function isBoltBraced(value: any): value is BoltBraced; @@ -1022,8 +1077,9 @@ 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 isBoltTypeNode(value: any): value is BoltTypeNode; -export function isBoltReferenceTypeNode(value: any): value is BoltReferenceTypeNode; +export function isBoltTypeExpression(value: any): value is BoltTypeExpression; +export function isBoltReferenceTypeExpression(value: any): value is BoltReferenceTypeExpression; +export function isBoltTypeParameter(value: any): value is BoltTypeParameter; export function isBoltPattern(value: any): value is BoltPattern; export function isBoltBindPattern(value: any): value is BoltBindPattern; export function isBoltTypePattern(value: any): value is BoltTypePattern; @@ -1048,7 +1104,7 @@ export function isBoltResumeStatement(value: any): value is BoltResumeStatement; export function isBoltExpressionStatement(value: any): value is BoltExpressionStatement; export function isBoltParameter(value: any): value is BoltParameter; export function isBoltDeclaration(value: any): value is BoltDeclaration; -export function isBoltNewTypeDeclaration(value: any): value is BoltNewTypeDeclaration; +export function isBoltTypeDeclaration(value: any): value is BoltTypeDeclaration; export function isBoltModule(value: any): value is BoltModule; export function isBoltFunctionDeclaration(value: any): value is BoltFunctionDeclaration; export function isBoltVariableDeclaration(value: any): value is BoltVariableDeclaration; @@ -1056,11 +1112,15 @@ export function isBoltImportSymbol(value: any): value is BoltImportSymbol; export function isBoltPlainImportSymbol(value: any): value is BoltPlainImportSymbol; export function isBoltImportDeclaration(value: any): value is BoltImportDeclaration; export function isBoltRecordDeclarationField(value: any): value is BoltRecordDeclarationField; +export function isBoltTypeAliasDeclaration(value: any): value is BoltTypeAliasDeclaration; export function isBoltSourceElement(value: any): value is BoltSourceElement; export function isBoltRecordDeclaration(value: any): value is BoltRecordDeclaration; export function isJSToken(value: any): value is JSToken; export function isJSOperator(value: any): value is JSOperator; export function isJSIdentifier(value: any): value is JSIdentifier; +export function isJSReturnKeyword(value: any): value is JSReturnKeyword; +export function isJSTryKeyword(value: any): value is JSTryKeyword; +export function isJSCatchKeyword(value: any): value is JSCatchKeyword; export function isJSPattern(value: any): value is JSPattern; export function isJSBindPattern(value: any): value is JSBindPattern; export function isJSExpression(value: any): value is JSExpression; @@ -1073,6 +1133,7 @@ export function isJSNewExpression(value: any): value is JSNewExpression; export function isJSSequenceExpression(value: any): value is JSSequenceExpression; export function isJSConditionalExpression(value: any): value is JSConditionalExpression; export function isJSReferenceExpression(value: any): value is JSReferenceExpression; +export function isJSSourceElement(value: any): value is JSSourceElement; export function isJSStatement(value: any): value is JSStatement; export function isJSExpressionStatement(value: any): value is JSExpressionStatement; export function isJSConditionalStatement(value: any): value is JSConditionalStatement; @@ -1082,4 +1143,3 @@ export function isJSFunctionDeclaration(value: any): value is JSFunctionDeclarat export function isJSArrowFunctionDeclaration(value: any): value is JSArrowFunctionDeclaration; export function isJSLetDeclaration(value: any): value is JSLetDeclaration; export function isJSSourceFile(value: any): value is JSSourceFile; -export function isJSSourceElement(value: any): value is JSSourceElement; diff --git a/src/compiler.ts b/src/compiler.ts index 5f8ac197c..dcaa7c0a3 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -125,7 +125,7 @@ export class Compiler { // TODO break; - case SyntaxKind.BoltNewTypeDeclaration: + case SyntaxKind.BoltTypeAliasDeclaration: break; case SyntaxKind.BoltVariableDeclaration: diff --git a/src/debugServer.ts b/src/debugServer.ts new file mode 100644 index 000000000..40b4e7047 --- /dev/null +++ b/src/debugServer.ts @@ -0,0 +1,5 @@ + +export function connectToInspector(address: string) { + +} + diff --git a/src/expander.ts b/src/expander.ts index 4e1b08fb2..327145e7e 100644 --- a/src/expander.ts +++ b/src/expander.ts @@ -228,7 +228,7 @@ export class Expander { } else { - this.checker.check(node); + //this.checker.check(node); return node; diff --git a/src/parser.ts b/src/parser.ts index e59228308..0b86338a7 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1,4 +1,4 @@ - +) import * as acorn from "acorn" import { @@ -19,8 +19,8 @@ import { BoltPattern, createBoltBindPattern, BoltImportDeclaration, - BoltTypeNode, - createBoltReferenceTypeNode, + BoltTypeExpression, + createBoltReferenceTypeExpression, createBoltConstantExpression, createBoltReferenceExpression, createBoltParameter, @@ -42,18 +42,27 @@ import { BoltRecordDeclarationField, BoltModule, createBoltModule, - BoltNewTypeDeclaration, - createBoltNewTypeDeclaration, + BoltTypeAliasDeclaration, + createBoltTypeAliasDeclaration, BoltFunctionDeclaration, createBoltFunctionDeclaration, createBoltCallExpression, BoltSymbol, + JSSourceElement, + JSStatement, + BoltTypeParameter, + createBoltTypePattern, + createBoltTypeParameter, } from "./ast" -import { Stream, setOrigNodeRange, createTokenStream, uniq } from "./util" +import { Scanner } from "./scanner" + +import { Stream, setOrigNodeRange, createTokenStream, uniq, FastStringMap } from "./util" export type BoltTokenStream = Stream; +export type JSTokenStream = Stream; + function describeKind(kind: SyntaxKind): string { switch (kind) { case SyntaxKind.BoltIdentifier: @@ -94,16 +103,22 @@ function describeKind(kind: SyntaxKind): string { return "'struct'" case SyntaxKind.BoltEnumKeyword: return "'enum'" - case SyntaxKind.BoltNewTypeKeyword: - return "'newtype'"; + case SyntaxKind.BoltTypeKeyword: + return "'type'"; case SyntaxKind.BoltBraced: return "'{' .. '}'" case SyntaxKind.BoltBracketed: return "'[' .. ']'" case SyntaxKind.BoltParenthesized: return "'(' .. ')'" - case SyntaxKind.BoltEOS: + case SyntaxKind.EndOfFile: return "'}', ')', ']' or end-of-file" + case SyntaxKind.BoltLtSign: + return "'<'"; + case SyntaxKind.BoltGtSign: + return "'<'"; + case SyntaxKind.BoltEqSign: + return "'='"; default: throw new Error(`failed to describe ${kindToString(kind)}`) } @@ -117,7 +132,6 @@ function enumerate(elements: string[]) { } } - export class ParseError extends Error { constructor(public actual: BoltToken, public expected: SyntaxKind[]) { super(`${actual.span!.file.origPath}:${actual.span!.start.line}:${actual.span!.start.column}: expected ${enumerate(expected.map(e => describeKind(e)))} but got ${describeKind(actual.kind)}`) @@ -131,6 +145,10 @@ enum OperatorKind { Suffix, } +function isRightAssoc(kind: OperatorKind) { + return kind === OperatorKind.InfixR; +} + interface OperatorInfo { kind: OperatorKind; arity: number; @@ -162,9 +180,9 @@ const KIND_DECLARATION_KEYWORD = [ SyntaxKind.BoltFnKeyword, SyntaxKind.BoltEnumKeyword, SyntaxKind.BoltLetKeyword, - SyntaxKind.BoltNewTypeKeyword, SyntaxKind.BoltModKeyword, SyntaxKind.BoltStructKeyword, + SyntaxKind.BoltTypeKeyword, ] const KIND_DECLARATION_T0 = uniq([ @@ -180,9 +198,37 @@ const KIND_SOURCEELEMENT_T0 = uniq([ ...KIND_DECLARATION_T0, ]) +type OperatorTableMatrix = [OperatorKind, number, string][][]; + +class OperatorTable { + + private operatorsByName = new FastStringMap(); + //private operatorsByPrecedence = FastStringMap(); + + constructor(definitions: OperatorTableMatrix) { + let i = 0; + for (const group of definitions) { + for (const [kind, arity, name] of group) { + const info = { kind, arity, name, precedence: i } + this.operatorsByName.set(name, info); + //this.operatorsByPrecedence[i] = info; + } + i++; + } + } + + public lookup(name: string): OperatorInfo | null { + if (!this.operatorsByName.has(name)) { + return null; + } + return this.operatorsByName.get(name); + } + +} + export class Parser { - operatorTable = [ + exprOperatorTable = new OperatorTable([ [ [OperatorKind.InfixL, 2, '&&'], [OperatorKind.InfixL, 2, '||'] @@ -207,14 +253,20 @@ export class Parser { [OperatorKind.InfixL, 2, '%'], ], [ - [OperatorKind.Prefix, '!'] + [OperatorKind.Prefix, 1, '!'] ], - ]; + ]); + + typeOperatorTable = new OperatorTable([ + [ + [OperatorKind.InfixL, 2, '|'], + ] + ]); protected assertEmpty(tokens: BoltTokenStream) { const t0 = tokens.peek(1); - if (t0.kind !== SyntaxKind.BoltEOS) { - throw new ParseError(t0, [SyntaxKind.BoltEOS]); + if (t0.kind !== SyntaxKind.EndOfFile) { + throw new ParseError(t0, [SyntaxKind.EndOfFile]); } } @@ -280,15 +332,16 @@ export class Parser { return node; } - public parseReferenceTypeNode(tokens: BoltTokenStream) { + public parseReferenceTypeExpression(tokens: BoltTokenStream) { const name = this.parseQualName(tokens) const t1 = tokens.peek(); - let typeArgs: BoltTypeNode[] | null = null; + let typeArgs: BoltTypeExpression[] | null = null; if (t1.kind === SyntaxKind.BoltLtSign) { + typeArgs = []; tokens.get(); let first = true; while (true) { @@ -302,26 +355,63 @@ export class Parser { assertToken(t2, SyntaxKind.BoltComma); tokens.get(); } - typeArgs!.push(this.parseTypeNode(tokens)); + typeArgs!.push(this.parseTypeExpression(tokens)); } const t4 = tokens.get(); assertToken(t4, SyntaxKind.BoltGtSign); } - const node = createBoltReferenceTypeNode(name, typeArgs); + const node = createBoltReferenceTypeExpression(name, typeArgs); setOrigNodeRange(node, name, name); return node; } - public parseTypeNode(tokens: BoltTokenStream): BoltTypeNode { + private parsePrimTypeExpression(tokens: BoltTokenStream): BoltTypeExpression { const t0 = tokens.peek(); if (t0.kind === SyntaxKind.BoltIdentifier) { - return this.parseReferenceTypeNode(tokens); + return this.parseReferenceTypeExpression(tokens); } else { throw new ParseError(t0, [SyntaxKind.BoltIdentifier]); } } + private parseTypeExpressionOperators(tokens: BoltTokenStream, lhs: BoltTypeExpression, minPrecedence: number): BoltTypeExpression { + while (true) { + const t0 = tokens.peek(); + if (t0.kind !== SyntaxKind.BoltOperator) { + break; + } + let desc0 = this.typeOperatorTable.lookup(t0.text); + if (desc0 === null || desc0.arity !== 2 || desc0.precedence < minPrecedence) { + break; + } + console.log(desc0) + tokens.get(); + let rhs = this.parsePrimTypeExpression(tokens); + while (true) { + const t1 = tokens.peek() + if (t1.kind !== SyntaxKind.BoltOperator) { + break; + } + const desc1 = this.typeOperatorTable.lookup(t1.text) + if (desc1 === null || desc1.arity !== 2 || desc1.precedence < desc0.precedence || !isRightAssoc(desc1.kind)) { + break; + } + rhs = this.parseTypeExpressionOperators(tokens, rhs, desc1.precedence); + } + const name = createBoltQualName([], t0); + setOrigNodeRange(name, t0, t0); + lhs = createBoltReferenceTypeExpression(name, [lhs, rhs]); + setOrigNodeRange(lhs, t0, rhs); + } + return lhs + } + + public parseTypeExpression(tokens: BoltTokenStream) { + const lhs = this.parsePrimTypeExpression(tokens); + return this.parseTypeExpressionOperators(tokens, lhs, 0); + } + public parseConstantExpression(tokens: BoltTokenStream): BoltConstantExpression { const t0 = tokens.get(); let value: boolean | string | bigint; @@ -396,7 +486,7 @@ export class Parser { let endNode: BoltSyntax = pattern; if (t0.kind === SyntaxKind.BoltColon) { tokens.get(); - typeDecl = this.parseTypeNode(tokens); + typeDecl = this.parseTypeExpression(tokens); endNode = typeDecl; t0 = tokens.get(); } @@ -434,7 +524,7 @@ export class Parser { if (t2.kind === SyntaxKind.BoltColon) { tokens.get(); - lastNode = typeDecl = this.parseTypeNode(tokens); + lastNode = typeDecl = this.parseTypeExpression(tokens); t2 = tokens.peek(); } @@ -456,7 +546,7 @@ export class Parser { let expr = null; const t1 = tokens.peek(); - if (t1.kind !== SyntaxKind.BoltEOS) { + if (t1.kind !== SyntaxKind.EndOfFile) { expr = this.parseExpression(tokens) } @@ -506,9 +596,49 @@ export class Parser { } } + public parseGenericTypeParameter(tokens: BoltTokenStream) { + const t0 = tokens.peek(); + if (t0.kind === SyntaxKind.BoltIdentifier) { + tokens.get(); + const node = createBoltTypeParameter(0, t0, null) + setOrigNodeRange(node, t0, t0); + return node; + } else { + throw new ParseError(t0, [SyntaxKind.BoltIdentifier]); + } + } + + private parseGenericTypeParameters(tokens: BoltTokenStream) { + let typeParams: BoltTypeParameter[] = []; + const t0 = tokens.get(); + assertToken(t0, SyntaxKind.BoltLtSign); + while (true) { + let t1 = tokens.peek(); + if (t1.kind === SyntaxKind.BoltGtSign) { + break; + } + if (t1.kind === SyntaxKind.EndOfFile) { + throw new ParseError(t1, [SyntaxKind.BoltGtSign, SyntaxKind.BoltIdentifier, SyntaxKind.BoltComma]); + } + if (typeParams.length > 0) { + tokens.get(); + assertToken(t1, SyntaxKind.BoltComma); + t1 = tokens.peek(); + } + if (t1.kind === SyntaxKind.EndOfFile) { + throw new ParseError(t1, [SyntaxKind.BoltGtSign, SyntaxKind.BoltIdentifier]); + } + typeParams.push(this.parseGenericTypeParameter(tokens)); + } + const t3 = tokens.get(); + assertToken(t3, SyntaxKind.BoltGtSign); + return typeParams; + } + public parseRecordDeclaration(tokens: BoltTokenStream): BoltRecordDeclaration { let modifiers = 0; + let typeParams = null; let t0 = tokens.get(); const firstToken = t0; @@ -525,31 +655,49 @@ export class Parser { assertToken(t1, SyntaxKind.BoltIdentifier); const name = createBoltQualName([], t1 as BoltIdentifier); - const t2 = tokens.get(); + let t2 = tokens.peek(); + + if (t2.kind === SyntaxKind.EndOfFile) { + const node = createBoltRecordDeclaration(modifiers, name, null, []); + setOrigNodeRange(node, firstToken, t2); + return node; + } + + if (t2.kind === SyntaxKind.BoltLtSign) { + typeParams = this.parseGenericTypeParameters(tokens); + t2 = tokens.peek(); + } if (t2.kind !== SyntaxKind.BoltBraced) { throw new ParseError(t2, [SyntaxKind.BoltBraced]) } let fields: BoltRecordDeclarationField[] = []; + tokens.get(); const innerTokens = createTokenStream(t2); while (true) { - const t3 = innerTokens.get(); - if (t3.kind === SyntaxKind.BoltEOS) { + const t3 = innerTokens.peek(); + if (t3.kind === SyntaxKind.EndOfFile) { break; } - const name = innerTokens.get(); - assertToken(name, SyntaxKind.BoltIdentifier); + assertToken(t3, SyntaxKind.BoltIdentifier); + innerTokens.get(); + const name = t3 as BoltIdentifier; const t4 = innerTokens.get(); assertToken(t4, SyntaxKind.BoltColon); - const type = this.parseTypeNode(innerTokens); + 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, fields); + const node = createBoltRecordDeclaration(modifiers, name, typeParams, fields); setOrigNodeRange(node, firstToken, t2); return node; } @@ -558,7 +706,7 @@ export class Parser { const statements: BoltStatement[] = []; while (true) { const t0 = tokens.peek(); - if (t0.kind === SyntaxKind.BoltEOS) { + if (t0.kind === SyntaxKind.EndOfFile) { break; } const statement = this.parseStatement(tokens); @@ -579,7 +727,7 @@ export class Parser { t0 = tokens.peek(); } - if (t0.kind !== SyntaxKind.BoltIdentifier || t0.text !== 'mod') { + if (t0.kind !== SyntaxKind.BoltModKeyword) { throw new ParseError(t0, [SyntaxKind.BoltModKeyword]) } @@ -589,7 +737,7 @@ export class Parser { if (t1.kind !== SyntaxKind.BoltBraced) { throw new ParseError(t1, [SyntaxKind.BoltBraced]) } - const sentences = this.parseSentences(createTokenStream(t1)); + const sentences = this.parseSourceElementList(createTokenStream(t1)); const node = createBoltModule(modifiers, name, sentences); setOrigNodeRange(node, firstToken, t1); @@ -597,33 +745,38 @@ export class Parser { } - public parseNewTypeDeclaration(tokens: BoltTokenStream): BoltNewTypeDeclaration { + public parseTypeAliasDeclaration(tokens: BoltTokenStream): BoltTypeAliasDeclaration { let modifiers = 0; + let typeParams = null; let t0 = tokens.get(); const firstToken = t0; if (t0.kind === SyntaxKind.BoltPubKeyword) { - tokens.get(); modifiers |= BoltDeclarationModifiers.Public; - t0 = tokens.peek(); - if (t0.kind !== SyntaxKind.BoltIdentifier) { - throw new ParseError(t0, [SyntaxKind.BoltNewTypeKeyword]) - } + t0 = tokens.get(); } - if (t0.kind !== SyntaxKind.BoltNewTypeKeyword) { - throw new ParseError(t0, [SyntaxKind.BoltNewTypeKeyword]) - } + assertToken(t0, SyntaxKind.BoltTypeKeyword); const name = tokens.get(); if (name.kind !== SyntaxKind.BoltIdentifier) { throw new ParseError(name, [SyntaxKind.BoltIdentifier]) } - const node = createBoltNewTypeDeclaration(modifiers, name) - setOrigNodeRange(node, firstToken, name); + const t2 = tokens.peek(); + if (t2.kind === SyntaxKind.BoltLtSign) { + typeParams = this.parseGenericTypeParameters(tokens); + } + + const t3 = tokens.get(); + assertToken(t3, SyntaxKind.BoltEqSign); + + const typeExpr = this.parseTypeExpression(tokens); + + const node = createBoltTypeAliasDeclaration(modifiers, name, typeParams, typeExpr) + setOrigNodeRange(node, firstToken, typeExpr); return node; } @@ -725,17 +878,17 @@ export class Parser { const innerTokens = createTokenStream(t2); while (true) { const t3 = innerTokens.peek(); - if (t3.kind === SyntaxKind.BoltEOS) { + if (t3.kind === SyntaxKind.EndOfFile) { break; } params.push(this.parseParameter(innerTokens, i++)) const t4 = innerTokens.get(); if (t4.kind === SyntaxKind.BoltComma) { continue; - } else if (t4.kind === SyntaxKind.BoltEOS) { + } else if (t4.kind === SyntaxKind.EndOfFile) { break; } else { - throw new ParseError(t4, [SyntaxKind.BoltComma, SyntaxKind.BoltEOS]) + throw new ParseError(t4, [SyntaxKind.BoltComma, SyntaxKind.EndOfFile]) } } } @@ -756,7 +909,7 @@ export class Parser { if (t2.kind === SyntaxKind.BoltRArrow) { lastToken = t2; tokens.get(); - returnType = this.parseTypeNode(tokens); + returnType = this.parseTypeExpression(tokens); } // Parse function body @@ -770,7 +923,8 @@ export class Parser { body = this.parseStatements(tokens); break; case "JS": - body = acorn.parse(t3.text); + const scanner = new Scanner(t3.span!.file, t3.text); + body = this.parseJSSourceElementList(scanner); break; default: throw new Error(`Unrecognised language: ${target}`); @@ -790,6 +944,23 @@ export class Parser { } + //public parseModuleDeclaration(tokens: BoltTokenStream): BoltModule { + //let modifiers = 0; + //let t0 = tokens.get(); + //if (t0.kind === SyntaxKind.BoltPubKeyword) { + //modifiers |= BoltDeclarationModifiers.Public; + //t0 = tokens.get(); + //} + //assertToken(t0, SyntaxKind.BoltModKeyword); + //const name = this.parseQualName(tokens); + //const t1 = tokens.get(); + //assertToken(t1, SyntaxKind.BoltBraced); + //const elements = this.parseSourceElementList(createTokenStream(t1)); + //const node = createBoltModule(modifiers, name, elements); + //setOrigNodeRange(node, t0, t1); + //return node; + //} + public parseDeclaration(tokens: BoltTokenStream): BoltDeclaration { let t0 = tokens.peek(1); let i = 1; @@ -810,8 +981,8 @@ export class Parser { } } switch (t0.kind) { - case SyntaxKind.BoltNewTypeKeyword: - return this.parseNewTypeDeclaration(tokens); + case SyntaxKind.BoltTypeKeyword: + return this.parseTypeAliasDeclaration(tokens); case SyntaxKind.BoltModKeyword: return this.parseModuleDeclaration(tokens); case SyntaxKind.BoltFnKeyword: @@ -826,9 +997,8 @@ export class Parser { throw new ParseError(t0, KIND_DECLARATION_T0); } } - + public parseSourceElement(tokens: BoltTokenStream): BoltSourceElement { - const t0 = tokens.peek(); try { return this.parseDeclaration(tokens) } catch (e1) { @@ -846,19 +1016,20 @@ export class Parser { } } - protected getOperatorDesc(seekArity: number, seekName: string): OperatorInfo { - for (let i = 0; i < this.operatorTable.length; ++i) { - for (const [kind, arity, name] of this.operatorTable[i]) { - if (arity == seekArity && name === seekName) { - return { - kind, - name, - arity, - precedence: i - } - } + public parseSourceElementList(tokens: BoltTokenStream): BoltSourceElement[] { + const elements: BoltSourceElement[] = [] + while (true) { + const t0 = tokens.peek(); + if (t0.kind === SyntaxKind.EndOfFile) { + break; } + if (t0.kind === SyntaxKind.BoltSemi) { + tokens.get(); + continue; + } + elements.push(this.parseSourceElement(tokens)); } + return elements } //parseBinOp(tokens: TokenStream, lhs: Expr , minPrecedence: number) { @@ -887,12 +1058,12 @@ export class Parser { // return lhs //} - public parseCallOrPrimitiveExpression(tokens: BoltTokenStream): BoltExpression { + private parseCallOrPrimitiveExpression(tokens: BoltTokenStream): BoltExpression { const operator = this.parsePrimitiveExpression(tokens) const t2 = tokens.get(); - if (t2.kind === SyntaxKind.BoltEOS) { + if (t2.kind === SyntaxKind.EndOfFile) { return operator; } assertToken(t2, SyntaxKind.BoltParenthesized); @@ -902,12 +1073,12 @@ export class Parser { while (true) { const t3 = innerTokens.peek(); - if (t3.kind === SyntaxKind.BoltEOS) { + if (t3.kind === SyntaxKind.EndOfFile) { break; } args.push(this.parseExpression(innerTokens)) const t4 = innerTokens.get(); - if (t4.kind === SyntaxKind.BoltEOS) { + if (t4.kind === SyntaxKind.EndOfFile) { break } else if (t4.kind !== SyntaxKind.BoltComma){ throw new ParseError(t4, [SyntaxKind.BoltComma]) @@ -920,5 +1091,22 @@ export class Parser { } + public parseJSStatement(tokens: JSTokenStream): JSStatement { + return this.parseJSExpressionStatement(tokens); + } + + public parseJSSourceElementList(tokens: JSTokenStream): JSSourceElement[] { + const elements: JSSourceElement[] = []; + while (true) { + const t0 = tokens.peek(); + if (t0.kind === SyntaxKind.EndOfFile) { + break; + } + const statement = this.parseJSStatement(tokens) + elements.push(statement); + } + return elements; + } + } diff --git a/src/scanner.ts b/src/scanner.ts index da589c379..9a43c4aa1 100644 --- a/src/scanner.ts +++ b/src/scanner.ts @@ -12,6 +12,7 @@ import { SyntaxKind, BoltToken, BoltSentence, + createEndOfFile, createBoltSentence, createBoltIdentifier, createBoltRArrow, @@ -25,7 +26,6 @@ import { createBoltStringLiteral, createBoltIntegerLiteral, createBoltColon, - createBoltEOS, createBoltDot, createBoltEqSign, createBoltPubKeyword, @@ -39,7 +39,12 @@ import { createBoltFnKeyword, createBoltLArrow, createBoltDotDot, - createBoltNewTypeKeyword, + createJSIdentifier, + JSToken, + createBoltLtSign, + createBoltGtSign, + createBoltModKeyword, + createBoltTypeKeyword, } from "./ast" export enum PunctType { @@ -136,7 +141,27 @@ function isIdentPart(ch: string) { } function isSymbol(ch: string) { - return /[=+\/-*%$!><&^|]/.test(ch) + return /[=+\/\-*%$!><&^|]/.test(ch) +} + + +function isJSWhiteSpace(ch: string): boolean { + return ch === '\u0009' + || ch === '\u000B' + || ch === '\u000C' + || ch === '\u0020' + || ch === '\u00A0' + || ch === '\u000B' + || ch === '\uFEFF' + || XRegExp('\\p{Zs}').test(ch) +} + +function isJSIdentStart(ch: string): boolean { + return XRegExp('[\\p{ID_Start}$_\\]').test(ch) +} + +function isJSIdentPart(ch: string): boolean { + return XRegExp('[\u200C\u200D\\p{ID_Continue}$\\]').test(ch) } //function isOperatorPart(ch: string) { @@ -218,7 +243,7 @@ export class Scanner { const startPos = this.currPos.clone() if (c0 == EOF) { - return createBoltEOS(new TextSpan(this.file, startPos, startPos)); + return createEndOfFile(new TextSpan(this.file, startPos, startPos)); } switch (c0) { @@ -313,15 +338,16 @@ export class Scanner { const span = new TextSpan(this.file, startPos, endPos); switch (name) { case 'pub': return createBoltPubKeyword(span); + case 'mod': return createBoltModKeyword(span); case 'fn': return createBoltFnKeyword(span); case 'return': return createBoltReturnKeyword(span); case 'yield': return createBoltYieldKeyword(span); + case 'type': return createBoltTypeKeyword(span); case 'foreign': return createBoltForeignKeyword(span); case 'let': return createBoltPubKeyword(span); case 'mut': return createBoltMutKeyword(span); case 'struct': return createBoltStructKeyword(span); case 'enum': return createBoltEnumKeyword(span); - case 'newtype': return createBoltNewTypeKeyword(span); default: return createBoltIdentifier(name, span); } @@ -331,23 +357,24 @@ export class Scanner { const endPos = this.currPos.clone() const span = new TextSpan(this.file, startPos, endPos); - if (text.endsWith('=')) { - const operator = text.substring(0, text.length-1); - if (text === '==') { - return createBoltOperator(text, span); - } - return createBoltAssignment(operator.length === 0 ? null : operator, span); - } - switch (text) { case '->': return createBoltRArrow(span); case '<-': return createBoltLArrow(span); + case '<': return createBoltLtSign(span); + case '>': return createBoltGtSign(span); case '.': return createBoltDot(span); case '..': return createBoltDotDot(span); case '=': return createBoltEqSign(span); - default: return createBoltOperator(text, span); + case '==': return createBoltOperator(text, span); } + if (text.endsWith('=')) { + const operator = text.substring(0, text.length-1); + return createBoltAssignment(operator.length === 0 ? null : operator, span); + } + + return createBoltOperator(text, span); + } else { throw new ScanError(this.file, this.currPos.clone(), c0); @@ -358,14 +385,14 @@ export class Scanner { } - peek(count = 1): BoltToken { + public peek(count = 1): BoltToken { while (this.scanned.length < count) { this.scanned.push(this.scanToken()); } return this.scanned[count - 1]; } - get(): BoltToken { + public get(): BoltToken { return this.scanned.length > 0 ? this.scanned.shift()! : this.scanToken(); @@ -381,7 +408,7 @@ export class Scanner { inner: while (true) { const token = this.scanToken(); - if (token.kind === SyntaxKind.BoltEOS) { + if (token.kind === SyntaxKind.EndOfFile) { if (tokens.length === 0) { break outer; } else { @@ -411,7 +438,7 @@ export class Scanner { return elements } - scan() { + public scan() { const startPos = this.currPos.clone(); const elements = this.scanTokens(); const endPos = this.currPos.clone(); @@ -421,3 +448,188 @@ export class Scanner { } } + +export class JSScanner { + + private buffer: string[] = []; + private scanned: JSToken[] = []; + private offset = 0; + + constructor( + private file: TextFile, + private input: string, + private currPos: TextPos = new TextPos(0,1,1), + ) { + + } + + protected readChar() { + if (this.offset == this.input.length) { + return EOF + } + return this.input[this.offset++] + } + + protected peekChar(count = 1) { + while (this.buffer.length < count) { + this.buffer.push(this.readChar()); + } + return this.buffer[count - 1]; + } + + protected getChar() { + + const ch = this.buffer.length > 0 + ? this.buffer.shift()! + : this.readChar() + + if (ch == EOF) { + return EOF + } + + if (isNewLine(ch)) { + this.currPos.line += 1; + this.currPos.column = 1; + } else { + this.currPos.column += 1; + } + this.currPos.offset += 1; + + return ch + } + + private assertChar(expected: string) { + const actual = this.getChar(); + if (actual !== expected) { + throw new ScanError(this.file, this.currPos.clone(), actual); + } + } + + private scanLineComment(): string { + let text = ''; + this.assertChar('/'); + this.assertChar('/') + while (true) { + const c2 = this.peekChar(); + if (c2 === '\n') { + this.getChar(); + if (this.peekChar() === '\r') { + this.getChar(); + } + break; + } + if (c2 === EOF) { + break; + } + text += this.getChar(); + } + return text; + } + + private scanMultiLineComment(): string { + let text = ''; + while (true) { + const c2 = this.getChar(); + if (c2 === '*') { + const c3 = this.getChar(); + if (c3 === '/') { + break; + } + text += c2 + c3; + } else if (c2 === EOF) { + throw new ScanError(this.file, this.currPos.clone(), c2); + } else { + text += c2; + } + } + return text; + } + + private skipComments() { + while (true) { + const c0 = this.peekChar(); + if (c0 === '/') { + const c1 = this.peekChar(2); + if (c1 == '/') { + this.scanLineComment(); + } else if (c1 === '*') { + this.scanMultiLineComment(); + } else { + break; + } + } else if (isWhiteSpace(c0)) { + this.getChar(); + } else { + break; + } + } + } + + private scanHexDigit(): number { + const startPos = this.currPos.clone(); + const c0 = this.getChar(); + switch (c0.toLowerCase()) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 0; + case 'a': return 10; + case 'b': return 11; + case 'c': return 12; + case 'd': return 13; + case 'e': return 14; + case 'f': return 15; + default: + throw new ScanError(this.file, startPos, c0); + } + } + + private scanUnicodeEscapeSequence() { + throw new Error(`Scanning unicode escape sequences is not yet implemented.`); + } + + public scan(): JSToken { + this.skipComments(); + const c0 = this.peekChar(); + const startPos = this.currPos.clone(); + if (isJSIdentStart(c0)) { + let name = ''; + while (true) { + const c0 = this.peekChar(); + if (!isJSIdentPart(c0)) { + break; + } + if (c0 === '\\') { + name += this.scanUnicodeEscapeSequence(); + } else { + name += this.getChar(); + } + } + const endPos = this.currPos.clone(); + return createJSIdentifier(name, new TextSpan(this.file, startPos, endPos)) + } else { + throw new ScanError(this.file, this.currPos.clone(), c0); + } + } + + public peek(count = 1): JSToken { + while (this.scanned.length < count) { + this.scanned.push(this.scan()); + } + return this.scanned[count - 1]; + } + + public get(): JSToken { + return this.scanned.length > 0 + ? this.scanned.shift()! + : this.scan(); + } + +} + diff --git a/src/util.ts b/src/util.ts index a129eba23..c9ec5902d 100644 --- a/src/util.ts +++ b/src/util.ts @@ -6,7 +6,7 @@ import chalk from "chalk" import { TextSpan, TextPos } from "./text" import { Scanner } from "./scanner" -import { kindToString, Syntax, BoltQualName, BoltDeclaration, BoltDeclarationModifiers, createBoltEOS, SyntaxKind, isBoltPunctuated } from "./ast" +import { kindToString, Syntax, BoltQualName, BoltDeclaration, BoltDeclarationModifiers, createEndOfFile, SyntaxKind, isBoltPunctuated } from "./ast" export function createTokenStream(node: Syntax) { if (isBoltPunctuated(node)) { @@ -16,7 +16,7 @@ export function createTokenStream(node: Syntax) { } else if (node.kind === SyntaxKind.BoltSentence) { return new StreamWrapper( node.tokens, - () => createBoltEOS(new TextSpan(node.span!.file, node.span!.end.clone(), node.span!.end.clone())) + () => createEndOfFile(new TextSpan(node.span!.file, node.span!.end.clone(), node.span!.end.clone())) ); } else { throw new Error(`Could not convert ${kindToString(node.kind)} to a token stream.`); @@ -40,8 +40,36 @@ export function uniq(elements: T[]): T[] { return out; } -export interface FastStringMap { - [key: string]: T + +export class FastStringMap { + + private mapping = Object.create(null); + + public get(key: K): V { + if (!(key in this.mapping)) { + throw new Error(`No value found for key '${key}'.`); + } + return 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.`); + } + this.mapping[key] = value + } + + public has(key: K): boolean { + return key in this.mapping; + } + + public delete(key: K): void { + if (!(key in this.mapping)) { + throw new Error(`No value found for key '${key}'.`); + } + delete this.mapping[key]; + } + } class DeepMap { diff --git a/tsconfig.json b/tsconfig.json index 39b1f93b9..c28c2392c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "outDir": "./lib", "strict": true, "esModuleInterop": true, - "inlineSourceMap": true, + "sourceMap": true, "experimentalDecorators": true, "emitDecoratorMetadata": true }