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,
|
|
|
|
BoltImportDeclaration,
|
2020-05-22 19:50:47 +02:00
|
|
|
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,
|
2020-05-23 14:18:20 +02:00
|
|
|
createBoltRecordField,
|
2020-05-10 18:21:44 +02:00
|
|
|
createBoltImportDeclaration,
|
|
|
|
BoltDeclarationModifiers,
|
|
|
|
BoltStringLiteral,
|
|
|
|
BoltImportSymbol,
|
2020-05-10 18:54:57 +02:00
|
|
|
BoltCallExpression,
|
|
|
|
BoltExpressionStatement,
|
|
|
|
createBoltExpressionStatement,
|
2020-05-10 19:05:37 +02:00
|
|
|
BoltVariableDeclaration,
|
|
|
|
BoltSyntax,
|
|
|
|
createBoltVariableDeclaration,
|
|
|
|
BoltReturnStatement,
|
|
|
|
createBoltReturnStatement,
|
2020-05-23 14:18:20 +02:00
|
|
|
BoltRecordMember,
|
2020-05-10 19:05:37 +02:00
|
|
|
BoltModule,
|
|
|
|
createBoltModule,
|
2020-05-22 19:50:47 +02:00
|
|
|
BoltTypeAliasDeclaration,
|
|
|
|
createBoltTypeAliasDeclaration,
|
2020-05-10 19:05:37 +02:00
|
|
|
BoltFunctionDeclaration,
|
|
|
|
createBoltFunctionDeclaration,
|
|
|
|
createBoltCallExpression,
|
2020-05-10 23:50:42 +02:00
|
|
|
BoltSymbol,
|
2020-05-22 19:50:47 +02:00
|
|
|
BoltTypeParameter,
|
|
|
|
createBoltTypePattern,
|
|
|
|
createBoltTypeParameter,
|
2020-05-22 21:57:42 +02:00
|
|
|
BoltTraitDeclaration,
|
|
|
|
createBoltTraitKeyword,
|
|
|
|
createBoltTraitDeclaration,
|
|
|
|
createBoltImplDeclaration,
|
|
|
|
BoltImplDeclaration,
|
2020-05-23 14:18:20 +02:00
|
|
|
BoltSourceFile,
|
|
|
|
BoltFunctionBodyElement,
|
|
|
|
createBoltSourceFile,
|
|
|
|
BoltRecordField,
|
2020-05-23 21:15:20 +02:00
|
|
|
setParents,
|
2020-05-24 11:17:56 +02:00
|
|
|
BoltMatchExpression,
|
|
|
|
createBoltMatchArm,
|
|
|
|
BoltMatchArm,
|
|
|
|
createBoltMatchExpression,
|
|
|
|
createBoltExpressionPattern,
|
2020-05-24 20:17:42 +02:00
|
|
|
BoltFunctionTypeExpression,
|
|
|
|
BoltReferenceTypeExpression,
|
|
|
|
createBoltFunctionTypeExpression,
|
|
|
|
BoltRecordPattern,
|
|
|
|
createBoltRecordPattern,
|
|
|
|
createBoltRecordFieldPattern,
|
|
|
|
BoltQuoteKeyword,
|
|
|
|
isBoltPunctuated,
|
|
|
|
Token,
|
|
|
|
createBoltQuoteExpression,
|
|
|
|
BoltQuoteExpression,
|
|
|
|
BoltBlockExpression,
|
|
|
|
createBoltBlockExpression,
|
2020-05-24 21:03:15 +02:00
|
|
|
isBoltOperatorLike,
|
|
|
|
BoltFunctionExpression,
|
|
|
|
createBoltFunctionExpression,
|
|
|
|
BoltMacroCall,
|
|
|
|
createBoltMacroCall,
|
2020-05-24 21:18:54 +02:00
|
|
|
BoltMemberExpression,
|
|
|
|
createBoltMemberExpression,
|
2020-02-25 12:26:21 +01:00
|
|
|
} from "./ast"
|
|
|
|
|
2020-05-22 21:29:14 +02:00
|
|
|
import { parseForeignLanguage } from "./foreign"
|
2020-05-22 19:50:47 +02:00
|
|
|
|
2020-05-22 21:29:14 +02:00
|
|
|
import {
|
|
|
|
Stream,
|
|
|
|
OperatorKind,
|
|
|
|
OperatorTable,
|
|
|
|
assertToken,
|
|
|
|
ParseError,
|
|
|
|
setOrigNodeRange,
|
|
|
|
createTokenStream,
|
|
|
|
uniq,
|
2020-05-24 20:17:42 +02:00
|
|
|
assert,
|
2020-05-22 21:29:14 +02:00
|
|
|
} from "./util"
|
2020-05-10 23:50:42 +02:00
|
|
|
|
|
|
|
export type BoltTokenStream = Stream<BoltToken>;
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
export function isModifierKeyword(kind: SyntaxKind) {
|
|
|
|
return kind === SyntaxKind.BoltPubKeyword
|
|
|
|
|| kind === SyntaxKind.BoltForeignKeyword;
|
|
|
|
}
|
|
|
|
|
2020-05-24 11:17:56 +02:00
|
|
|
function assertNoTokens(tokens: BoltTokenStream) {
|
|
|
|
const t0 = tokens.peek(1);
|
|
|
|
if (t0.kind !== SyntaxKind.EndOfFile) {
|
|
|
|
throw new ParseError(t0, [SyntaxKind.EndOfFile]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
const KIND_EXPRESSION_T0 = [
|
|
|
|
SyntaxKind.BoltStringLiteral,
|
|
|
|
SyntaxKind.BoltIntegerLiteral,
|
|
|
|
SyntaxKind.BoltIdentifier,
|
|
|
|
SyntaxKind.BoltOperator,
|
2020-05-24 21:03:15 +02:00
|
|
|
SyntaxKind.BoltVBar,
|
2020-05-10 18:54:57 +02:00
|
|
|
SyntaxKind.BoltMatchKeyword,
|
2020-05-24 20:17:42 +02:00
|
|
|
SyntaxKind.BoltQuoteKeyword,
|
2020-05-10 18:54:57 +02:00
|
|
|
SyntaxKind.BoltYieldKeyword,
|
|
|
|
]
|
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 = [
|
2020-05-22 21:57:42 +02:00
|
|
|
SyntaxKind.BoltImplKeyword,
|
|
|
|
SyntaxKind.BoltTraitKeyword,
|
2020-05-10 18:54:57 +02:00
|
|
|
SyntaxKind.BoltFnKeyword,
|
|
|
|
SyntaxKind.BoltEnumKeyword,
|
|
|
|
SyntaxKind.BoltLetKeyword,
|
|
|
|
SyntaxKind.BoltModKeyword,
|
|
|
|
SyntaxKind.BoltStructKeyword,
|
2020-05-22 19:50:47 +02:00
|
|
|
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,
|
|
|
|
...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
|
|
|
|
2020-05-24 21:03:15 +02:00
|
|
|
function isRightAssoc(kind: OperatorKind): boolean {
|
|
|
|
return kind === OperatorKind.InfixR;
|
|
|
|
}
|
|
|
|
|
2020-02-25 12:26:21 +01:00
|
|
|
export class Parser {
|
|
|
|
|
2020-05-22 19:50:47 +02:00
|
|
|
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, '%'],
|
|
|
|
],
|
|
|
|
[
|
2020-05-22 19:50:47 +02:00
|
|
|
[OperatorKind.Prefix, 1, '!']
|
2020-03-03 14:53:54 +01:00
|
|
|
],
|
2020-05-22 19:50:47 +02: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-24 21:03:15 +02:00
|
|
|
public parseNamespacePath(tokens: BoltTokenStream): BoltQualName {
|
|
|
|
|
|
|
|
let modulePath = null;
|
|
|
|
|
|
|
|
if (tokens.peek(2).kind === SyntaxKind.BoltColonColon) {
|
|
|
|
modulePath = [];
|
|
|
|
while (true) {
|
|
|
|
modulePath.push(tokens.get() as BoltIdentifier)
|
|
|
|
tokens.get();
|
|
|
|
const t0 = tokens.peek(2);
|
|
|
|
if (t0.kind !== SyntaxKind.BoltColonColon) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const name = tokens.get();
|
|
|
|
assertToken(name, SyntaxKind.BoltIdentifier);
|
|
|
|
const startNode = modulePath !== null ? modulePath[0] : name;
|
|
|
|
const endNode = name;
|
|
|
|
const node = createBoltQualName(modulePath, name as BoltIdentifier, null);
|
|
|
|
setOrigNodeRange(node, startNode, endNode);
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
public parseQualName(tokens: BoltTokenStream): BoltQualName {
|
2020-02-25 12:26:21 +01:00
|
|
|
|
2020-05-23 21:15:20 +02:00
|
|
|
let modulePath = null;
|
2020-02-25 12:26:21 +01:00
|
|
|
|
2020-05-23 21:15:20 +02:00
|
|
|
if (tokens.peek(2).kind === SyntaxKind.BoltDot) {
|
|
|
|
modulePath = [];
|
|
|
|
while (true) {
|
|
|
|
modulePath.push(tokens.get() as BoltIdentifier)
|
|
|
|
tokens.get();
|
|
|
|
const t0 = tokens.peek(2);
|
|
|
|
if (t0.kind !== SyntaxKind.BoltDot) {
|
|
|
|
break;
|
|
|
|
}
|
2020-02-25 12:26:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const name = tokens.get();
|
2020-05-23 21:15:20 +02:00
|
|
|
assertToken(name, SyntaxKind.BoltIdentifier);
|
|
|
|
const startNode = modulePath !== null ? modulePath[0] : name;
|
2020-02-25 12:26:21 +01:00
|
|
|
const endNode = name;
|
2020-05-23 21:15:20 +02:00
|
|
|
const node = createBoltQualName(modulePath, name as BoltIdentifier, null);
|
2020-05-10 18:21:44 +02:00
|
|
|
setOrigNodeRange(node, startNode, endNode);
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-05-24 20:17:42 +02:00
|
|
|
public parseRecordPattern(tokens: BoltTokenStream): BoltRecordPattern {
|
|
|
|
|
2020-05-24 21:03:15 +02:00
|
|
|
const name = this.parseNamespacePath(tokens);
|
2020-05-24 20:17:42 +02:00
|
|
|
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);
|
2020-05-24 20:17:42 +02:00
|
|
|
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);
|
2020-05-24 11:17:56 +02:00
|
|
|
} 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
public parseImportDeclaration(tokens: BoltTokenStream): BoltImportDeclaration {
|
2020-02-25 18:34:17 +01:00
|
|
|
|
|
|
|
const t0 = tokens.get();
|
2020-05-10 18:21:44 +02:00
|
|
|
assertToken(t0, SyntaxKind.BoltImportKeyword);
|
2020-02-25 18:34:17 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
const t1 = tokens.get();
|
|
|
|
assertToken(t1, SyntaxKind.BoltStringLiteral);
|
|
|
|
const filename = (t1 as BoltStringLiteral).value;
|
|
|
|
|
|
|
|
const symbols: BoltImportSymbol[] = [];
|
|
|
|
// TODO implement grammar and parsing logic for symbols
|
|
|
|
|
|
|
|
const node = createBoltImportDeclaration(filename, symbols);
|
|
|
|
setOrigNodeRange(node, t0, t1);
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2020-05-24 20:17:42 +02:00
|
|
|
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-24 21:03:15 +02:00
|
|
|
const name = this.parseNamespacePath(tokens)
|
2020-05-10 18:21:44 +02:00
|
|
|
|
|
|
|
const t1 = tokens.peek();
|
|
|
|
|
2020-05-22 19:50:47 +02:00
|
|
|
let typeArgs: BoltTypeExpression[] | null = null;
|
2020-05-10 18:21:44 +02:00
|
|
|
|
|
|
|
if (t1.kind === SyntaxKind.BoltLtSign) {
|
2020-05-22 19:50:47 +02:00
|
|
|
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();
|
|
|
|
}
|
2020-05-22 19:50:47 +02:00
|
|
|
typeArgs!.push(this.parseTypeExpression(tokens));
|
2020-05-10 18:21:44 +02:00
|
|
|
}
|
|
|
|
const t4 = tokens.get();
|
|
|
|
assertToken(t4, SyntaxKind.BoltGtSign);
|
|
|
|
}
|
2020-02-25 18:34:17 +01:00
|
|
|
|
2020-05-22 19:50:47 +02:00
|
|
|
const node = createBoltReferenceTypeExpression(name, typeArgs);
|
2020-05-10 18:21:44 +02:00
|
|
|
setOrigNodeRange(node, name, name);
|
|
|
|
return node;
|
2020-02-25 18:34:17 +01:00
|
|
|
}
|
|
|
|
|
2020-05-22 19:50:47 +02:00
|
|
|
private parsePrimTypeExpression(tokens: BoltTokenStream): BoltTypeExpression {
|
2020-02-25 12:26:21 +01:00
|
|
|
const t0 = tokens.peek();
|
2020-05-24 20:17:42 +02:00
|
|
|
if (t0.kind === SyntaxKind.BoltFnKeyword) {
|
|
|
|
return this.parseFunctionTypeExpression(tokens);
|
|
|
|
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
|
2020-05-22 19:50:47 +02:00
|
|
|
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-22 19:50:47 +02:00
|
|
|
private parseTypeExpressionOperators(tokens: BoltTokenStream, lhs: BoltTypeExpression, minPrecedence: number): BoltTypeExpression {
|
|
|
|
while (true) {
|
|
|
|
const t0 = tokens.peek();
|
2020-05-24 21:03:15 +02:00
|
|
|
if (!isBoltOperatorLike(t0)) {
|
2020-05-22 19:50:47 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-05-24 21:03:15 +02:00
|
|
|
let desc0 = this.typeOperatorTable.lookup(emit(t0));
|
2020-05-22 19:50:47 +02:00
|
|
|
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()
|
2020-05-24 21:03:15 +02:00
|
|
|
if (!isBoltOperatorLike(t1.kind)) {
|
2020-05-22 19:50:47 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-05-24 21:03:15 +02:00
|
|
|
const desc1 = this.typeOperatorTable.lookup(emit(t1))
|
2020-05-22 19:50:47 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-05-24 21:03:15 +02:00
|
|
|
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 {
|
2020-05-24 21:03:15 +02:00
|
|
|
const name = this.parseNamespacePath(tokens);
|
2020-05-10 18:21:44 +02:00
|
|
|
const node = createBoltReferenceExpression(name);
|
|
|
|
setOrigNodeRange(node, name, name);
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
2020-05-24 11:17:56 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-05-24 20:17:42 +02:00
|
|
|
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);
|
|
|
|
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;
|
2020-05-24 21:03:15 +02:00
|
|
|
if (t0.kind === SyntaxKind.BoltVBar) {
|
2020-05-24 21:18:54 +02:00
|
|
|
result = this.parseFunctionExpression(tokens);
|
2020-05-24 21:03:15 +02:00
|
|
|
} else if (t0.kind === SyntaxKind.BoltBraced) {
|
2020-05-24 21:18:54 +02:00
|
|
|
result = this.parseBlockExpression(tokens);
|
2020-05-24 20:17:42 +02:00
|
|
|
} else if (t0.kind === SyntaxKind.BoltQuoteKeyword) {
|
2020-05-24 21:18:54 +02:00
|
|
|
result = this.parseQuoteExpression(tokens);
|
2020-05-24 20:17:42 +02:00
|
|
|
} else if (t0.kind === SyntaxKind.BoltMatchKeyword) {
|
2020-05-24 21:18:54 +02:00
|
|
|
result = this.parseMatchExpression(tokens);
|
2020-05-24 11:17:56 +02:00
|
|
|
} 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
|
|
|
}
|
|
|
|
|
2020-05-24 20:17:42 +02: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)
|
|
|
|
|
2020-05-22 21:57:42 +02:00
|
|
|
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();
|
2020-05-22 19:50:47 +02:00
|
|
|
typeDecl = this.parseTypeExpression(tokens);
|
2020-05-10 18:21:44 +02:00
|
|
|
endNode = typeDecl;
|
2020-05-22 21:57:42 +02:00
|
|
|
t0 = tokens.peek();
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2020-05-24 20:17:42 +02: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;
|
2020-02-25 18:34:17 +01:00
|
|
|
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) {
|
2020-02-25 18:34:17 +01:00
|
|
|
tokens.get();
|
2020-05-10 18:21:44 +02:00
|
|
|
modifiers |= BoltDeclarationModifiers.Mutable;
|
2020-02-25 18:34:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2020-02-25 18:34:17 +01:00
|
|
|
tokens.get();
|
2020-05-22 19:50:47 +02:00
|
|
|
lastNode = typeDecl = this.parseTypeExpression(tokens);
|
2020-05-10 18:21:44 +02:00
|
|
|
t2 = tokens.peek();
|
2020-02-25 18:34:17 +01:00
|
|
|
}
|
|
|
|
|
2020-05-10 15:56:34 +02:00
|
|
|
if (t2.kind === SyntaxKind.BoltEqSign) {
|
2020-02-25 18:34:17 +01:00
|
|
|
tokens.get();
|
2020-05-10 18:21:44 +02:00
|
|
|
lastNode = value = this.parseExpression(tokens);
|
2020-02-25 18:34:17 +01:00
|
|
|
}
|
|
|
|
|
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();
|
2020-05-22 19:50:47 +02:00
|
|
|
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-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
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 {
|
2020-05-24 21:03:15 +02:00
|
|
|
if (this.lookaheadIsMacroCall(tokens)) {
|
|
|
|
return this.parseMacroCall(tokens);
|
|
|
|
}
|
2020-05-10 18:21:44 +02:00
|
|
|
const t0 = tokens.peek();
|
2020-05-23 21:15:20 +02:00
|
|
|
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 {
|
2020-05-23 21:15:20 +02:00
|
|
|
throw new ParseError(t0, KIND_STATEMENT_T0);
|
2020-05-10 18:21:44 +02:00
|
|
|
}
|
|
|
|
}
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-22 21:57:42 +02:00
|
|
|
public parseGenericTypeParameter(tokens: BoltTokenStream): BoltTypeParameter {
|
2020-05-22 19:50:47 +02:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-22 21:57:42 +02:00
|
|
|
private parseGenericTypeParameters(tokens: BoltTokenStream): BoltTypeParameter[] {
|
2020-05-22 19:50:47 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
public parseRecordDeclaration(tokens: BoltTokenStream): BoltRecordDeclaration {
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
let modifiers = 0;
|
2020-05-22 19:50:47 +02:00
|
|
|
let typeParams = null;
|
2020-05-10 18:21:44 +02:00
|
|
|
|
|
|
|
let t0 = tokens.get();
|
|
|
|
const firstToken = t0;
|
|
|
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
|
|
|
modifiers |= BoltDeclarationModifiers.Public;
|
|
|
|
t0 = tokens.get();
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
if (t0.kind !== SyntaxKind.BoltStructKeyword) {
|
|
|
|
throw new ParseError(t0, [SyntaxKind.BoltStructKeyword])
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
2020-05-10 19:05:37 +02:00
|
|
|
const t1 = tokens.get();
|
|
|
|
assertToken(t1, SyntaxKind.BoltIdentifier);
|
2020-05-23 21:15:20 +02:00
|
|
|
const name = t1 as BoltIdentifier;
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-22 19:50:47 +02:00
|
|
|
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();
|
|
|
|
}
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
let members = null;
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
if (t2.kind !== SyntaxKind.BoltSemi) {
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
if (t2.kind !== SyntaxKind.BoltBraced) {
|
|
|
|
throw new ParseError(t2, [SyntaxKind.BoltBraced])
|
2020-05-10 18:21:44 +02:00
|
|
|
}
|
2020-05-23 14:18:20 +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-22 19:50:47 +02:00
|
|
|
}
|
2020-05-23 14:18:20 +02:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
}
|
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
const node = createBoltRecordDeclaration(modifiers, name, typeParams, members);
|
2020-05-10 18:21:44 +02:00
|
|
|
setOrigNodeRange(node, firstToken, t2);
|
|
|
|
return node;
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
public parseStatements(tokens: BoltTokenStream): BoltStatement[] {
|
|
|
|
const statements: BoltStatement[] = [];
|
|
|
|
while (true) {
|
|
|
|
const t0 = tokens.peek();
|
2020-05-22 19:50:47 +02:00
|
|
|
if (t0.kind === SyntaxKind.EndOfFile) {
|
2020-05-10 18:21:44 +02:00
|
|
|
break;
|
|
|
|
}
|
2020-05-23 21:15:20 +02:00
|
|
|
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-02-26 18:53:28 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
let modifiers = 0;
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
let t0 = tokens.get();
|
|
|
|
const firstToken = t0;
|
|
|
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
|
|
|
tokens.get();
|
|
|
|
modifiers |= BoltDeclarationModifiers.Public;
|
|
|
|
t0 = tokens.peek();
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
2020-05-22 19:50:47 +02:00
|
|
|
if (t0.kind !== SyntaxKind.BoltModKeyword) {
|
2020-05-10 18:21:44 +02:00
|
|
|
throw new ParseError(t0, [SyntaxKind.BoltModKeyword])
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
2020-05-24 21:03:15 +02:00
|
|
|
const name = this.parseNamespacePath(tokens);
|
2020-02-26 18:53:28 +01:00
|
|
|
|
|
|
|
const t1 = tokens.get();
|
2020-05-10 15:56:34 +02:00
|
|
|
if (t1.kind !== SyntaxKind.BoltBraced) {
|
|
|
|
throw new ParseError(t1, [SyntaxKind.BoltBraced])
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
2020-05-23 14:18:20 +02:00
|
|
|
const sentences = this.parseSourceElements(createTokenStream(t1));
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
const node = createBoltModule(modifiers, name, sentences);
|
|
|
|
setOrigNodeRange(node, firstToken, t1);
|
|
|
|
return node;
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
2020-02-25 12:26:21 +01:00
|
|
|
|
2020-05-22 19:50:47 +02:00
|
|
|
public parseTypeAliasDeclaration(tokens: BoltTokenStream): BoltTypeAliasDeclaration {
|
2020-05-10 18:21:44 +02:00
|
|
|
|
|
|
|
let modifiers = 0;
|
2020-05-22 19:50:47 +02:00
|
|
|
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 |= BoltDeclarationModifiers.Public;
|
2020-05-22 19:50:47 +02:00
|
|
|
t0 = tokens.get();
|
2020-03-03 14:53:54 +01:00
|
|
|
}
|
|
|
|
|
2020-05-22 19:50:47 +02: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
|
|
|
}
|
|
|
|
|
2020-05-22 19:50:47 +02:00
|
|
|
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);
|
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();
|
2020-05-10 19:05:37 +02:00
|
|
|
let lastToken: BoltSyntax;
|
2020-05-10 18:21:44 +02:00
|
|
|
const firstToken = k0;
|
|
|
|
|
2020-05-10 23:50:42 +02:00
|
|
|
if (k0.kind === SyntaxKind.BoltPubKeyword) {
|
2020-02-26 18:53:28 +01:00
|
|
|
tokens.get();
|
2020-05-10 18:21:44 +02:00
|
|
|
modifiers |= BoltDeclarationModifiers.Public;
|
|
|
|
k0 = tokens.peek();
|
2020-02-25 17:55:17 +01:00
|
|
|
}
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
if (k0.kind === SyntaxKind.BoltForeignKeyword) {
|
2020-02-26 18:53:28 +01:00
|
|
|
tokens.get();
|
2020-05-10 18:21:44 +02:00
|
|
|
modifiers |= BoltDeclarationModifiers.IsForeign;
|
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[] = [];
|
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++)
|
2020-05-24 11:17:56 +02:00
|
|
|
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();
|
2020-05-22 19:50:47 +02:00
|
|
|
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;
|
2020-05-22 19:50:47 +02:00
|
|
|
} else if (t4.kind === SyntaxKind.EndOfFile) {
|
2020-02-25 12:26:21 +01:00
|
|
|
break;
|
|
|
|
} else {
|
2020-05-22 19:50:47 +02:00
|
|
|
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
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-05-10 19:05:37 +02:00
|
|
|
if (params.length > 0) {
|
|
|
|
lastToken = params[params.length-1];
|
|
|
|
}
|
|
|
|
|
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-05-10 19:05:37 +02:00
|
|
|
lastToken = t2;
|
2020-02-25 12:26:21 +01:00
|
|
|
tokens.get();
|
2020-05-22 19:50:47 +02:00
|
|
|
returnType = this.parseTypeExpression(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-05-10 19:05:37 +02:00
|
|
|
lastToken = t3;
|
2020-02-25 17:55:17 +01:00
|
|
|
tokens.get();
|
|
|
|
switch (target) {
|
|
|
|
case "Bolt":
|
2020-05-24 11:17:56 +02:00
|
|
|
body = this.parseStatements(createTokenStream(t3));
|
2020-02-25 17:55:17 +01:00
|
|
|
break;
|
|
|
|
default:
|
2020-05-22 21:29:14 +02:00
|
|
|
body = parseForeignLanguage(target, t3.text, t3.span!.file, t3.span!.start);
|
|
|
|
break;
|
2020-02-25 17:55:17 +01:00
|
|
|
}
|
2020-02-25 12:26:21 +01:00
|
|
|
}
|
|
|
|
|
2020-05-22 21:29:14 +02: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,
|
|
|
|
body
|
|
|
|
);
|
2020-05-22 21:29:14 +02:00
|
|
|
setOrigNodeRange(result, firstToken, lastToken!);
|
|
|
|
return result;
|
2020-02-26 18:53:28 +01:00
|
|
|
|
|
|
|
}
|
2020-02-25 12:26:21 +01:00
|
|
|
|
2020-05-22 21:57:42 +02:00
|
|
|
public parseTraitDeclaration(tokens: BoltTokenStream): BoltTraitDeclaration {
|
|
|
|
let modifiers = 0;
|
|
|
|
let t0 = tokens.get();
|
|
|
|
const firstToken = t0;
|
|
|
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
|
|
|
modifiers |= BoltDeclarationModifiers.Public;
|
|
|
|
t0 = tokens.get();
|
|
|
|
}
|
|
|
|
assertToken(t0, SyntaxKind.BoltTraitKeyword);
|
|
|
|
const t1 = tokens.get();
|
|
|
|
assertToken(t1, SyntaxKind.BoltIdentifier);
|
|
|
|
let typeParams = null
|
|
|
|
const t2 = tokens.peek();
|
|
|
|
if (t2.kind === SyntaxKind.BoltLtSign) {
|
|
|
|
typeParams = this.parseGenericTypeParameters(tokens);
|
|
|
|
}
|
|
|
|
const t3 = tokens.get();
|
|
|
|
assertToken(t3, SyntaxKind.BoltBraced);
|
2020-05-23 14:18:20 +02:00
|
|
|
const elements = this.parseSourceElements(createTokenStream(t3));
|
2020-05-22 21:57:42 +02:00
|
|
|
const result = createBoltTraitDeclaration(modifiers, t1 as BoltIdentifier, typeParams, elements as BoltDeclaration[]);
|
|
|
|
setOrigNodeRange(result, firstToken, t3);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
public parseImplDeclaration(tokens: BoltTokenStream): BoltImplDeclaration {
|
|
|
|
let modifiers = 0;
|
|
|
|
let t0 = tokens.get();
|
|
|
|
const firstToken = t0;
|
|
|
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
|
|
|
modifiers |= BoltDeclarationModifiers.Public;
|
|
|
|
t0 = tokens.get();
|
|
|
|
}
|
|
|
|
assertToken(t0, SyntaxKind.BoltImplKeyword);
|
|
|
|
const t1 = tokens.get();
|
|
|
|
assertToken(t1, SyntaxKind.BoltIdentifier);
|
|
|
|
const t2 = tokens.get();
|
|
|
|
assertToken(t2, SyntaxKind.BoltForKeyword);
|
|
|
|
const typeExpr = this.parseTypeExpression(tokens);
|
|
|
|
let typeParams = null
|
|
|
|
const t3 = tokens.peek();
|
|
|
|
if (t3.kind === SyntaxKind.BoltLtSign) {
|
|
|
|
typeParams = this.parseGenericTypeParameters(tokens);
|
|
|
|
}
|
|
|
|
const t4 = tokens.get();
|
|
|
|
assertToken(t4, SyntaxKind.BoltBraced);
|
2020-05-23 14:18:20 +02:00
|
|
|
const elements = this.parseSourceElements(createTokenStream(t4));
|
2020-05-22 21:57:42 +02:00
|
|
|
const result = createBoltImplDeclaration(modifiers, t1 as BoltIdentifier, typeExpr, typeParams, elements as BoltDeclaration[]);
|
|
|
|
setOrigNodeRange(result, firstToken, t4);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2020-05-10 18:54:57 +02:00
|
|
|
public parseDeclaration(tokens: BoltTokenStream): BoltDeclaration {
|
|
|
|
let t0 = tokens.peek(1);
|
|
|
|
let i = 1;
|
|
|
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
2020-05-24 11:17:56 +02:00
|
|
|
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-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
}
|
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-02-26 18:53:28 +01:00
|
|
|
}
|
2020-05-10 18:54:57 +02:00
|
|
|
}
|
|
|
|
switch (t0.kind) {
|
2020-05-22 21:57:42 +02:00
|
|
|
case SyntaxKind.BoltImplKeyword:
|
|
|
|
return this.parseImplDeclaration(tokens);
|
|
|
|
case SyntaxKind.BoltTraitKeyword:
|
|
|
|
return this.parseTraitDeclaration(tokens);
|
2020-05-22 19:50:47 +02:00
|
|
|
case SyntaxKind.BoltTypeKeyword:
|
|
|
|
return this.parseTypeAliasDeclaration(tokens);
|
2020-05-10 18:54:57 +02:00
|
|
|
case SyntaxKind.BoltModKeyword:
|
|
|
|
return this.parseModuleDeclaration(tokens);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2020-05-22 19:50:47 +02:00
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
private getFirstTokenAfterModifiers(tokens: BoltTokenStream): BoltToken {
|
|
|
|
let mustBeDecl = false;
|
|
|
|
let mustBeFunctionOrVariable = false;
|
|
|
|
let i = 1;
|
|
|
|
let t0 = tokens.peek(i);
|
|
|
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
|
|
|
mustBeDecl = true;
|
|
|
|
t0 = tokens.peek(++i);
|
|
|
|
}
|
|
|
|
if (t0.kind === SyntaxKind.BoltForeignKeyword) {
|
|
|
|
mustBeFunctionOrVariable = true;
|
2020-05-24 11:17:56 +02:00
|
|
|
i += 2;
|
|
|
|
t0 = tokens.peek(i);
|
2020-05-23 14:18:20 +02:00
|
|
|
}
|
2020-05-24 20:17:42 +02:00
|
|
|
if (mustBeFunctionOrVariable
|
2020-05-23 14:18:20 +02:00
|
|
|
&& t0.kind !== SyntaxKind.BoltStructKeyword
|
|
|
|
&& t0.kind !== SyntaxKind.BoltFnKeyword) {
|
|
|
|
throw new ParseError(t0, [SyntaxKind.BoltStructKeyword, SyntaxKind.BoltFnKeyword]);
|
|
|
|
}
|
|
|
|
if (mustBeDecl && KIND_DECLARATION_T0.indexOf(t0.kind) === -1) {
|
|
|
|
throw new ParseError(t0, KIND_DECLARATION_KEYWORD);
|
|
|
|
}
|
|
|
|
return t0;
|
|
|
|
}
|
|
|
|
|
2020-05-24 21:03:15 +02:00
|
|
|
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 {
|
2020-05-24 21:03:15 +02:00
|
|
|
if (this.lookaheadIsMacroCall(tokens)) {
|
|
|
|
return this.parseMacroCall(tokens);
|
|
|
|
}
|
2020-05-23 14:18:20 +02:00
|
|
|
const t0 = this.getFirstTokenAfterModifiers(tokens);
|
|
|
|
if (KIND_STATEMENT_T0.indexOf(t0.kind) !== -1) {
|
|
|
|
return this.parseStatement(tokens);
|
|
|
|
}
|
2020-05-24 21:03:15 +02:00
|
|
|
return this.parseDeclaration(tokens);
|
2020-05-23 14:18:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public parseFunctionBodyElement(tokens: BoltTokenStream): BoltFunctionBodyElement {
|
2020-05-24 21:03:15 +02:00
|
|
|
if (this.lookaheadIsMacroCall(tokens)) {
|
|
|
|
return this.parseMacroCall(tokens);
|
|
|
|
}
|
2020-05-23 14:18:20 +02:00
|
|
|
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]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-24 21:03:15 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
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
|
|
|
}
|
2020-05-23 14:18:20 +02:00
|
|
|
if (t0.kind === SyntaxKind.BoltSemi) {
|
|
|
|
tokens.get();
|
|
|
|
continue;
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
2020-05-23 14:18:20 +02:00
|
|
|
elements.push(this.parseFunctionBodyElement(tokens));
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
2020-05-23 14:18:20 +02:00
|
|
|
return elements
|
2020-02-25 12:26:21 +01:00
|
|
|
}
|
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
public parseSourceElements(tokens: BoltTokenStream): BoltSourceElement[] {
|
2020-05-22 19:50:47 +02:00
|
|
|
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
|
|
|
}
|
2020-05-22 19:50:47 +02:00
|
|
|
elements.push(this.parseSourceElement(tokens));
|
2020-03-03 14:53:54 +01:00
|
|
|
}
|
2020-05-22 19:50:47 +02: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
|
|
|
|
2020-05-23 14:18:20 +02:00
|
|
|
public parseSourceFile(tokens: BoltTokenStream): BoltSourceFile {
|
|
|
|
const elements = this.parseSourceElements(tokens);
|
|
|
|
const t1 = tokens.peek();
|
|
|
|
assertToken(t1, SyntaxKind.EndOfFile);
|
|
|
|
return createBoltSourceFile(
|
|
|
|
elements,
|
|
|
|
new TextSpan(t1.span!.file, new TextPos(0,1,1), t1.span!.end.clone())
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseExpression(tokens: BoltTokenStream): boolean {
|
|
|
|
// TODO
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseReturnStatement(tokens: BoltTokenStream): boolean {
|
|
|
|
const t0 = tokens.get();
|
|
|
|
if (t0.kind !== SyntaxKind.BoltReturnKeyword) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
const t1 = tokens.peek();
|
|
|
|
if (t1.kind === SyntaxKind.EndOfFile) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return this.canParseExpression(tokens);
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseStatement(tokens: BoltTokenStream): boolean {
|
|
|
|
const t0 = tokens.peek();
|
|
|
|
switch (t0.kind) {
|
|
|
|
case SyntaxKind.BoltReturnKeyword:
|
|
|
|
return this.canParseReturnStatement(tokens);
|
|
|
|
case SyntaxKind.BoltLoopKeyword:
|
|
|
|
return this.canParseLoopStatement(tokens);
|
|
|
|
default:
|
|
|
|
return this.canParseExpression(tokens)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseFunctionDeclaration(tokens: BoltTokenStream): boolean {
|
|
|
|
let t0 = tokens.peek();
|
|
|
|
if (t0.kind === SyntaxKind.BoltPubKeyword) {
|
|
|
|
tokens.get();
|
|
|
|
t0 = tokens.peek();
|
|
|
|
}
|
|
|
|
if (t0.kind === SyntaxKind.BoltForeignKeyword) {
|
|
|
|
tokens.get();
|
|
|
|
const t1 = tokens.get();
|
|
|
|
if (t1.kind !== SyntaxKind.BoltStringLiteral) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
t0 = tokens.peek();
|
|
|
|
}
|
|
|
|
// TODO
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseRecordDeclaration(tokens: BoltTokenStream): boolean {
|
|
|
|
// TODO
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseVariableDeclaration(tokens: BoltTokenStream): boolean {
|
|
|
|
// TODO
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseDeclaration(tokens: BoltTokenStream): boolean {
|
|
|
|
let i = 0;
|
|
|
|
let t0 = tokens.peek(i);
|
|
|
|
while (isModifierKeyword(t0.kind)) {
|
|
|
|
t0 = tokens.peek(++i);
|
|
|
|
}
|
|
|
|
switch (t0.kind) {
|
|
|
|
case SyntaxKind.BoltFnKeyword:
|
|
|
|
return this.canParseFunctionDeclaration(tokens);
|
|
|
|
case SyntaxKind.BoltStructKeyword:
|
|
|
|
return this.canParseRecordDeclaration(tokens);
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseSourceElement(tokens: BoltTokenStream): boolean {
|
|
|
|
return this.canParseStatement(tokens)
|
|
|
|
|| this.canParseDeclaration(tokens)
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseRecordMember(tokens: BoltTokenStream): boolean {
|
|
|
|
// TODO
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseFunctionBodyElement(tokens: BoltTokenStream): boolean {
|
|
|
|
return this.canParseFunctionDeclaration(tokens)
|
|
|
|
|| this.canParseStatement(tokens)
|
|
|
|
|| this.canParseVariableDeclaration(tokens);
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseRecordMembers(tokens: BoltTokenStream): boolean {
|
|
|
|
while (true) {
|
|
|
|
const t0 = tokens.peek();
|
|
|
|
if (t0.kind === SyntaxKind.EndOfFile) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!this.canParseRecordMember(tokens)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseSourceElements(tokens: BoltTokenStream): boolean {
|
|
|
|
while (true) {
|
|
|
|
const t0 = tokens.peek();
|
|
|
|
if (t0.kind === SyntaxKind.EndOfFile) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!this.canParseSourceElement(tokens)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
private canParseFunctionBodyElements(tokens: BoltTokenStream): boolean {
|
|
|
|
while (true) {
|
|
|
|
const t0 = tokens.peek();
|
|
|
|
if (t0.kind === SyntaxKind.EndOfFile) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!this.canParseFunctionBodyElement(tokens)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
import { Scanner } from "./scanner"
|
|
|
|
import { TextFile, TextSpan, TextPos } from "./text"
|
|
|
|
import * as fs from "fs"
|
2020-05-24 20:17:42 +02:00
|
|
|
import {JSScanner} from "./foreign/js/scanner";
|
2020-05-24 21:03:15 +02:00
|
|
|
import {emit} from "./emitter";
|
2020-05-23 14:18:20 +02:00
|
|
|
|
|
|
|
export function parseSourceFile(filepath: string): BoltSourceFile {
|
|
|
|
const file = new TextFile(filepath);
|
|
|
|
const contents = fs.readFileSync(file.origPath, 'utf8');
|
|
|
|
const scanner = new Scanner(file, contents)
|
|
|
|
const parser = new Parser();
|
2020-05-23 21:15:20 +02:00
|
|
|
const sourceFile = parser.parseSourceFile(scanner);
|
|
|
|
setParents(sourceFile);
|
|
|
|
return sourceFile;
|
2020-02-25 12:26:21 +01:00
|
|
|
}
|
2020-05-24 20:17:42 +02:00
|
|
|
|