bolt/src/parser.ts

912 lines
25 KiB
TypeScript
Raw Normal View History

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,
BoltTypeNode,
createBoltReferenceTypeNode,
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,
createBoltRecordDeclarationField,
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,
BoltRecordDeclarationField,
BoltModule,
createBoltModule,
BoltNewTypeDeclaration,
createBoltNewTypeDeclaration,
BoltFunctionDeclaration,
createBoltFunctionDeclaration,
createBoltCallExpression,
2020-02-25 12:26:21 +01:00
} from "./ast"
2020-05-10 18:21:44 +02:00
import { BoltTokenStream, setOrigNodeRange } from "./util"
2020-02-25 12:26:21 +01:00
function describeKind(kind: SyntaxKind): string {
switch (kind) {
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltIdentifier:
2020-02-25 12:26:21 +01:00
return "an identifier"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltOperator:
2020-02-25 12:26:21 +01:00
return "an operator"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltStringLiteral:
2020-02-25 17:55:17 +01:00
return "a string"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltIntegerLiteral:
2020-02-25 17:55:17 +01:00
return "an integer"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltFnKeyword:
2020-02-25 17:55:17 +01:00
return "'fn'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltForeignKeyword:
2020-02-25 17:55:17 +01:00
return "'foreign'"
2020-05-10 18:54:57 +02:00
case SyntaxKind.BoltMatchKeyword:
return "'match'";
case SyntaxKind.BoltYieldKeyword:
return "'yield'";
case SyntaxKind.BoltReturnKeyword:
return "'return'";
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltPubKeyword:
return "'pub'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltLetKeyword:
2020-02-25 17:55:17 +01:00
return "'let'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltSemi:
2020-02-25 12:26:21 +01:00
return "';'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltColon:
2020-02-25 12:26:21 +01:00
return "':'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltDot:
2020-02-25 12:26:21 +01:00
return "'.'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltRArrow:
2020-03-03 14:53:54 +01:00
return "'->'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltComma:
2020-02-25 12:26:21 +01:00
return "','"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltModKeyword:
return "'mod'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltStructKeyword:
return "'struct'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltEnumKeyword:
return "'enum'"
2020-05-10 18:54:57 +02:00
case SyntaxKind.BoltNewTypeKeyword:
return "'newtype'";
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltBraced:
2020-02-25 12:26:21 +01:00
return "'{' .. '}'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltBracketed:
2020-02-25 12:26:21 +01:00
return "'[' .. ']'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltParenthesized:
2020-02-25 12:26:21 +01:00
return "'(' .. ')'"
2020-05-10 15:56:34 +02:00
case SyntaxKind.BoltEOS:
2020-02-25 17:55:17 +01:00
return "'}', ')', ']' or end-of-file"
2020-02-25 12:26:21 +01:00
default:
2020-05-10 15:56:34 +02:00
throw new Error(`failed to describe ${kindToString(kind)}`)
2020-02-25 12:26:21 +01:00
}
}
function enumerate(elements: string[]) {
if (elements.length === 1) {
return elements[0]
} else {
2020-05-10 18:54:57 +02:00
return elements.slice(0, elements.length-1).join(', ') + ' or ' + elements[elements.length-1]
2020-02-25 12:26:21 +01:00
}
}
export class ParseError extends Error {
2020-05-10 18:21:44 +02:00
constructor(public actual: BoltToken, public expected: SyntaxKind[]) {
super(`${actual.span!.file.origPath}:${actual.span!.start.line}:${actual.span!.start.column}: expected ${enumerate(expected.map(e => describeKind(e)))} but got ${describeKind(actual.kind)}`)
2020-02-25 12:26:21 +01:00
}
}
2020-03-03 14:53:54 +01:00
enum OperatorKind {
Prefix,
InfixL,
InfixR,
Suffix,
}
interface OperatorInfo {
kind: OperatorKind;
arity: number;
name: string;
precedence: number;
}
2020-05-10 18:21:44 +02:00
function assertToken(node: BoltToken, kind: SyntaxKind) {
if (node.kind !== kind) {
throw new ParseError(node, [kind]);
}
}
const KIND_EXPRESSION_T0 = [
SyntaxKind.BoltStringLiteral,
SyntaxKind.BoltIntegerLiteral,
SyntaxKind.BoltIdentifier,
SyntaxKind.BoltOperator,
2020-05-10 18:54:57 +02:00
SyntaxKind.BoltMatchKeyword,
SyntaxKind.BoltYieldKeyword,
]
2020-05-10 18:21:44 +02:00
const KIND_STATEMENT_T0 = [
SyntaxKind.BoltReturnKeyword,
...KIND_EXPRESSION_T0,
]
2020-05-10 18:54:57 +02:00
const KIND_DECLARATION_KEYWORD = [
SyntaxKind.BoltFnKeyword,
SyntaxKind.BoltEnumKeyword,
SyntaxKind.BoltLetKeyword,
SyntaxKind.BoltNewTypeKeyword,
SyntaxKind.BoltModKeyword,
SyntaxKind.BoltStructKeyword,
]
const KIND_DECLARATION_T0 = [
SyntaxKind.BoltPubKeyword,
SyntaxKind.BoltForeignKeyword,
...KIND_DECLARATION_KEYWORD,
]
const KIND_SOURCEELEMENT_T0 = [
SyntaxKind.BoltModKeyword,
...KIND_EXPRESSION_T0,
...KIND_STATEMENT_T0,
...KIND_DECLARATION_T0,
]
2020-02-25 12:26:21 +01:00
export class Parser {
2020-03-03 14:53:54 +01:00
operatorTable = [
[
[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, '!']
],
];
2020-05-10 18:21:44 +02:00
protected assertEmpty(tokens: BoltTokenStream) {
const t0 = tokens.peek(1);
if (t0.kind !== SyntaxKind.BoltEOS) {
throw new ParseError(t0, [SyntaxKind.BoltEOS]);
}
}
2020-03-03 14:53:54 +01:00
2020-05-10 18:21:44 +02:00
public parseQualName(tokens: BoltTokenStream): BoltQualName {
2020-02-25 12:26:21 +01:00
2020-05-10 15:56:34 +02:00
const path: BoltIdentifier[] = [];
2020-02-25 12:26:21 +01:00
while (true) {
const t0 = tokens.peek(2);
2020-05-10 15:56:34 +02:00
if (t0.kind !== SyntaxKind.BoltDot) {
2020-02-25 12:26:21 +01:00
break;
}
2020-05-10 15:56:34 +02:00
path.push(tokens.get() as BoltIdentifier)
2020-02-25 12:26:21 +01:00
tokens.get();
}
const name = tokens.get();
2020-05-10 15:56:34 +02:00
if (name.kind !== SyntaxKind.BoltIdentifier) {
throw new ParseError(name, [SyntaxKind.BoltIdentifier]);
2020-02-25 12:26:21 +01:00
}
const startNode = path.length > 0 ? path[0] : name;
const endNode = name;
2020-05-10 18:21:44 +02:00
const node = createBoltQualName(path, name, null);
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-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-10 15:56:34 +02:00
if (t0.kind === SyntaxKind.BoltIdentifier) {
2020-05-10 18:21:44 +02:00
return this.parseBindPattern(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-10 18:21:44 +02:00
public parseImportDeclaration(tokens: BoltTokenStream): BoltImportDeclaration {
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 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;
}
public parseReferenceTypeNode(tokens: BoltTokenStream) {
const name = this.parseQualName(tokens)
const t1 = tokens.peek();
let typeArgs: BoltTypeNode[] | null = null;
if (t1.kind === SyntaxKind.BoltLtSign) {
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.parseTypeNode(tokens));
}
const t4 = tokens.get();
assertToken(t4, SyntaxKind.BoltGtSign);
}
2020-05-10 18:21:44 +02:00
const node = createBoltReferenceTypeNode(name, typeArgs);
setOrigNodeRange(node, name, name);
return node;
}
2020-05-10 18:21:44 +02:00
public parseTypeNode(tokens: BoltTokenStream): BoltTypeNode {
2020-02-25 12:26:21 +01:00
const t0 = tokens.peek();
2020-05-10 15:56:34 +02:00
if (t0.kind === SyntaxKind.BoltIdentifier) {
2020-05-10 18:21:44 +02:00
return this.parseReferenceTypeNode(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-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 parseReferenceExpression(tokens: BoltTokenStream): BoltReferenceExpression {
const name = this.parseQualName(tokens);
const node = createBoltReferenceExpression(name);
setOrigNodeRange(node, name, name);
return node;
}
protected parsePrimitiveExpression(tokens: BoltTokenStream): BoltExpression {
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.BoltIntegerLiteral || t0.kind === SyntaxKind.BoltStringLiteral) {
return this.parseConstantExpression(tokens);
2020-05-10 15:56:34 +02:00
} else if (t0.kind === SyntaxKind.BoltIdentifier) {
2020-05-10 18:21:44 +02:00
return 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-10 18:21:44 +02:00
//parseSyntax(tokens: TokenStream): Syntax {
2020-05-10 18:21:44 +02:00
// // Assuming first token is 'syntax'
// const t0 = tokens.get();
// assertToken(t0, SyntaxKind.Bolt
2020-05-10 18:21:44 +02:00
// const t1 = tokens.get();
// if (t1.kind !== SyntaxKind.BoltBraced) {
// throw new ParseError(t1, [SyntaxKind.BoltBraced])
// }
2020-03-03 14:53:54 +01:00
2020-05-10 18:21:44 +02:00
// const innerTokens = t1.toTokenStream();
2020-03-03 14:53:54 +01:00
2020-05-10 18:21:44 +02:00
// const pattern = this.parsePattern(innerTokens)
2020-03-03 14:53:54 +01:00
2020-05-10 18:21:44 +02:00
// const t2 = innerTokens.get();
// if (t2.kind !== SyntaxKind.BoltRArrow) {
// throw new ParseError(t2, [SyntaxKind.BoltRArrow]);
// }
2020-03-03 14:53:54 +01:00
2020-05-10 18:21:44 +02:00
// const body = this.parseBody(innerTokens);
2020-03-03 14:53:54 +01:00
2020-05-10 18:21:44 +02:00
// return new Macro(pattern, body)
2020-05-10 18:21:44 +02:00
//}
2020-05-10 18:21:44 +02:00
public parseExpression(tokens: BoltTokenStream): BoltExpression {
return this.parsePrimitiveExpression(tokens)
2020-02-25 17:55:17 +01:00
}
2020-05-10 18:21:44 +02:00
public parseParameter(tokens: BoltTokenStream): BoltParameter {
2020-02-25 12:26:21 +01:00
let defaultValue = null;
let typeDecl = null;
const pattern = this.parsePattern(tokens)
2020-05-10 18:21:44 +02:00
let t0 = tokens.peek(1);
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-10 18:21:44 +02:00
typeDecl = this.parseTypeNode(tokens);
endNode = typeDecl;
t0 = tokens.get();
}
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-10 18:21:44 +02:00
const node = createBoltParameter(0, pattern, typeDecl, defaultValue)
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-10 18:21:44 +02:00
modifiers |= BoltDeclarationModifiers.Mutable;
}
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();
2020-05-10 18:21:44 +02:00
lastNode = typeDecl = this.parseTypeNode(tokens);
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();
2020-05-10 15:56:34 +02:00
if (t1.kind !== SyntaxKind.BoltEOS) {
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 {
const t0 = tokens.peek();
if (t0.kind === SyntaxKind.BoltReturnKeyword) {
return this.parseReturnStatement(tokens);
} else if (t0.kind === SyntaxKind.BoltLoopKeyword) {
return this.parseLoopStatement(tokens);
} else {
try {
return this.parseExpressionStatement(tokens);
} catch (e) {
if (!(e instanceof ParseError)) {
throw e;
}
throw new ParseError(t0, KIND_STATEMENT_T0);
}
}
}
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 t0 = tokens.get();
const firstToken = t0;
if (t0.kind === SyntaxKind.BoltPubKeyword) {
modifiers |= BoltDeclarationModifiers.Public;
t0 = tokens.get();
}
2020-05-10 18:21:44 +02:00
if (t0.kind !== SyntaxKind.BoltStructKeyword) {
throw new ParseError(t0, [SyntaxKind.BoltStructKeyword])
}
2020-05-10 19:05:37 +02:00
const t1 = tokens.get();
assertToken(t1, SyntaxKind.BoltIdentifier);
const name = createBoltQualName([], t1 as BoltIdentifier);
const t2 = tokens.get();
2020-05-10 15:56:34 +02:00
if (t2.kind !== SyntaxKind.BoltBraced) {
2020-05-10 18:21:44 +02:00
throw new ParseError(t2, [SyntaxKind.BoltBraced])
}
2020-05-10 18:21:44 +02:00
let fields: BoltRecordDeclarationField[] = [];
const innerTokens = createTokenStream(t2);
2020-05-10 18:21:44 +02:00
while (true) {
const t3 = innerTokens.get();
2020-05-10 19:05:37 +02:00
if (t3.kind === SyntaxKind.BoltEOS) {
2020-05-10 18:21:44 +02:00
break;
}
const name = innerTokens.get();
assertToken(name, SyntaxKind.BoltIdentifier);
const t4 = innerTokens.get();
assertToken(t4, SyntaxKind.BoltColon);
const type = this.parseTypeNode(innerTokens);
const field = createBoltRecordDeclarationField(name as BoltIdentifier, type);
setOrigNodeRange(field, name, type);
fields.push(field);
}
2020-05-10 19:05:37 +02:00
const node = createBoltRecordDeclaration(modifiers, name, fields);
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.BoltEOS) {
break;
}
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;
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-05-10 18:21:44 +02:00
if (t0.kind !== SyntaxKind.BoltIdentifier || t0.text !== 'mod') {
throw new ParseError(t0, [SyntaxKind.BoltModKeyword])
}
const name = this.parseQualName(tokens);
const t1 = tokens.get();
2020-05-10 15:56:34 +02:00
if (t1.kind !== SyntaxKind.BoltBraced) {
throw new ParseError(t1, [SyntaxKind.BoltBraced])
}
2020-05-10 18:21:44 +02:00
const sentences = this.parseSentences(createTokenStream(t1));
2020-05-10 18:21:44 +02:00
const node = createBoltModule(modifiers, name, sentences);
setOrigNodeRange(node, firstToken, t1);
return node;
}
2020-02-25 12:26:21 +01:00
2020-05-10 19:05:37 +02:00
public parseNewTypeDeclaration(tokens: BoltTokenStream): BoltNewTypeDeclaration {
2020-05-10 18:21:44 +02:00
let modifiers = 0;
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) {
tokens.get();
modifiers |= BoltDeclarationModifiers.Public;
t0 = tokens.peek();
2020-05-10 15:56:34 +02:00
if (t0.kind !== SyntaxKind.BoltIdentifier) {
throw new ParseError(t0, [SyntaxKind.BoltNewTypeKeyword])
2020-03-03 14:53:54 +01:00
}
}
2020-05-10 18:21:44 +02:00
if (t0.kind !== SyntaxKind.BoltNewTypeKeyword) {
2020-05-10 15:56:34 +02:00
throw new ParseError(t0, [SyntaxKind.BoltNewTypeKeyword])
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-10 18:21:44 +02:00
const node = createBoltNewTypeDeclaration(modifiers, name)
setOrigNodeRange(node, firstToken, name);
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;
if (k0.kind !== SyntaxKind.BoltPubKeyword) {
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-05-10 18:21:44 +02:00
if (k0.kind === SyntaxKind.BoltForeignKeyword) {
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();
let name: BoltQualName;
2020-02-25 12:26:21 +01:00
let returnType = null;
let body = null;
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-02-25 12:26:21 +01:00
this.assertEmpty(innerTokens);
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 18:21:44 +02:00
name = createBoltQualName([], t0);
setOrigNodeRange(name, t0, 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 18:21:44 +02:00
name = createBoltQualName([], t1);
setOrigNodeRange(name, t1, 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
name = this.parseQualName(tokens)
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-10 15:56:34 +02:00
if (t3.kind === SyntaxKind.BoltEOS) {
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-10 15:56:34 +02:00
} else if (t4.kind === SyntaxKind.BoltEOS) {
2020-02-25 12:26:21 +01:00
break;
} else {
2020-05-10 15:56:34 +02:00
throw new ParseError(t4, [SyntaxKind.BoltComma, SyntaxKind.BoltEOS])
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-10 18:21:44 +02:00
returnType = this.parseTypeNode(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-10 18:21:44 +02:00
body = this.parseStatements(tokens);
2020-02-25 17:55:17 +01:00
break;
case "JS":
2020-05-10 18:21:44 +02:00
// TODO
//body = acorn.parse(t3.text).body;
2020-02-25 17:55:17 +01:00
break;
default:
throw new Error(`Unrecognised language: ${target}`);
}
2020-02-25 12:26:21 +01:00
}
2020-05-10 18:21:44 +02:00
const node = createBoltFunctionDeclaration(
modifiers,
2020-05-10 19:05:37 +02:00
target,
2020-05-10 18:21:44 +02:00
name,
params,
returnType,
body
);
2020-05-10 19:05:37 +02:00
setOrigNodeRange(node, firstToken, lastToken!);
2020-05-10 18:54:57 +02:00
return node;
}
2020-02-25 12:26:21 +01:00
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) {
t0 = tokens.peek(i++);
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.BoltNewTypeKeyword:
return this.parseNewTypeDeclaration(tokens);
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);
}
}
public parseSourceElement(tokens: BoltTokenStream): BoltSourceElement {
const t0 = tokens.peek();
try {
return this.parseDeclaration(tokens)
} catch (e) {
if (!(e instanceof ParseError)) {
throw e;
}
try {
return this.parseStatement(tokens);
} catch (e) {
if (!(e instanceof ParseError)) {
throw e;
}
throw new ParseError(t0, KIND_SOURCEELEMENT_T0)
}
}
2020-02-25 12:26:21 +01:00
}
2020-05-10 18:54:57 +02:00
protected getOperatorDesc(seekArity: number, seekName: string): OperatorInfo {
2020-03-03 14:53:54 +01:00
for (let i = 0; i < this.operatorTable.length; ++i) {
for (const [kind, arity, name] of this.operatorTable[i]) {
2020-05-10 15:56:34 +02:00
if (arity == seekArity && name === seekName) {
2020-03-03 14:53:54 +01:00
return {
kind,
name,
arity,
precedence: i
}
}
}
}
}
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-10 18:54:57 +02:00
public parseCallExpression(tokens: BoltTokenStream): BoltCallExpression {
2020-02-25 17:55:17 +01:00
2020-05-10 18:21:44 +02:00
const operator = this.parsePrimitiveExpression(tokens)
2020-05-10 18:54:57 +02:00
const args: BoltExpression[] = []
2020-02-25 17:55:17 +01:00
const t2 = tokens.get();
2020-05-10 18:54:57 +02:00
assertToken(t2, SyntaxKind.BoltParenthesized);
2020-02-25 17:55:17 +01:00
2020-05-10 18:54:57 +02:00
const innerTokens = createTokenStream(t2);
2020-02-25 17:55:17 +01:00
while (true) {
const t3 = innerTokens.peek();
2020-05-10 15:56:34 +02:00
if (t3.kind === SyntaxKind.BoltEOS) {
2020-02-25 17:55:17 +01:00
break;
}
2020-05-10 18:21:44 +02:00
args.push(this.parseExpression(innerTokens))
2020-02-25 17:55:17 +01:00
const t4 = innerTokens.get();
2020-05-10 15:56:34 +02:00
if (t4.kind === SyntaxKind.BoltEOS) {
2020-02-25 17:55:17 +01:00
break
2020-05-10 15:56:34 +02:00
} else if (t4.kind !== SyntaxKind.BoltComma){
throw new ParseError(t4, [SyntaxKind.BoltComma])
2020-02-25 17:55:17 +01:00
}
}
2020-05-10 19:05:37 +02:00
return createBoltCallExpression(operator, args, null)
2020-02-25 17:55:17 +01:00
2020-02-25 12:26:21 +01:00
}
}