bolt/src/parser.ts

1711 lines
49 KiB
TypeScript
Raw Normal View History

2020-05-10 23:50:42 +02:00
2020-02-25 12:26:21 +01:00
import {
2020-05-10 15:56:34 +02:00
SyntaxKind,
2020-05-10 18:21:44 +02:00
kindToString,
BoltToken,
2020-05-10 15:56:34 +02:00
BoltIdentifier,
2020-05-10 18:21:44 +02:00
BoltConstantExpression,
BoltReferenceExpression,
BoltExpression,
BoltRecordDeclaration,
BoltStatement,
2020-05-10 18:54:57 +02:00
BoltDeclaration,
2020-05-10 19:05:37 +02:00
BoltParameter,
2020-05-10 18:54:57 +02:00
BoltSourceElement,
2020-05-10 15:56:34 +02:00
createBoltQualName,
BoltQualName,
BoltPattern,
createBoltBindPattern,
BoltImportDirective,
BoltTypeExpression,
createBoltReferenceTypeExpression,
2020-05-10 18:21:44 +02:00
createBoltConstantExpression,
2020-05-10 15:56:34 +02:00
createBoltReferenceExpression,
2020-05-10 18:21:44 +02:00
createBoltParameter,
BoltBindPattern,
createBoltRecordDeclaration,
createBoltRecordField,
createBoltImportDirective,
BoltModifiers,
2020-05-10 18:21:44 +02:00
BoltStringLiteral,
BoltImportSymbol,
2020-05-10 18:54:57 +02:00
BoltExpressionStatement,
createBoltExpressionStatement,
2020-05-10 19:05:37 +02:00
BoltVariableDeclaration,
BoltSyntax,
createBoltVariableDeclaration,
BoltReturnStatement,
createBoltReturnStatement,
BoltModule,
createBoltModule,
BoltTypeAliasDeclaration,
createBoltTypeAliasDeclaration,
2020-05-10 19:05:37 +02:00
BoltFunctionDeclaration,
createBoltFunctionDeclaration,
createBoltCallExpression,
2020-05-10 23:50:42 +02:00
BoltSymbol,
BoltTypeParameter,
createBoltTypeParameter,
BoltTraitDeclaration,
createBoltTraitDeclaration,
createBoltImplDeclaration,
BoltImplDeclaration,
BoltSourceFile,
BoltFunctionBodyElement,
createBoltSourceFile,
setParents,
BoltMatchExpression,
createBoltMatchArm,
BoltMatchArm,
createBoltMatchExpression,
createBoltExpressionPattern,
BoltFunctionTypeExpression,
BoltReferenceTypeExpression,
createBoltFunctionTypeExpression,
BoltRecordPattern,
createBoltRecordPattern,
createBoltRecordFieldPattern,
isBoltPunctuated,
Token,
createBoltQuoteExpression,
BoltQuoteExpression,
BoltBlockExpression,
createBoltBlockExpression,
isBoltOperatorLike,
BoltFunctionExpression,
createBoltFunctionExpression,
BoltMacroCall,
createBoltMacroCall,
2020-05-24 21:18:54 +02:00
createBoltMemberExpression,
BoltDeclarationLike,
2020-05-30 11:33:16 +02:00
BoltTraitOrImplElement,
2020-02-25 12:26:21 +01:00
} from "./ast"
import { parseForeignLanguage } from "./foreign"
import {
OperatorKind,
OperatorTable,
assertToken,
ParseError,
setOrigNodeRange,
createTokenStream,
Package,
} from "./common"
2020-05-30 11:33:16 +02:00
import { Stream, uniq, assert } from "./util"
2020-05-10 23:50:42 +02:00
export type BoltTokenStream = Stream<BoltToken>;
export function isModifierKeyword(kind: SyntaxKind) {
return kind === SyntaxKind.BoltPubKeyword
|| kind === SyntaxKind.BoltForeignKeyword;
}
function assertNoTokens(tokens: BoltTokenStream) {
const t0 = tokens.peek(1);
if (t0.kind !== SyntaxKind.EndOfFile) {
throw new ParseError(t0, [SyntaxKind.EndOfFile]);
}
}
const KIND_OPERATOR = [
2020-05-10 18:21:44 +02:00
SyntaxKind.BoltOperator,
SyntaxKind.BoltVBar,
SyntaxKind.BoltLtSign,
SyntaxKind.BoltGtSign,
];
const KIND_EXPRESSION_T0 = uniq([
SyntaxKind.BoltStringLiteral,
SyntaxKind.BoltIntegerLiteral,
SyntaxKind.BoltOperator,
2020-05-10 18:54:57 +02:00
SyntaxKind.BoltMatchKeyword,
SyntaxKind.BoltQuoteKeyword,
2020-05-10 18:54:57 +02:00
SyntaxKind.BoltYieldKeyword,
SyntaxKind.BoltIdentifier,
SyntaxKind.BoltParenthesized,
])
2020-05-10 18:21:44 +02:00
2020-05-10 23:50:42 +02:00
const KIND_STATEMENT_T0 = uniq([
2020-05-10 18:21:44 +02:00
SyntaxKind.BoltReturnKeyword,
...KIND_EXPRESSION_T0,
2020-05-10 23:50:42 +02:00
])
2020-05-10 18:21:44 +02:00
2020-05-10 18:54:57 +02:00
const KIND_DECLARATION_KEYWORD = [
SyntaxKind.BoltImplKeyword,
SyntaxKind.BoltTraitKeyword,
2020-05-10 18:54:57 +02:00
SyntaxKind.BoltFnKeyword,
SyntaxKind.BoltEnumKeyword,
SyntaxKind.BoltLetKeyword,
SyntaxKind.BoltModKeyword,
SyntaxKind.BoltStructKeyword,
SyntaxKind.BoltTypeKeyword,
2020-05-10 18:54:57 +02:00
]
2020-05-10 23:50:42 +02:00
const KIND_DECLARATION_T0 = uniq([
2020-05-10 18:54:57 +02:00
SyntaxKind.BoltPubKeyword,
SyntaxKind.BoltForeignKeyword,
...KIND_DECLARATION_KEYWORD,
2020-05-10 23:50:42 +02:00
])
2020-05-10 18:54:57 +02:00
2020-05-10 23:50:42 +02:00
const KIND_SOURCEELEMENT_T0 = uniq([
2020-05-10 18:54:57 +02:00
SyntaxKind.BoltModKeyword,
SyntaxKind.BoltImportKeyword,
2020-05-10 18:54:57 +02:00
...KIND_EXPRESSION_T0,
...KIND_STATEMENT_T0,
...KIND_DECLARATION_T0,
2020-05-10 23:50:42 +02:00
])
2020-05-10 18:54:57 +02:00
function isRightAssoc(kind: OperatorKind): boolean {
return kind === OperatorKind.InfixR;
}
2020-02-25 12:26:21 +01:00
export class Parser {
exprOperatorTable = new OperatorTable([
2020-03-03 14:53:54 +01:00
[
[OperatorKind.InfixL, 2, '&&'],
[OperatorKind.InfixL, 2, '||']
],
[
[OperatorKind.InfixL, 2, '<'],
[OperatorKind.InfixL, 2, '>'],
[OperatorKind.InfixL, 2, '<='],
[OperatorKind.InfixL, 2, '>=']
],
[
[OperatorKind.InfixL, 2, '>>'],
[OperatorKind.InfixL, 2, '<<']
],
[
[OperatorKind.InfixL, 2, '+'],
[OperatorKind.InfixL, 2, '-'],
],
[
[OperatorKind.InfixL, 2, '/'],
[OperatorKind.InfixL, 2, '*'],
[OperatorKind.InfixL, 2, '%'],
],
[
[OperatorKind.Prefix, 1, '!']
2020-03-03 14:53:54 +01:00
],
]);
typeOperatorTable = new OperatorTable([
[
[OperatorKind.InfixL, 2, '|'],
]
]);
2020-03-03 14:53:54 +01:00
2020-05-10 23:50:42 +02:00
public parse(kind: SyntaxKind, tokens: BoltTokenStream): BoltSyntax {
return (this as any)['parse' + kindToString(kind).substring('Bolt'.length)](tokens);
}
2020-05-27 17:17:27 +02:00
public parseModulePath(tokens: BoltTokenStream): BoltModulePath | null {
2020-05-27 17:17:27 +02:00
let firstToken = tokens.peek();;
let lastToken: Token;
let isAbsolute = false;
let elements = [];
2020-05-27 17:17:27 +02:00
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.BoltColonColon) {
isAbsolute = true;
tokens.get();
2020-05-27 17:17:27 +02:00
lastToken = t0;
}
if (tokens.peek(2).kind === SyntaxKind.BoltColonColon) {
while (true) {
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltIdentifier);
elements.push(t1 as BoltIdentifier)
const t2 = tokens.get();
if (tokens.peek(2).kind !== SyntaxKind.BoltColonColon) {
lastToken = t2;
break;
}
}
}
2020-05-27 17:17:27 +02:00
if (!isAbsolute && elements.length === 0) {
return null;
}
const result = createBoltModulePath(isAbsolute, elements);
2020-05-27 17:17:27 +02:00
setOrigNodeRange(result, firstToken, lastToken!);
return result;
}
2020-05-10 18:21:44 +02:00
public parseQualName(tokens: BoltTokenStream): BoltQualName {
2020-02-25 12:26:21 +01:00
const firstToken = tokens.peek();
let isAbsolute = false;
let modulePath = [];
let name;
if (tokens.peek().kind === SyntaxKind.BoltColonColon) {
isAbsolute = true;
tokens.get();
}
while (true) {
const t1 = tokens.get();
if (tokens.peek().kind === SyntaxKind.BoltColonColon) {
assertToken(t1, SyntaxKind.BoltIdentifier);
modulePath.push(t1 as BoltIdentifier);
tokens.get();
} else {
if (t1.kind === SyntaxKind.BoltParenthesized) {
const innerTokens = createTokenStream(t1);
const t2 = innerTokens.get();
if (!isBoltOperatorLike(t2)) {
throw new ParseError(t2, KIND_OPERATOR);
}
assertNoTokens(innerTokens);
name = t2;
} else if (t1.kind === SyntaxKind.BoltIdentifier) {
name = t1;
} else {
throw new ParseError(t1, [SyntaxKind.BoltParenthesized, SyntaxKind.BoltIdentifier]);
}
break;
}
2020-02-25 12:26:21 +01:00
}
const node = createBoltQualName(isAbsolute, modulePath, name as BoltIdentifier, null);
setOrigNodeRange(node, firstToken, name);
2020-05-10 18:21:44 +02:00
return node;
}
public parseBindPattern(tokens: BoltTokenStream): BoltBindPattern {
const t0 = tokens.get();
assertToken(t0, SyntaxKind.BoltIdentifier);
2020-05-10 19:05:37 +02:00
const node = createBoltBindPattern(t0 as BoltIdentifier);
2020-05-10 18:21:44 +02:00
setOrigNodeRange(node, t0, t0);
return node;
2020-02-25 12:26:21 +01:00
}
public parseRecordPattern(tokens: BoltTokenStream): BoltRecordPattern {
const name = this.parseTypeExpression(tokens);
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltBraced);
const innerTokens = createTokenStream(t1);
const members = [];
while (true) {
let t0 = innerTokens.get();
const firstToken = t0;
if (t0.kind === SyntaxKind.EndOfFile) {
break;
}
let isRest = false;
let name = null;
let pattern = null;
if (t0.kind === SyntaxKind.BoltDotDot) {
isRest = true;
t0 = innerTokens.peek();
}
if (t0.kind === SyntaxKind.BoltIdentifier) {
name = t0;
t0 = innerTokens.peek();
} else if (!isRest) {
throw new ParseError(t0, [SyntaxKind.BoltIdentifier]);
}
if (t0.kind === SyntaxKind.BoltEqSign) {
pattern = this.parsePattern(innerTokens);
}
let member = createBoltRecordFieldPattern(isRest, name, pattern);
setOrigNodeRange(member, firstToken, t0);
members.push(member);
if (t0.kind === SyntaxKind.EndOfFile) {
break;
}
assertToken(t0, SyntaxKind.BoltComma);
}
const result = createBoltRecordPattern(name, members);
setOrigNodeRange(result, name, t1);
return result;
}
2020-05-10 18:21:44 +02:00
public parsePattern(tokens: BoltTokenStream): BoltPattern {
2020-02-25 12:26:21 +01:00
const t0 = tokens.peek(1);
const t1 = tokens.peek(2);
if (t0.kind === SyntaxKind.BoltIdentifier && t1.kind === SyntaxKind.BoltBraced) {
return this.parseRecordPattern(tokens);
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
2020-05-10 18:21:44 +02:00
return this.parseBindPattern(tokens);
} else if (t0.kind === SyntaxKind.BoltOperator && t0.text === '^') {
tokens.get();
const refExpr = this.parseReferenceExpression(tokens);
const result = createBoltExpressionPattern(refExpr);
setOrigNodeRange(result, t0, refExpr);
return result;
} else if (KIND_EXPRESSION_T0.indexOf(t0.kind) !== -1) {
const expr = this.parseExpression(tokens);
const result = createBoltExpressionPattern(expr);
setOrigNodeRange(result, expr, expr);
return result;
2020-02-25 12:26:21 +01:00
} else {
2020-05-10 15:56:34 +02:00
throw new ParseError(t0, [SyntaxKind.BoltIdentifier])
2020-02-25 12:26:21 +01:00
}
}
public parseImportDirective(tokens: BoltTokenStream): BoltImportDirective {
let modifiers = 0;
if (tokens.peek().kind === SyntaxKind.BoltPubKeyword) {
tokens.get();
modifiers |= BoltModifiers.IsPublic;
}
const t0 = tokens.get();
2020-05-10 18:21:44 +02:00
assertToken(t0, SyntaxKind.BoltImportKeyword);
2020-05-10 18:21:44 +02:00
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltStringLiteral);
const symbols = null;
const t2 = tokens.peek();
if (t2.kind === SyntaxKind.BoltParenthesized) {
// TODO implement grammar and parsing logic for symbols
}
2020-05-10 18:21:44 +02:00
const node = createBoltImportDirective(modifiers, t1 as BoltStringLiteral, symbols);
2020-05-10 18:21:44 +02:00
setOrigNodeRange(node, t0, t1);
return node;
}
public parseFunctionTypeExpression(tokens: BoltTokenStream): BoltFunctionTypeExpression {
const t0 = tokens.get();
assertToken(t0, SyntaxKind.BoltFnKeyword);
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltParenthesized);
const innerTokens = createTokenStream(t1);
let i = 0;
const params: BoltParameter[] = [];
while (true) {
const t2 = innerTokens.peek();
if (t2.kind === SyntaxKind.EndOfFile) {
break;
}
const param = this.parseParameter(innerTokens, i++)
params.push(param);
const t3 = innerTokens.peek()
if (t3.kind === SyntaxKind.EndOfFile) {
break;
}
const t4 = innerTokens.get();
assertToken(t4, SyntaxKind.BoltComma);
}
const t3 = tokens.peek();
let returnType = null;
if (t3.kind === SyntaxKind.BoltRArrow) {
tokens.get();
returnType = this.parseTypeExpression(tokens);
}
const result = createBoltFunctionTypeExpression(params, returnType)
setOrigNodeRange(result, t0, returnType !== null ? returnType : t1);
return result;
}
public parseReferenceTypeExpression(tokens: BoltTokenStream): BoltReferenceTypeExpression {
2020-05-10 18:21:44 +02:00
2020-05-27 17:17:27 +02:00
const firstToken = tokens.peek();
let isAbsolute = false;
let modulePath = [];
let name;
if (tokens.peek().kind === SyntaxKind.BoltColonColon) {
isAbsolute = true;
tokens.get();
2020-05-27 17:17:27 +02:00
}
while (true) {
const t1 = tokens.get();
if (tokens.peek().kind === SyntaxKind.BoltColonColon) {
assertToken(t1, SyntaxKind.BoltIdentifier);
modulePath.push(t1 as BoltIdentifier);
tokens.get();
} else {
assertToken(t1, SyntaxKind.BoltIdentifier);
name = t1 as BoltIdentifier;
break;
}
}
2020-05-10 18:21:44 +02:00
let lastToken: BoltToken = name;
let typeArgs: BoltTypeExpression[] | null = null;
2020-05-10 18:21:44 +02:00
2020-05-27 17:17:27 +02:00
if (tokens.peek().kind === SyntaxKind.BoltLtSign) {
typeArgs = [];
2020-05-10 18:21:44 +02:00
tokens.get();
let first = true;
while (true) {
const t2 = tokens.peek();
if (t2.kind === SyntaxKind.BoltGtSign) {
break;
}
if (first) {
first = false;
} else {
assertToken(t2, SyntaxKind.BoltComma);
tokens.get();
}
typeArgs!.push(this.parseTypeExpression(tokens));
2020-05-10 18:21:44 +02:00
}
const t4 = tokens.get();
assertToken(t4, SyntaxKind.BoltGtSign);
lastToken = t4;
2020-05-10 18:21:44 +02:00
}
const qualName = createBoltQualName(isAbsolute, modulePath, name);
setOrigNodeRange(qualName, firstToken, modulePath.length > 0 ? modulePath[modulePath.length-1] : firstToken)
const node = createBoltReferenceTypeExpression(qualName, typeArgs);
2020-05-27 17:17:27 +02:00
setOrigNodeRange(node, firstToken, lastToken);
2020-05-10 18:21:44 +02:00
return node;
}
private parsePrimTypeExpression(tokens: BoltTokenStream): BoltTypeExpression {
2020-02-25 12:26:21 +01:00
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.BoltFnKeyword) {
return this.parseFunctionTypeExpression(tokens);
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
return this.parseReferenceTypeExpression(tokens);
2020-02-25 12:26:21 +01:00
} else {
2020-05-10 15:56:34 +02:00
throw new ParseError(t0, [SyntaxKind.BoltIdentifier]);
2020-02-25 12:26:21 +01:00
}
}
2020-05-27 17:17:27 +02:00
//private parseTypeExpressionOperators(tokens: BoltTokenStream, lhs: BoltTypeExpression, minPrecedence: number): BoltTypeExpression {
// while (true) {
// const t0 = tokens.peek();
// if (!isBoltOperatorLike(t0)) {
// break;
// }
// let desc0 = this.typeOperatorTable.lookup(emitNode(t0));
// if (desc0 === null || desc0.arity !== 2 || desc0.precedence < minPrecedence) {
// break;
// }
// tokens.get();
// let rhs = this.parsePrimTypeExpression(tokens);
// while (true) {
// const t1 = tokens.peek()
// if (!isBoltOperatorLike(t1.kind)) {
// break;
// }
// const desc1 = this.typeOperatorTable.lookup(emitNode(t1))
// if (desc1 === null || desc1.arity !== 2 || desc1.precedence < desc0.precedence || !isRightAssoc(desc1.kind)) {
// break;
// }
// rhs = this.parseTypeExpressionOperators(tokens, rhs, desc1.precedence);
// }
// const name = emitNode(t0);
// switch (name) {
// case '|':
// return createBoltFunctionTypeExpression();
// )
// }
// lhs = createBoltReferenceTypeExpression(null, t0, [lhs, rhs]);
// setOrigNodeRange(lhs, t0, rhs);
// }
// return lhs
//}
public parseTypeExpression(tokens: BoltTokenStream) {
2020-05-27 17:17:27 +02:00
//const lhs = this.parsePrimTypeExpression(tokens);
//return this.parseTypeExpressionOperators(tokens, lhs, 0);
return this.parsePrimTypeExpression(tokens);
}
2020-05-10 18:21:44 +02:00
public parseConstantExpression(tokens: BoltTokenStream): BoltConstantExpression {
const t0 = tokens.get();
let value: boolean | string | bigint;
2020-05-10 15:56:34 +02:00
if (t0.kind === SyntaxKind.BoltStringLiteral) {
2020-05-10 18:21:44 +02:00
value = t0.value;
2020-05-10 15:56:34 +02:00
} else if (t0.kind === SyntaxKind.BoltIntegerLiteral) {
2020-05-10 18:21:44 +02:00
value = t0.value;
} else {
throw new ParseError(t0, [SyntaxKind.BoltStringLiteral, SyntaxKind.BoltIntegerLiteral]);
}
const node = createBoltConstantExpression(value);
setOrigNodeRange(node, t0, t0);
return node;
}
public parseFunctionExpression(tokens: BoltTokenStream): BoltFunctionExpression {
const t0 = tokens.get();
assertToken(t0, SyntaxKind.BoltVBar);
let i = 0;
const params: BoltParameter[] = [];
while (true) {
const t1 = tokens.peek();
if (t1.kind === SyntaxKind.BoltVBar) {
tokens.get();
break;
}
const param = this.parseParameter(tokens, i++);
params.push(param);
const t2 = tokens.peek();
if (t2.kind === SyntaxKind.BoltVBar) {
tokens.get();
break;
}
const t3 = tokens.get();
assertToken(t3, SyntaxKind.BoltComma);
}
let returnType = null;
let t4 = tokens.get();
if (t4.kind === SyntaxKind.BoltRArrow) {
returnType = this.parseTypeExpression(tokens);
t4 = tokens.get();
}
assertToken(t4, SyntaxKind.BoltBraced);
const innerTokens = createTokenStream(t4);
const body = this.parseFunctionBodyElements(innerTokens);
const result = createBoltFunctionExpression(params, returnType, body);
setOrigNodeRange(result, t0, t4);
return result;
}
2020-05-10 18:21:44 +02:00
public parseReferenceExpression(tokens: BoltTokenStream): BoltReferenceExpression {
const firstToken = tokens.peek();
const name = this.parseQualName(tokens);
const node = createBoltReferenceExpression(name);
setOrigNodeRange(node, firstToken, name);
2020-05-10 18:21:44 +02:00
return node;
}
public parseMatchExpression(tokens: BoltTokenStream): BoltMatchExpression {
const t0 = tokens.get();
assertToken(t0, SyntaxKind.BoltMatchKeyword);
const expr = this.parseExpression(tokens);
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltBraced);
const innerTokens = createTokenStream(t1);
const matchArms: BoltMatchArm[] = [];
while (true) {
const t2 = innerTokens.peek();
if (t2.kind === SyntaxKind.EndOfFile) {
break;
}
const pattern = this.parsePattern(innerTokens);
const t3 = innerTokens.get();
assertToken(t3, SyntaxKind.BoltRArrowAlt);
const expression = this.parseExpression(innerTokens);
const arm = createBoltMatchArm(pattern, expression);
setOrigNodeRange(arm, pattern, expression);
matchArms.push(arm);
const t4 = tokens.peek();
if (t4.kind === SyntaxKind.EndOfFile) {
break;
}
assertToken(t4, SyntaxKind.BoltComma);
tokens.get();
}
const result = createBoltMatchExpression(expr, matchArms);
setOrigNodeRange(result, t0, t1);
return result;
}
public parseQuoteExpression(tokens: BoltTokenStream): BoltQuoteExpression {
const t0 = tokens.get();
assertToken(t0, SyntaxKind.BoltQuoteKeyword);
let t1 = tokens.get();
let target = "Bolt";
if (t1.kind === SyntaxKind.BoltStringLiteral) {
target = t1.value;
t1 = tokens.get();
}
if (!isBoltPunctuated(t1)) {
throw new ParseError(t1, [SyntaxKind.BoltBraced, SyntaxKind.BoltParenthesized, SyntaxKind.BoltBracketed]);
}
let scanner;
switch (target) {
case "Bolt":
scanner = new Scanner(t1.span!.file, t1.text, t1.span!.start.clone());
break;
case "JS":
scanner = new JSScanner(t1.span!.file, t1.text, t1.span!.start.clone());
break;
default:
throw new Error(`Unrecognised language.`);
}
const scanned: Token[] = [];
while (true) {
const t2 = scanner.scan();
if (t2.kind === SyntaxKind.EndOfFile) {
break;
}
scanned.push(t2);
}
const result = createBoltQuoteExpression(scanned as Token[]);
setOrigNodeRange(result, t0, t1);
return result;
}
public parseBlockExpression(tokens: BoltTokenStream): BoltBlockExpression {
const t0 = tokens.get();
const innerTokens = createTokenStream(t0);
const elements = this.parseFunctionBodyElements(innerTokens)
const result = createBoltBlockExpression(elements);
setOrigNodeRange(result, t0, t0);
return result;
}
2020-05-24 21:18:54 +02:00
private parseExpression(tokens: BoltTokenStream): BoltExpression {
2020-05-10 18:21:44 +02:00
const t0 = tokens.peek();
2020-05-24 21:18:54 +02:00
let result;
if (t0.kind === SyntaxKind.BoltVBar) {
2020-05-24 21:18:54 +02:00
result = this.parseFunctionExpression(tokens);
} else if (t0.kind === SyntaxKind.BoltBraced) {
2020-05-24 21:18:54 +02:00
result = this.parseBlockExpression(tokens);
} else if (t0.kind === SyntaxKind.BoltQuoteKeyword) {
2020-05-24 21:18:54 +02:00
result = this.parseQuoteExpression(tokens);
} else if (t0.kind === SyntaxKind.BoltMatchKeyword) {
2020-05-24 21:18:54 +02:00
result = this.parseMatchExpression(tokens);
} else if (t0.kind === SyntaxKind.BoltIntegerLiteral || t0.kind === SyntaxKind.BoltStringLiteral) {
2020-05-24 21:18:54 +02:00
result = this.parseConstantExpression(tokens);
2020-05-10 15:56:34 +02:00
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
2020-05-24 21:18:54 +02:00
result = this.parseReferenceExpression(tokens);
2020-02-25 12:26:21 +01:00
} else {
2020-05-10 15:56:34 +02:00
throw new ParseError(t0, [SyntaxKind.BoltStringLiteral, SyntaxKind.BoltIdentifier]);
2020-02-25 12:26:21 +01:00
}
2020-05-24 21:18:54 +02:00
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;
2020-02-25 17:55:17 +01:00
}
public parseParameter(tokens: BoltTokenStream, index: number): BoltParameter {
2020-02-25 12:26:21 +01:00
let defaultValue = null;
let typeDecl = null;
const pattern = this.parsePattern(tokens)
let t0 = tokens.peek();
2020-05-10 18:21:44 +02:00
let endNode: BoltSyntax = pattern;
2020-05-10 15:56:34 +02:00
if (t0.kind === SyntaxKind.BoltColon) {
2020-02-25 12:26:21 +01:00
tokens.get();
typeDecl = this.parseTypeExpression(tokens);
2020-05-10 18:21:44 +02:00
endNode = typeDecl;
t0 = tokens.peek();
}
2020-05-10 15:56:34 +02:00
if (t0.kind === SyntaxKind.BoltEqSign) {
2020-02-25 12:26:21 +01:00
tokens.get();
2020-05-10 18:21:44 +02:00
defaultValue = this.parseExpression(tokens);
endNode = defaultValue;
2020-02-25 12:26:21 +01:00
}
const node = createBoltParameter(index, pattern, typeDecl, defaultValue)
2020-05-10 18:21:44 +02:00
setOrigNodeRange(node, pattern, endNode);
return node;
2020-02-25 12:26:21 +01:00
}
2020-05-10 18:21:44 +02:00
public parseVariableDeclaration(tokens: BoltTokenStream): BoltVariableDeclaration {
2020-02-25 12:26:21 +01:00
2020-05-10 18:21:44 +02:00
let modifiers = 0;
let typeDecl = null;
let value = null;
2020-05-10 18:21:44 +02:00
const t0 = tokens.get();
assertToken(t0, SyntaxKind.BoltLetKeyword);
2020-02-25 17:55:17 +01:00
2020-05-10 18:21:44 +02:00
const t1 = tokens.peek();
if (t1.kind === SyntaxKind.BoltMutKeyword) {
tokens.get();
2020-05-27 17:17:27 +02:00
modifiers |= BoltModifiers.IsMutable;
}
const bindings = this.parsePattern(tokens)
2020-05-10 18:21:44 +02:00
let t2 = tokens.peek();
let lastNode: BoltSyntax = bindings;
if (t2.kind === SyntaxKind.BoltColon) {
tokens.get();
lastNode = typeDecl = this.parseTypeExpression(tokens);
2020-05-10 18:21:44 +02:00
t2 = tokens.peek();
}
2020-05-10 15:56:34 +02:00
if (t2.kind === SyntaxKind.BoltEqSign) {
tokens.get();
2020-05-10 18:21:44 +02:00
lastNode = value = this.parseExpression(tokens);
}
2020-05-10 18:21:44 +02:00
const node = createBoltVariableDeclaration(modifiers, bindings, typeDecl, value)
setOrigNodeRange(node, t0, lastNode);
return node;
2020-02-25 12:26:21 +01:00
}
2020-05-10 18:21:44 +02:00
public parseReturnStatement(tokens: BoltTokenStream): BoltReturnStatement {
2020-02-25 12:26:21 +01:00
const t0 = tokens.get();
2020-05-10 18:21:44 +02:00
assertToken(t0, SyntaxKind.BoltReturnKeyword);
2020-02-25 12:26:21 +01:00
let expr = null;
const t1 = tokens.peek();
if (t1.kind !== SyntaxKind.EndOfFile) {
2020-05-10 18:21:44 +02:00
expr = this.parseExpression(tokens)
2020-02-25 12:26:21 +01:00
}
2020-05-10 18:21:44 +02:00
const node = createBoltReturnStatement(expr);
setOrigNodeRange(node, t0, expr !== null ? expr : t0);
return node;
2020-02-25 12:26:21 +01:00
}
2020-05-10 19:05:37 +02:00
protected isUnaryOperator(name: string) {
// TODO
return false;
}
2020-05-10 18:21:44 +02:00
protected lookaheadHasExpression(tokens: BoltTokenStream, i = 1): boolean {
const t0 = tokens.peek(i);
if (t0.kind === SyntaxKind.BoltParenthesized) {
return this.lookaheadHasExpression(tokens, i+1);
}
return t0.kind === SyntaxKind.BoltIdentifier
|| t0.kind === SyntaxKind.BoltStringLiteral
|| t0.kind === SyntaxKind.BoltIntegerLiteral
|| (t0.kind === SyntaxKind.BoltOperator && this.isUnaryOperator(t0.text));
}
2020-05-10 18:54:57 +02:00
public parseExpressionStatement(tokens: BoltTokenStream): BoltExpressionStatement {
const expression = this.parseExpression(tokens)
const node = createBoltExpressionStatement(expression)
setOrigNodeRange(node, expression, expression);
return node;
}
2020-05-10 18:21:44 +02:00
public parseStatement(tokens: BoltTokenStream): BoltStatement {
if (this.lookaheadIsMacroCall(tokens)) {
return this.parseMacroCall(tokens);
}
2020-05-10 18:21:44 +02:00
const t0 = tokens.peek();
if (KIND_EXPRESSION_T0.indexOf(t0.kind) !== -1) {
return this.parseExpressionStatement(tokens);
} else if (t0.kind === SyntaxKind.BoltReturnKeyword) {
2020-05-10 18:21:44 +02:00
return this.parseReturnStatement(tokens);
} else if (t0.kind === SyntaxKind.BoltLoopKeyword) {
return this.parseLoopStatement(tokens);
} else {
throw new ParseError(t0, KIND_STATEMENT_T0);
2020-05-10 18:21:44 +02:00
}
}
public parseGenericTypeParameter(tokens: BoltTokenStream): BoltTypeParameter {
const t0 = tokens.peek();
tokens.get();
assertToken(t0, SyntaxKind.BoltIdentifier);
let typeBound = null;
const t1 = tokens.peek();
if (t1.kind === SyntaxKind.BoltColon) {
tokens.get();
typeBound = this.parseTypeExpression(tokens);
}
const node = createBoltTypeParameter(0, t0 as BoltIdentifier, typeBound, null)
setOrigNodeRange(node, t0, t0);
return node;
}
private parseGenericTypeParameters(tokens: BoltTokenStream): BoltTypeParameter[] {
let typeParams: BoltTypeParameter[] = [];
while (true) {
let t1 = tokens.peek();
if (t1.kind !== SyntaxKind.BoltIdentifier) {
break;
}
typeParams.push(this.parseGenericTypeParameter(tokens));
const t2 = tokens.peek();
if (t2.kind !== SyntaxKind.BoltComma) {
break;
}
tokens.get();
}
return typeParams;
}
2020-05-10 18:21:44 +02:00
public parseRecordDeclaration(tokens: BoltTokenStream): BoltRecordDeclaration {
2020-05-10 18:21:44 +02:00
let modifiers = 0;
let typeParams = null;
2020-05-10 18:21:44 +02:00
let t0 = tokens.get();
const firstToken = t0;
if (t0.kind === SyntaxKind.BoltPubKeyword) {
modifiers |= BoltModifiers.IsPublic;
2020-05-10 18:21:44 +02:00
t0 = tokens.get();
}
assertToken(t0, SyntaxKind.BoltStructKeyword);
2020-05-10 19:05:37 +02:00
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltIdentifier);
const name = t1 as BoltIdentifier;
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) {
tokens.get();
typeParams = this.parseGenericTypeParameters(tokens);
const t3 = tokens.get();
assertToken(t3, SyntaxKind.BoltGtSign);
t2 = tokens.peek();
}
let members = null;
if (t2.kind !== SyntaxKind.BoltSemi) {
if (t2.kind !== SyntaxKind.BoltBraced) {
throw new ParseError(t2, [SyntaxKind.BoltBraced])
2020-05-10 18:21:44 +02:00
}
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);
}
2020-05-10 18:21:44 +02:00
}
const node = createBoltRecordDeclaration(modifiers, name, typeParams, members);
2020-05-10 18:21:44 +02:00
setOrigNodeRange(node, firstToken, t2);
return node;
}
2020-05-10 18:21:44 +02:00
public parseStatements(tokens: BoltTokenStream): BoltStatement[] {
const statements: BoltStatement[] = [];
while (true) {
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.EndOfFile) {
2020-05-10 18:21:44 +02:00
break;
}
if (t0.kind === SyntaxKind.BoltSemi) {
tokens.get();
continue;
}
2020-05-10 18:21:44 +02:00
const statement = this.parseStatement(tokens);
statements.push(statement);
}
return statements;
2020-02-25 12:26:21 +01:00
}
2020-05-10 18:21:44 +02:00
public parseModuleDeclaration(tokens: BoltTokenStream): BoltModule {
2020-05-10 18:21:44 +02:00
let modifiers = 0;
let pathElements = [];
2020-05-10 18:21:44 +02:00
let t0 = tokens.get();
const firstToken = t0;
if (t0.kind === SyntaxKind.BoltPubKeyword) {
modifiers |= BoltModifiers.IsPublic;
t0 = tokens.get();
}
if (t0.kind !== SyntaxKind.BoltModKeyword) {
2020-05-10 18:21:44 +02:00
throw new ParseError(t0, [SyntaxKind.BoltModKeyword])
}
while (true) {
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltIdentifier)
pathElements.push(t1 as BoltIdentifier)
const t2 = tokens.peek();
if (t2.kind !== SyntaxKind.BoltColonColon) {
break;
}
tokens.get();
}
const t1 = tokens.get();
2020-05-10 15:56:34 +02:00
if (t1.kind !== SyntaxKind.BoltBraced) {
throw new ParseError(t1, [SyntaxKind.BoltBraced])
}
const elements = this.parseSourceElements(createTokenStream(t1));
const node = createBoltModule(modifiers, pathElements, elements);
2020-05-10 18:21:44 +02:00
setOrigNodeRange(node, firstToken, t1);
return node;
}
2020-02-25 12:26:21 +01:00
public parseTypeAliasDeclaration(tokens: BoltTokenStream): BoltTypeAliasDeclaration {
2020-05-10 18:21:44 +02:00
let modifiers = 0;
let typeParams = null;
2020-03-03 14:53:54 +01:00
let t0 = tokens.get();
2020-05-10 19:05:37 +02:00
const firstToken = t0;
2020-05-10 18:21:44 +02:00
if (t0.kind === SyntaxKind.BoltPubKeyword) {
modifiers |= BoltModifiers.IsPublic;
t0 = tokens.get();
2020-03-03 14:53:54 +01:00
}
assertToken(t0, SyntaxKind.BoltTypeKeyword);
2020-03-03 14:53:54 +01:00
const name = tokens.get();
2020-05-10 15:56:34 +02:00
if (name.kind !== SyntaxKind.BoltIdentifier) {
throw new ParseError(name, [SyntaxKind.BoltIdentifier])
2020-03-03 14:53:54 +01:00
}
const t2 = tokens.peek();
if (t2.kind === SyntaxKind.BoltLtSign) {
tokens.get();
typeParams = this.parseGenericTypeParameters(tokens);
const t3 = tokens.get();
assertToken(t3, SyntaxKind.BoltGtSign);
}
const t3 = tokens.get();
assertToken(t3, SyntaxKind.BoltEqSign);
const typeExpr = this.parseTypeExpression(tokens);
const node = createBoltTypeAliasDeclaration(modifiers, name, typeParams, typeExpr)
setOrigNodeRange(node, firstToken, typeExpr);
2020-05-10 18:21:44 +02:00
return node;
2020-03-03 14:53:54 +01:00
}
2020-05-10 19:05:37 +02:00
private parseFunctionDeclaration(tokens: BoltTokenStream): BoltFunctionDeclaration {
2020-02-25 12:26:21 +01:00
2020-02-25 17:55:17 +01:00
let target = "Bolt";
2020-05-10 18:21:44 +02:00
let modifiers = 0;
2020-02-25 17:55:17 +01:00
2020-05-10 18:21:44 +02:00
let k0 = tokens.peek();
const firstToken = k0;
2020-05-10 23:50:42 +02:00
if (k0.kind === SyntaxKind.BoltPubKeyword) {
tokens.get();
modifiers |= BoltModifiers.IsPublic;
2020-05-10 18:21:44 +02:00
k0 = tokens.peek();
2020-02-25 17:55:17 +01:00
}
2020-05-10 18:21:44 +02:00
if (k0.kind === SyntaxKind.BoltForeignKeyword) {
tokens.get();
2020-02-25 17:55:17 +01:00
const l1 = tokens.get();
2020-05-10 15:56:34 +02:00
if (l1.kind !== SyntaxKind.BoltStringLiteral) {
throw new ParseError(l1, [SyntaxKind.BoltStringLiteral])
2020-02-25 17:55:17 +01:00
}
target = l1.value;
2020-05-10 18:21:44 +02:00
k0 = tokens.peek();
2020-02-25 17:55:17 +01:00
}
2020-05-10 18:21:44 +02:00
if (k0.kind !== SyntaxKind.BoltFnKeyword) {
throw new ParseError(k0, [SyntaxKind.BoltFnKeyword])
2020-02-25 17:55:17 +01:00
}
2020-02-25 12:26:21 +01:00
2020-05-10 18:21:44 +02:00
tokens.get();
2020-05-10 23:50:42 +02:00
let name: BoltSymbol;
2020-02-25 12:26:21 +01:00
let returnType = null;
2020-05-10 23:50:42 +02:00
let body: any = null; // FIXME type-checking should not be disabled
2020-05-10 18:21:44 +02:00
let params: BoltParameter[] = [];
let typeParams = null;
2020-02-25 12:26:21 +01:00
2020-02-25 17:55:17 +01:00
// Parse parameters
2020-05-10 18:21:44 +02:00
let i = 0;
2020-02-25 12:26:21 +01:00
const t0 = tokens.peek(1);
const t1 = tokens.peek(2);
2020-05-10 18:21:44 +02:00
const isParamLike = (token: BoltToken) =>
2020-05-10 15:56:34 +02:00
token.kind === SyntaxKind.BoltIdentifier || token.kind === SyntaxKind.BoltParenthesized;
2020-02-25 12:26:21 +01:00
2020-05-10 18:21:44 +02:00
const parseParamLike = (tokens: BoltTokenStream) => {
2020-02-25 12:26:21 +01:00
const t0 = tokens.peek(1);
2020-05-10 15:56:34 +02:00
if (t0.kind === SyntaxKind.BoltIdentifier) {
2020-02-25 12:26:21 +01:00
tokens.get();
2020-05-10 18:21:44 +02:00
const bindings = createBoltBindPattern(t0 as BoltIdentifier);
setOrigNodeRange(bindings, t0, t0);
const param = createBoltParameter(i++, bindings, null, null);
setOrigNodeRange(param, t0, t0);
return param;
2020-05-10 15:56:34 +02:00
} else if (t0.kind === SyntaxKind.BoltParenthesized) {
2020-02-25 12:26:21 +01:00
tokens.get();
2020-05-10 18:21:44 +02:00
const innerTokens = createTokenStream(t0);
const param = this.parseParameter(innerTokens, i++)
assertNoTokens(innerTokens);
2020-02-25 12:26:21 +01:00
return param
} else {
2020-05-10 15:56:34 +02:00
throw new ParseError(t0, [SyntaxKind.BoltIdentifier, SyntaxKind.BoltParenthesized])
2020-02-25 12:26:21 +01:00
}
}
2020-05-10 15:56:34 +02:00
if (t0.kind === SyntaxKind.BoltOperator) {
2020-02-25 12:26:21 +01:00
2020-05-10 23:50:42 +02:00
name = t0;
2020-02-25 12:26:21 +01:00
tokens.get();
params.push(parseParamLike(tokens))
2020-05-10 15:56:34 +02:00
} else if (isParamLike(t0) && t1.kind == SyntaxKind.BoltOperator) {
2020-02-25 12:26:21 +01:00
params.push(parseParamLike(tokens));
2020-05-10 23:50:42 +02:00
name = t1;
2020-02-25 12:26:21 +01:00
while (true) {
const t2 = tokens.peek();
2020-05-10 15:56:34 +02:00
if (t2.kind !== SyntaxKind.BoltOperator) {
2020-02-25 12:26:21 +01:00
break;
}
if (t2.text !== t1.text) {
throw new Error(`Operators have to match when defining or declaring an n-ary operator.`);
}
tokens.get();
params.push(parseParamLike(tokens))
}
2020-05-10 15:56:34 +02:00
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
2020-02-25 12:26:21 +01:00
2020-05-10 23:50:42 +02:00
name = t0;
tokens.get();
2020-02-25 12:26:21 +01:00
const t2 = tokens.get();
2020-05-10 15:56:34 +02:00
if (t2.kind === SyntaxKind.BoltParenthesized) {
2020-05-10 18:21:44 +02:00
const innerTokens = createTokenStream(t2);
2020-02-25 12:26:21 +01:00
while (true) {
const t3 = innerTokens.peek();
if (t3.kind === SyntaxKind.EndOfFile) {
2020-02-25 12:26:21 +01:00
break;
}
2020-05-10 18:21:44 +02:00
params.push(this.parseParameter(innerTokens, i++))
2020-02-25 12:26:21 +01:00
const t4 = innerTokens.get();
2020-05-10 15:56:34 +02:00
if (t4.kind === SyntaxKind.BoltComma) {
2020-02-25 12:26:21 +01:00
continue;
} else if (t4.kind === SyntaxKind.EndOfFile) {
2020-02-25 12:26:21 +01:00
break;
} else {
throw new ParseError(t4, [SyntaxKind.BoltComma, SyntaxKind.EndOfFile])
2020-02-25 12:26:21 +01:00
}
}
}
} else {
2020-05-10 15:56:34 +02:00
throw new ParseError(t0, [SyntaxKind.BoltIdentifier, SyntaxKind.BoltOperator, SyntaxKind.BoltParenthesized])
2020-02-25 12:26:21 +01:00
}
// Parse return type
const t2 = tokens.peek();
2020-05-10 15:56:34 +02:00
if (t2.kind === SyntaxKind.BoltRArrow) {
2020-02-25 12:26:21 +01:00
tokens.get();
returnType = this.parseTypeExpression(tokens);
2020-02-25 12:26:21 +01:00
}
// Parse second possible version of generic type parameters
const t4 = tokens.peek();
if (t4.kind === SyntaxKind.BoltWhereKeyword) {
tokens.get();
typeParams = this.parseGenericTypeParameters(tokens);
}
2020-02-25 12:26:21 +01:00
// Parse function body
const t3 = tokens.peek();
2020-05-10 15:56:34 +02:00
if (t3.kind === SyntaxKind.BoltBraced) {
2020-02-25 17:55:17 +01:00
tokens.get();
switch (target) {
case "Bolt":
body = this.parseStatements(createTokenStream(t3));
2020-02-25 17:55:17 +01:00
break;
default:
body = parseForeignLanguage(target, t3.text, t3.span!.file, t3.span!.start);
break;
2020-02-25 17:55:17 +01:00
}
} else if (t3.kind !== SyntaxKind.BoltSemi) {
const expected = [ SyntaxKind.BoltBraced, SyntaxKind.BoltSemi ];
if (returnType === null) {
expected.push(SyntaxKind.BoltRArrow);
}
throw new ParseError(t3, expected);
2020-02-25 12:26:21 +01:00
}
const result = createBoltFunctionDeclaration(
2020-05-10 18:21:44 +02:00
modifiers,
2020-05-10 19:05:37 +02:00
target,
2020-05-10 18:21:44 +02:00
name,
params,
returnType,
typeParams,
2020-05-10 18:21:44 +02:00
body
);
setOrigNodeRange(result, firstToken, t3);
return result;
}
2020-02-25 12:26:21 +01:00
public parseTraitDeclaration(tokens: BoltTokenStream): BoltTraitDeclaration {
2020-05-30 11:33:16 +02:00
let modifiers = 0;
2020-05-30 11:33:16 +02:00
let typeParams = null;
let name;
let typeBoundExpr = null;
let elements = null;
// Parse the 'pub' keyword, if present
let t0 = tokens.get();
const firstToken = t0;
if (t0.kind === SyntaxKind.BoltPubKeyword) {
modifiers |= BoltModifiers.IsPublic;
t0 = tokens.get();
}
2020-05-30 11:33:16 +02:00
// By now, we should encounter the 'trait' keyword'
assertToken(t0, SyntaxKind.BoltTraitKeyword);
2020-05-30 11:33:16 +02:00
// Type parameters are introduced by '<' and end with '>'
const t2 = tokens.peek();
if (t2.kind === SyntaxKind.BoltLtSign) {
tokens.get();
typeParams = this.parseGenericTypeParameters(tokens);
const t2 = tokens.get();
assertToken(t2, SyntaxKind.BoltGtSign);
}
// A trait must be named by an identifier
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltIdentifier);
2020-05-30 11:33:16 +02:00
name = t1 as BoltIdentifier;
let lastToken = t1;
2020-05-30 11:33:16 +02:00
if (tokens.peek().kind === SyntaxKind.BoltColon) {
tokens.get();
typeBoundExpr = this.parseTypeExpression(tokens);
}
// The trait may optionally have 'fn ...' and 'type ..' elements wrapped in braces.
const t3 = tokens.peek();
if (t2.kind === SyntaxKind.BoltBraced) {
const t3 = tokens.get();
lastToken = t3;
2020-05-30 11:33:16 +02:00
const innerTokens = createTokenStream(t3);
elements = this.parseTraitOrImplElements(innerTokens);
assertNoTokens(innerTokens);
}
2020-05-30 11:33:16 +02:00
// Create and return the resulting AST node
const result = createBoltTraitDeclaration(modifiers, typeParams, name, typeBoundExpr, elements);
setOrigNodeRange(result, firstToken, lastToken);
return result;
}
public parseImplDeclaration(tokens: BoltTokenStream): BoltImplDeclaration {
2020-05-30 11:33:16 +02:00
let modifiers = 0;
2020-05-30 11:33:16 +02:00
let typeParams = null;
let traitTypeExpr = null;
let name;
// Parse the 'pub' keyword
let t0 = tokens.get();
const firstToken = t0;
if (t0.kind === SyntaxKind.BoltPubKeyword) {
modifiers |= BoltModifiers.IsPublic;
t0 = tokens.get();
}
2020-05-30 11:33:16 +02:00
// By now, we should encounter the 'impl' keyword
assertToken(t0, SyntaxKind.BoltImplKeyword);
2020-05-30 11:33:16 +02:00
// Type parameters are introduced by '<' and end with '>'
const t1 = tokens.peek();
if (t1.kind === SyntaxKind.BoltLtSign) {
typeParams = this.parseGenericTypeParameters(tokens);
2020-05-30 11:33:16 +02:00
const t2 = tokens.get();
assertToken(t2, SyntaxKind.BoltGtSign);
}
2020-05-30 11:33:16 +02:00
// Check for the 'for' keyword occuring before '{' .. '}'
let i = 2;
let foundForKeyword = false;
while (true) {
const tn = tokens.peek(i++);
if (tn.kind === SyntaxKind.BoltBraced || tn.kind === SyntaxKind.EndOfFile) {
break;
}
if (tn.kind === SyntaxKind.BoltForKeyword) {
foundForKeyword = true;
}
}
if (foundForKeyword) {
traitTypeExpr = this.parseTypeExpression(tokens);
// Skip the 'for' keyword itself
tokens.get();
}
// Parse the name of the type that this implementation is for
const t3 = tokens.get();
assertToken(t3, SyntaxKind.BoltIdentifier);
name = t3 as BoltIdentifier;
// Parse all 'fn ...' and 'type ...' elements
const t5 = tokens.get();
assertToken(t5, SyntaxKind.BoltBraced);
const elements = this.parseSourceElements(createTokenStream(t5));
// Create and return the result
const result = createBoltImplDeclaration(modifiers, typeParams, name, traitTypeExpr, elements as BoltDeclaration[]);
setOrigNodeRange(result, firstToken, t5);
return result;
}
public parseDeclarationLike(tokens: BoltTokenStream): BoltDeclarationLike {
2020-05-10 18:54:57 +02:00
let t0 = tokens.peek(1);
let i = 1;
if (t0.kind === SyntaxKind.BoltPubKeyword) {
t0 = tokens.peek(++i);
2020-05-10 18:54:57 +02:00
if (t0.kind !== SyntaxKind.BoltForeignKeyword) {
if (KIND_DECLARATION_KEYWORD.indexOf(t0.kind) === -1) {
throw new ParseError(t0, KIND_DECLARATION_KEYWORD);
}
}
2020-05-10 18:54:57 +02:00
}
if (t0.kind === SyntaxKind.BoltForeignKeyword) {
i += 2;
t0 = tokens.peek(i);
if (KIND_DECLARATION_KEYWORD.indexOf(t0.kind) === -1) {
throw new ParseError(t0, KIND_DECLARATION_KEYWORD);
}
2020-05-10 18:54:57 +02:00
}
switch (t0.kind) {
case SyntaxKind.BoltImplKeyword:
return this.parseImplDeclaration(tokens);
case SyntaxKind.BoltTraitKeyword:
return this.parseTraitDeclaration(tokens);
case SyntaxKind.BoltTypeKeyword:
return this.parseTypeAliasDeclaration(tokens);
2020-05-10 18:54:57 +02:00
case SyntaxKind.BoltFnKeyword:
return this.parseFunctionDeclaration(tokens);
case SyntaxKind.BoltLetKeyword:
return this.parseVariableDeclaration(tokens);
case SyntaxKind.BoltStructKeyword:
return this.parseRecordDeclaration(tokens);
case SyntaxKind.BoltStructKeyword:
return this.parseVariableDeclaration(tokens);
default:
throw new ParseError(t0, KIND_DECLARATION_T0);
}
}
private getFirstTokenAfterModifiers(tokens: BoltTokenStream): BoltToken {
let mustBeDeclOrImport = false;
let mustBeFunctionOrVariable = false;
let i = 1;
let t0 = tokens.peek(i);
if (t0.kind === SyntaxKind.BoltPubKeyword) {
mustBeDeclOrImport = true;
t0 = tokens.peek(++i);
}
if (t0.kind === SyntaxKind.BoltForeignKeyword) {
mustBeFunctionOrVariable = true;
i += 2;
t0 = tokens.peek(i);
}
if (mustBeFunctionOrVariable
&& t0.kind !== SyntaxKind.BoltStructKeyword
&& t0.kind !== SyntaxKind.BoltFnKeyword) {
throw new ParseError(t0, [SyntaxKind.BoltStructKeyword, SyntaxKind.BoltFnKeyword]);
}
if (mustBeDeclOrImport && KIND_DECLARATION_T0.indexOf(t0.kind) === -1 && t0.kind !== SyntaxKind.BoltImportKeyword) {
throw new ParseError(t0, KIND_DECLARATION_KEYWORD);
}
return t0;
}
private lookaheadIsMacroCall(tokens: BoltTokenStream): boolean {
return tokens.peek(1).kind === SyntaxKind.BoltIdentifier
&& tokens.peek(2).kind === SyntaxKind.BoltExMark;
}
2020-05-10 18:54:57 +02:00
public parseSourceElement(tokens: BoltTokenStream): BoltSourceElement {
if (this.lookaheadIsMacroCall(tokens)) {
return this.parseMacroCall(tokens);
}
2020-05-27 17:17:27 +02:00
const t0 = tokens.peek();
const t1 = this.getFirstTokenAfterModifiers(tokens);
if (t1.kind === SyntaxKind.BoltImportKeyword) {
return this.parseImportDirective(tokens);
2020-05-27 17:17:27 +02:00
} else if (t1.kind === SyntaxKind.BoltModKeyword) {
return this.parseModuleDeclaration(tokens);
} else if (KIND_STATEMENT_T0.indexOf(t1.kind) !== -1) {
return this.parseStatement(tokens);
2020-05-27 17:17:27 +02:00
} else if (KIND_DECLARATION_KEYWORD.indexOf(t1.kind) !== -1) {
return this.parseDeclarationLike(tokens);
2020-05-27 17:17:27 +02:00
} else {
throw new ParseError(t0, KIND_SOURCEELEMENT_T0);
}
}
public parseFunctionBodyElement(tokens: BoltTokenStream): BoltFunctionBodyElement {
if (this.lookaheadIsMacroCall(tokens)) {
return this.parseMacroCall(tokens);
}
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 parseMacroCall(tokens: BoltTokenStream): BoltMacroCall {
const t0 = tokens.get();
assertToken(t0, SyntaxKind.BoltIdentifier);
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltExMark);
const t2 = tokens.get();
if (!isBoltPunctuated(t2)) {
throw new ParseError(t2, [SyntaxKind.BoltBraced, SyntaxKind.BoltParenthesized, SyntaxKind.BoltBracketed]);
}
const result = createBoltMacroCall(t0 as BoltIdentifier, t2.text);
setOrigNodeRange(result, t0, t2);
return result;
}
public parseFunctionBodyElements(tokens: BoltTokenStream): BoltFunctionBodyElement[] {
const elements: BoltFunctionBodyElement[] = []
while (true) {
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.EndOfFile) {
break;
2020-05-10 18:54:57 +02:00
}
if (t0.kind === SyntaxKind.BoltSemi) {
tokens.get();
continue;
}
elements.push(this.parseFunctionBodyElement(tokens));
}
return elements
2020-02-25 12:26:21 +01:00
}
public parseSourceElements(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;
2020-03-03 14:53:54 +01:00
}
elements.push(this.parseSourceElement(tokens));
2020-03-03 14:53:54 +01:00
}
return elements
2020-03-03 14:53:54 +01:00
}
2020-05-10 18:21:44 +02:00
//parseBinOp(tokens: TokenStream, lhs: Expr , minPrecedence: number) {
// let lookahead = tokens.peek(1);
// while (true) {
// if (lookahead.kind !== SyntaxKind.BoltOperator) {
// break;
// }
// const lookaheadDesc = this.getOperatorDesc(2, lookahead.text);
// if (lookaheadDesc === null || lookaheadDesc.precedence < minPrecedence) {
// break;
// }
// const op = lookahead;
// const opDesc = this.getOperatorDesc(2, op.text);
// tokens.get();
// let rhs = this.parsePrimExpr(tokens)
// lookahead = tokens.peek()
// while (lookaheadDesc.arity === 2
// && ((lookaheadDesc.precedence > opDesc.precedence)
// || lookaheadDesc.kind === OperatorKind.InfixR && lookaheadDesc.precedence === opDesc.precedence)) {
// rhs = this.parseBinOp(tokens, rhs, lookaheadDesc.precedence)
// }
// lookahead = tokens.peek();
// lhs = new CallExpr(new RefExpr(new QualName(op, [])), [lhs, rhs]);
// }
// return lhs
//}
2020-03-03 14:53:54 +01:00
public parseSourceFile(tokens: BoltTokenStream, pkg: Package): BoltSourceFile {
const elements = this.parseSourceElements(tokens);
const t1 = tokens.peek();
assertToken(t1, SyntaxKind.EndOfFile);
return createBoltSourceFile(
elements,
pkg,
new TextSpan(t1.span!.file, new TextPos(0,1,1), t1.span!.end.clone())
);
}
2020-05-30 11:33:16 +02:00
public parseTraitOrImplElements(tokens: BoltTokenStream): BoltTraitOrImplElement[] {
const elements: BoltTraitOrImplElement[] = [];
while (true) {
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.EndOfFile) {
break;
}
if (t0.kind === SyntaxKind.BoltSemi) {
tokens.get();
continue;
}
elements.push(this.parseTraitOrImplElement(tokens))
}
return elements;
}
public parseTraitOrImplElement(tokens: BoltTokenStream): BoltTraitOrImplElement {
if (this.lookaheadIsMacroCall(tokens)) {
return this.parseMacroCall(tokens);
}
const t0 = tokens.peek();
switch (t0.kind) {
case SyntaxKind.BoltFnKeyword:
return this.parseFunctionDeclaration(tokens);
case SyntaxKind.BoltTypeKeyword:
return this.parseTypeAliasDeclaration(tokens);
default:
throw new ParseError(t0, [SyntaxKind.BoltFnKeyword, SyntaxKind.BoltTypeAliasDeclaration, SyntaxKind.BoltMacroCall])
}
}
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"
import {JSScanner} from "./foreign/js/scanner";
import {emitNode} from "./emitter";
2020-05-27 17:17:27 +02:00
import { timingSafeEqual } from "crypto";
import { isatty } from "tty";
export function parseSourceFile(filepath: string, pkg: Package): BoltSourceFile {
const file = new TextFile(filepath);
const contents = fs.readFileSync(file.origPath, 'utf8');
const scanner = new Scanner(file, contents)
const parser = new Parser();
const sourceFile = parser.parseSourceFile(scanner, pkg);
setParents(sourceFile);
return sourceFile;
2020-02-25 12:26:21 +01:00
}