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,
|
|
|
|
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-02-25 12:26:21 +01:00
|
|
|
} from "./ast"
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
import { BoltTokenStream, setOrigNodeRange } from "./util"
|
2020-02-26 18:53:28 +01:00
|
|
|
|
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:
|
2020-02-26 18:53:28 +01:00
|
|
|
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:
|
2020-02-26 18:53:28 +01:00
|
|
|
return "'mod'"
|
2020-05-10 15:56:34 +02:00
|
|
|
case SyntaxKind.BoltStructKeyword:
|
2020-02-26 18:53:28 +01:00
|
|
|
return "'struct'"
|
2020-05-10 15:56:34 +02:00
|
|
|
case SyntaxKind.BoltEnumKeyword:
|
2020-02-26 18:53:28 +01:00
|
|
|
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);
|
|
|
|
const node = createBoltBindPattern((t0 as BoltIdentifier).text);
|
|
|
|
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 {
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-02-25 18:34:17 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
const node = createBoltReferenceTypeNode(name, typeArgs);
|
|
|
|
setOrigNodeRange(node, name, name);
|
|
|
|
return node;
|
2020-02-25 18:34:17 +01:00
|
|
|
}
|
|
|
|
|
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-02-26 18:53:28 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
// // Assuming first token is 'syntax'
|
|
|
|
// const t0 = tokens.get();
|
|
|
|
// assertToken(t0, SyntaxKind.Bolt
|
2020-02-26 18:53:28 +01:00
|
|
|
|
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-02-26 18:53:28 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
//}
|
2020-02-26 18:53:28 +01: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-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-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;
|
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-10 18:21:44 +02:00
|
|
|
lastNode = typeDecl = this.parseTypeNode(tokens);
|
|
|
|
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-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 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 {
|
|
|
|
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-02-26 18:53:28 +01:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
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 18:21:44 +02:00
|
|
|
const name = tokens.get();
|
|
|
|
assertToken(name, SyntaxKind.BoltIdentifier);
|
2020-02-26 18:53:28 +01:00
|
|
|
|
|
|
|
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-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
let fields: BoltRecordDeclarationField[] = [];
|
|
|
|
const innerTokens = createTokenStream(t2);
|
2020-02-26 18:53:28 +01:00
|
|
|
|
2020-05-10 18:21:44 +02:00
|
|
|
while (true) {
|
|
|
|
const t3 = innerTokens.get();
|
|
|
|
if (t3.kind === SyntaxKind.EOS) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
const node = new RecordDecl(modifiers, name, fields);
|
|
|
|
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();
|
|
|
|
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-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-10 18:21:44 +02:00
|
|
|
if (t0.kind !== SyntaxKind.BoltIdentifier || t0.text !== 'mod') {
|
|
|
|
throw new ParseError(t0, [SyntaxKind.BoltModKeyword])
|
2020-02-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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-02-26 18:53:28 +01:00
|
|
|
}
|
2020-05-10 18:21:44 +02:00
|
|
|
const sentences = this.parseSentences(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-10 18:21:44 +02:00
|
|
|
public parseNewTypeDeclaration(tokens: BoltTokenSteam): BoltNewTypeDeclaration {
|
|
|
|
|
|
|
|
let modifiers = 0;
|
2020-03-03 14:53:54 +01:00
|
|
|
|
|
|
|
let t0 = tokens.get();
|
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 18:54:57 +02:00
|
|
|
private parseFunctionDeclaration(tokens: BoltTokenStream): BoltFunctionDeclaration | BoltForeignFunctionDeclaration {
|
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();
|
|
|
|
let lastNode: BoltSyntax;
|
|
|
|
const firstToken = k0;
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse return type
|
|
|
|
|
|
|
|
const t2 = tokens.peek();
|
2020-05-10 15:56:34 +02:00
|
|
|
if (t2.kind === SyntaxKind.BoltRArrow) {
|
2020-02-25 12:26:21 +01:00
|
|
|
tokens.get();
|
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-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,
|
|
|
|
name,
|
|
|
|
params,
|
|
|
|
returnType,
|
|
|
|
body
|
|
|
|
);
|
|
|
|
setOrigNodeRange(node, firstToken, lastNode);
|
2020-05-10 18:54:57 +02:00
|
|
|
return node;
|
2020-02-26 18:53:28 +01:00
|
|
|
|
|
|
|
}
|
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-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) {
|
|
|
|
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-26 18:53:28 +01:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new CallExpr(operator, args, null)
|
|
|
|
|
2020-02-25 12:26:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|