From 8f661f49a79b02c984106f05008533b999baf2e3 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Sun, 24 May 2020 21:18:54 +0200 Subject: [PATCH] Enable parsing member expressions --- spec/ast.txt | 5 ++ src/ast.d.ts | 190 +++++++++++++++++++++++++++----------------------- src/parser.ts | 108 ++++++++++++++++------------ 3 files changed, 171 insertions(+), 132 deletions(-) diff --git a/spec/ast.txt b/spec/ast.txt index 17e0636ff..7be3ed512 100644 --- a/spec/ast.txt +++ b/spec/ast.txt @@ -155,6 +155,11 @@ node BoltReferenceExpression > BoltExpression { name: BoltQualName, } +node BoltMemberExpression > BoltExpression { + expression: BoltExpression, + path: Vec, +} + node BoltFunctionExpression > BoltExpression { params: Vec, returnType: Option, diff --git a/src/ast.d.ts b/src/ast.d.ts index 92fb7d2a6..2c0d996d8 100644 --- a/src/ast.d.ts +++ b/src/ast.d.ts @@ -56,95 +56,96 @@ export const enum SyntaxKind { BoltRecordPattern = 65, BoltQuoteExpression = 67, BoltReferenceExpression = 68, - BoltFunctionExpression = 69, - BoltCallExpression = 70, - BoltYieldExpression = 71, - BoltMatchArm = 72, - BoltMatchExpression = 73, - BoltCase = 74, - BoltCaseExpression = 75, - BoltBlockExpression = 76, - BoltConstantExpression = 77, - BoltReturnStatement = 79, - BoltConditionalCase = 80, - BoltConditionalStatement = 81, - BoltResumeStatement = 82, - BoltExpressionStatement = 83, - BoltParameter = 84, - BoltModule = 88, - BoltFunctionDeclaration = 90, - BoltVariableDeclaration = 91, - BoltPlainImportSymbol = 93, - BoltImportDeclaration = 94, - BoltTraitDeclaration = 95, - BoltImplDeclaration = 96, - BoltTypeAliasDeclaration = 97, - BoltRecordField = 99, - BoltRecordDeclaration = 100, - BoltMacroCall = 102, - JSOperator = 105, - JSIdentifier = 106, - JSString = 107, - JSInteger = 108, - JSFromKeyword = 109, - JSReturnKeyword = 110, - JSTryKeyword = 111, - JSFinallyKeyword = 112, - JSCatchKeyword = 113, - JSImportKeyword = 114, - JSAsKeyword = 115, - JSConstKeyword = 116, - JSLetKeyword = 117, - JSExportKeyword = 118, - JSFunctionKeyword = 119, - JSWhileKeyword = 120, - JSForKeyword = 121, - JSCloseBrace = 122, - JSCloseBracket = 123, - JSCloseParen = 124, - JSOpenBrace = 125, - JSOpenBracket = 126, - JSOpenParen = 127, - JSSemi = 128, - JSComma = 129, - JSDot = 130, - JSDotDotDot = 131, - JSMulOp = 132, - JSAddOp = 133, - JSDivOp = 134, - JSSubOp = 135, - JSLtOp = 136, - JSGtOp = 137, - JSBOrOp = 138, - JSBXorOp = 139, - JSBAndOp = 140, - JSBNotOp = 141, - JSNotOp = 142, - JSBindPattern = 144, - JSConstantExpression = 146, - JSMemberExpression = 147, - JSCallExpression = 148, - JSBinaryExpression = 149, - JSUnaryExpression = 150, - JSNewExpression = 151, - JSSequenceExpression = 152, - JSConditionalExpression = 153, - JSLiteralExpression = 155, - JSReferenceExpression = 156, - JSCatchBlock = 160, - JSTryCatchStatement = 161, - JSExpressionStatement = 162, - JSConditionalCase = 163, - JSConditionalStatement = 164, - JSReturnStatement = 165, - JSParameter = 166, - JSImportStarBinding = 170, - JSImportAsBinding = 171, - JSImportDeclaration = 172, - JSFunctionDeclaration = 173, - JSArrowFunctionDeclaration = 174, - JSLetDeclaration = 175, - JSSourceFile = 176, + BoltMemberExpression = 69, + BoltFunctionExpression = 70, + BoltCallExpression = 71, + BoltYieldExpression = 72, + BoltMatchArm = 73, + BoltMatchExpression = 74, + BoltCase = 75, + BoltCaseExpression = 76, + BoltBlockExpression = 77, + BoltConstantExpression = 78, + BoltReturnStatement = 80, + BoltConditionalCase = 81, + BoltConditionalStatement = 82, + BoltResumeStatement = 83, + BoltExpressionStatement = 84, + BoltParameter = 85, + BoltModule = 89, + BoltFunctionDeclaration = 91, + BoltVariableDeclaration = 92, + BoltPlainImportSymbol = 94, + BoltImportDeclaration = 95, + BoltTraitDeclaration = 96, + BoltImplDeclaration = 97, + BoltTypeAliasDeclaration = 98, + BoltRecordField = 100, + BoltRecordDeclaration = 101, + BoltMacroCall = 103, + JSOperator = 106, + JSIdentifier = 107, + JSString = 108, + JSInteger = 109, + JSFromKeyword = 110, + JSReturnKeyword = 111, + JSTryKeyword = 112, + JSFinallyKeyword = 113, + JSCatchKeyword = 114, + JSImportKeyword = 115, + JSAsKeyword = 116, + JSConstKeyword = 117, + JSLetKeyword = 118, + JSExportKeyword = 119, + JSFunctionKeyword = 120, + JSWhileKeyword = 121, + JSForKeyword = 122, + JSCloseBrace = 123, + JSCloseBracket = 124, + JSCloseParen = 125, + JSOpenBrace = 126, + JSOpenBracket = 127, + JSOpenParen = 128, + JSSemi = 129, + JSComma = 130, + JSDot = 131, + JSDotDotDot = 132, + JSMulOp = 133, + JSAddOp = 134, + JSDivOp = 135, + JSSubOp = 136, + JSLtOp = 137, + JSGtOp = 138, + JSBOrOp = 139, + JSBXorOp = 140, + JSBAndOp = 141, + JSBNotOp = 142, + JSNotOp = 143, + JSBindPattern = 145, + JSConstantExpression = 147, + JSMemberExpression = 148, + JSCallExpression = 149, + JSBinaryExpression = 150, + JSUnaryExpression = 151, + JSNewExpression = 152, + JSSequenceExpression = 153, + JSConditionalExpression = 154, + JSLiteralExpression = 156, + JSReferenceExpression = 157, + JSCatchBlock = 161, + JSTryCatchStatement = 162, + JSExpressionStatement = 163, + JSConditionalCase = 164, + JSConditionalStatement = 165, + JSReturnStatement = 166, + JSParameter = 167, + JSImportStarBinding = 171, + JSImportAsBinding = 172, + JSImportDeclaration = 173, + JSFunctionDeclaration = 174, + JSArrowFunctionDeclaration = 175, + JSLetDeclaration = 176, + JSSourceFile = 177, } @@ -610,6 +611,7 @@ export interface BoltRecordPattern extends SyntaxBase { + kind: SyntaxKind.BoltMemberExpression; + expression: BoltExpression; + path: BoltIdentifier[]; +} + export interface BoltFunctionExpression extends SyntaxBase { kind: SyntaxKind.BoltFunctionExpression; params: BoltParameter[]; @@ -1321,6 +1329,7 @@ export type BoltSyntax | BoltRecordPattern | BoltQuoteExpression | BoltReferenceExpression + | BoltMemberExpression | BoltFunctionExpression | BoltCallExpression | BoltYieldExpression @@ -1472,6 +1481,7 @@ export type Syntax | BoltRecordPattern | BoltQuoteExpression | BoltReferenceExpression + | BoltMemberExpression | BoltFunctionExpression | BoltCallExpression | BoltYieldExpression @@ -1621,6 +1631,7 @@ export function createBoltRecordFieldPattern(isRest: boolean, name: BoltIdentifi export function createBoltRecordPattern(name: BoltQualName, fields: BoltRecordFieldPattern[], span?: TextSpan | null): BoltRecordPattern; export function createBoltQuoteExpression(tokens: Token[], span?: TextSpan | null): BoltQuoteExpression; export function createBoltReferenceExpression(name: BoltQualName, span?: TextSpan | null): BoltReferenceExpression; +export function createBoltMemberExpression(expression: BoltExpression, path: BoltIdentifier[], span?: TextSpan | null): BoltMemberExpression; export function createBoltFunctionExpression(params: BoltParameter[], returnType: BoltTypeExpression | null, body: BoltFunctionBodyElement[], span?: TextSpan | null): BoltFunctionExpression; export function createBoltCallExpression(operator: BoltExpression, operands: BoltExpression[], span?: TextSpan | null): BoltCallExpression; export function createBoltYieldExpression(value: BoltExpression, span?: TextSpan | null): BoltYieldExpression; @@ -1777,6 +1788,7 @@ export function isBoltRecordPattern(value: any): value is BoltRecordPattern; export function isBoltExpression(value: any): value is BoltExpression; export function isBoltQuoteExpression(value: any): value is BoltQuoteExpression; export function isBoltReferenceExpression(value: any): value is BoltReferenceExpression; +export function isBoltMemberExpression(value: any): value is BoltMemberExpression; export function isBoltFunctionExpression(value: any): value is BoltFunctionExpression; export function isBoltCallExpression(value: any): value is BoltCallExpression; export function isBoltYieldExpression(value: any): value is BoltYieldExpression; diff --git a/src/parser.ts b/src/parser.ts index 659ec679f..cdfbd0da5 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -82,6 +82,8 @@ import { createBoltFunctionExpression, BoltMacroCall, createBoltMacroCall, + BoltMemberExpression, + createBoltMemberExpression, } from "./ast" import { parseForeignLanguage } from "./foreign" @@ -594,27 +596,80 @@ export class Parser { return result; } - private parsePrimitiveExpression(tokens: BoltTokenStream): BoltExpression { + private parseExpression(tokens: BoltTokenStream): BoltExpression { + const t0 = tokens.peek(); + + let result; if (t0.kind === SyntaxKind.BoltVBar) { - return this.parseFunctionExpression(tokens); + result = this.parseFunctionExpression(tokens); } else if (t0.kind === SyntaxKind.BoltBraced) { - return this.parseBlockExpression(tokens); + result = this.parseBlockExpression(tokens); } else if (t0.kind === SyntaxKind.BoltQuoteKeyword) { - return this.parseQuoteExpression(tokens); + result = this.parseQuoteExpression(tokens); } else if (t0.kind === SyntaxKind.BoltMatchKeyword) { - return this.parseMatchExpression(tokens); + result = this.parseMatchExpression(tokens); } else if (t0.kind === SyntaxKind.BoltIntegerLiteral || t0.kind === SyntaxKind.BoltStringLiteral) { - return this.parseConstantExpression(tokens); + result = this.parseConstantExpression(tokens); } else if (t0.kind === SyntaxKind.BoltIdentifier) { - return this.parseReferenceExpression(tokens); + result = this.parseReferenceExpression(tokens); } else { throw new ParseError(t0, [SyntaxKind.BoltStringLiteral, SyntaxKind.BoltIdentifier]); } - } - public parseExpression(tokens: BoltTokenStream): BoltExpression { - return this.parseCallOrPrimitiveExpression(tokens) + while (true) { + + let t2 = tokens.peek(); + const firstToken = t2; + + const path: BoltIdentifier[] = []; + + while (t2.kind === SyntaxKind.BoltDot) { + tokens.get(); + const t3 = tokens.get(); + assertToken(t3, SyntaxKind.BoltIdentifier); + path.push(t3 as BoltIdentifier); + t2 = tokens.peek(); + } + + if (path.length > 0) { + const node = createBoltMemberExpression(result, path); + setOrigNodeRange(node, firstToken, t2); + result = node; + } + + if (t2.kind !== SyntaxKind.BoltParenthesized) { + break; + } + + tokens.get(); + + const args: BoltExpression[] = [] + const innerTokens = createTokenStream(t2); + + while (true) { + const t3 = innerTokens.peek(); + if (t3.kind === SyntaxKind.EndOfFile) { + break; + } + args.push(this.parseExpression(innerTokens)) + const t4 = innerTokens.get(); + if (t4.kind === SyntaxKind.EndOfFile) { + break + } + if (t4.kind !== SyntaxKind.BoltComma) { + throw new ParseError(t4, [SyntaxKind.BoltComma]) + } + } + + const node = createBoltCallExpression(result, args, null) + setOrigNodeRange(node, result, t2); + result = node; + + } + + return result; + } public parseParameter(tokens: BoltTokenStream, index: number): BoltParameter { @@ -1312,39 +1367,6 @@ export class Parser { // return lhs //} - private parseCallOrPrimitiveExpression(tokens: BoltTokenStream): BoltExpression { - - const operator = this.parsePrimitiveExpression(tokens) - - const t2 = tokens.peek(); - if (t2.kind !== SyntaxKind.BoltParenthesized) { - return operator; - } - tokens.get(); - - const args: BoltExpression[] = [] - const innerTokens = createTokenStream(t2); - - while (true) { - const t3 = innerTokens.peek(); - if (t3.kind === SyntaxKind.EndOfFile) { - break; - } - args.push(this.parseExpression(innerTokens)) - const t4 = innerTokens.get(); - if (t4.kind === SyntaxKind.EndOfFile) { - break - } else if (t4.kind !== SyntaxKind.BoltComma){ - throw new ParseError(t4, [SyntaxKind.BoltComma]) - } - } - - const node = createBoltCallExpression(operator, args, null) - setOrigNodeRange(node, operator, t2); - return node; - - } - public parseSourceFile(tokens: BoltTokenStream): BoltSourceFile { const elements = this.parseSourceElements(tokens); const t1 = tokens.peek();