2022-08-28 21:12:25 +02:00
|
|
|
|
|
|
|
import {
|
|
|
|
ReferenceTypeExpression,
|
|
|
|
SourceFile,
|
|
|
|
SourceFileElement,
|
|
|
|
StructDeclaration,
|
|
|
|
StructDeclarationField,
|
|
|
|
SyntaxKind,
|
|
|
|
Token,
|
|
|
|
TokenKind,
|
|
|
|
Expression,
|
|
|
|
TypeExpression,
|
|
|
|
ConstantExpression,
|
|
|
|
ReferenceExpression,
|
|
|
|
Dot,
|
|
|
|
Identifier,
|
|
|
|
TupleExpression,
|
|
|
|
PrefixExpression,
|
|
|
|
ExpressionStatement,
|
|
|
|
ImportDeclaration,
|
|
|
|
Param,
|
|
|
|
Pattern,
|
|
|
|
BindPattern,
|
|
|
|
LetDeclaration,
|
|
|
|
TypeAssert,
|
|
|
|
ExprBody,
|
|
|
|
BlockBody,
|
2022-08-29 16:17:55 +02:00
|
|
|
NestedExpression,
|
|
|
|
NamedTuplePattern,
|
|
|
|
StructPattern,
|
|
|
|
VariadicStructPatternElement,
|
2022-09-01 20:06:43 +02:00
|
|
|
PunnedStructPatternField,
|
|
|
|
StructPatternField,
|
2022-08-29 16:17:55 +02:00
|
|
|
TuplePattern,
|
|
|
|
InfixExpression,
|
2022-08-31 13:29:56 +02:00
|
|
|
TextFile,
|
|
|
|
CallExpression,
|
2022-08-31 13:53:57 +02:00
|
|
|
LetBodyElement,
|
|
|
|
ReturnStatement,
|
2022-09-01 20:06:43 +02:00
|
|
|
StructExpression,
|
|
|
|
StructExpressionField,
|
|
|
|
PunnedStructExpressionField,
|
|
|
|
IfStatementCase,
|
|
|
|
IfStatement,
|
2022-09-09 00:00:28 +02:00
|
|
|
MemberExpression,
|
|
|
|
IdentifierAlt,
|
2022-09-09 22:37:14 +02:00
|
|
|
WrappedOperator,
|
|
|
|
ArrowTypeExpression,
|
2022-09-10 14:11:04 +02:00
|
|
|
EnumDeclarationStructElement,
|
|
|
|
EnumDeclaration,
|
|
|
|
EnumDeclarationTupleElement,
|
2022-09-10 16:52:14 +02:00
|
|
|
VarTypeExpression,
|
2022-09-11 11:20:21 +02:00
|
|
|
TypeDeclaration,
|
|
|
|
AppTypeExpression,
|
2022-09-14 16:46:30 +02:00
|
|
|
NestedPattern,
|
|
|
|
NestedTypeExpression,
|
2022-09-16 11:31:34 +02:00
|
|
|
MatchArm,
|
|
|
|
MatchExpression,
|
|
|
|
LiteralPattern,
|
|
|
|
DisjunctivePattern,
|
2022-08-28 21:12:25 +02:00
|
|
|
} from "./cst"
|
2022-08-31 13:29:56 +02:00
|
|
|
import { Stream } from "./util";
|
2022-08-28 21:12:25 +02:00
|
|
|
|
2022-08-31 13:29:56 +02:00
|
|
|
export class ParseError extends Error {
|
2022-08-28 21:12:25 +02:00
|
|
|
|
|
|
|
public constructor(
|
2022-08-31 13:29:56 +02:00
|
|
|
public file: TextFile,
|
2022-08-28 21:12:25 +02:00
|
|
|
public actual: Token,
|
|
|
|
public expected: SyntaxKind[],
|
|
|
|
) {
|
2022-08-31 13:29:56 +02:00
|
|
|
super(`Uncaught parse error`);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-08-29 16:17:55 +02:00
|
|
|
function isBinaryOperatorLike(token: Token): boolean {
|
2022-09-16 11:31:34 +02:00
|
|
|
return token.kind === SyntaxKind.CustomOperator
|
|
|
|
|| token.kind === SyntaxKind.VBar;
|
2022-08-29 16:17:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
function isPrefixOperatorLike(token: Token): boolean {
|
2022-09-16 11:31:34 +02:00
|
|
|
return token.kind === SyntaxKind.CustomOperator
|
|
|
|
|| token.kind === SyntaxKind.VBar;
|
2022-08-29 16:17:55 +02:00
|
|
|
}
|
|
|
|
|
2022-08-28 21:12:25 +02:00
|
|
|
const enum OperatorMode {
|
|
|
|
None = 0,
|
|
|
|
Prefix = 1,
|
|
|
|
InfixL = 2,
|
|
|
|
InfixR = 4,
|
2022-08-29 16:17:55 +02:00
|
|
|
Infix = 6,
|
2022-08-28 21:12:25 +02:00
|
|
|
Suffix = 8,
|
|
|
|
}
|
|
|
|
|
|
|
|
interface OperatorInfo {
|
|
|
|
name: string,
|
|
|
|
mode: OperatorMode,
|
2022-08-29 16:17:55 +02:00
|
|
|
precedence: number,
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
2022-08-29 16:17:55 +02:00
|
|
|
const EXPR_OPERATOR_TABLE: Array<[string, OperatorMode, number]> = [
|
|
|
|
["**", OperatorMode.InfixR, 11],
|
|
|
|
["*", OperatorMode.InfixL, 8],
|
|
|
|
["/", OperatorMode.InfixL, 8],
|
|
|
|
["+", OperatorMode.InfixL, 7],
|
|
|
|
["-", OperatorMode.InfixL, 7],
|
|
|
|
["<", OperatorMode.InfixL, 6],
|
|
|
|
[">", OperatorMode.InfixL, 6],
|
|
|
|
["<=", OperatorMode.InfixL, 5],
|
|
|
|
[">=", OperatorMode.InfixL, 5],
|
|
|
|
["==", OperatorMode.InfixL, 5],
|
|
|
|
["!=", OperatorMode.InfixL, 5],
|
|
|
|
["<*", OperatorMode.InfixL, 4],
|
|
|
|
[":", OperatorMode.InfixL, 3],
|
|
|
|
["<|>", OperatorMode.InfixL, 2],
|
|
|
|
["<?>", OperatorMode.InfixL, 1],
|
|
|
|
["$", OperatorMode.InfixR, 0]
|
|
|
|
];
|
|
|
|
|
2022-08-28 21:12:25 +02:00
|
|
|
export class Parser {
|
|
|
|
|
2022-08-29 16:17:55 +02:00
|
|
|
private prefixExprOperators = new Set<string>();
|
|
|
|
private binaryExprOperators = new Map<string, OperatorInfo>();
|
|
|
|
private suffixExprOperators = new Set<string>();
|
2022-08-28 21:12:25 +02:00
|
|
|
|
|
|
|
public constructor(
|
2022-08-31 13:29:56 +02:00
|
|
|
public file: TextFile,
|
2022-08-28 21:12:25 +02:00
|
|
|
public tokens: Stream<Token>,
|
|
|
|
) {
|
2022-08-29 16:17:55 +02:00
|
|
|
for (const [name, mode, precedence] of EXPR_OPERATOR_TABLE) {
|
|
|
|
this.binaryExprOperators.set(name, { name, mode, precedence });
|
|
|
|
}
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private getToken(): Token {
|
|
|
|
return this.tokens.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
private peekToken(offset = 1): Token {
|
|
|
|
return this.tokens.peek(offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
private assertToken<K extends Token['kind']>(token: Token, expectedKind: K): void {
|
|
|
|
if (token.kind !== expectedKind) {
|
|
|
|
this.raiseParseError(token, [ expectedKind ]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private expectToken<K extends TokenKind>(expectedKind: K): Token & { kind: K } {
|
|
|
|
const token = this.getToken();
|
|
|
|
if (token.kind !== expectedKind) {
|
|
|
|
this.raiseParseError(token, [ expectedKind ])
|
|
|
|
}
|
|
|
|
return token as Token & { kind: K };
|
|
|
|
}
|
|
|
|
|
|
|
|
private raiseParseError(actual: Token, expected: SyntaxKind[]): never {
|
2022-08-31 13:29:56 +02:00
|
|
|
throw new ParseError(this.file, actual, expected);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private peekTokenAfterModifiers(): Token {
|
|
|
|
let t0;
|
|
|
|
for (let i = 1;;i++) {
|
|
|
|
t0 = this.peekToken(i);
|
|
|
|
if (t0.kind !== SyntaxKind.PubKeyword) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return t0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public parseReferenceTypeExpression(): ReferenceTypeExpression {
|
2022-09-01 20:18:47 +02:00
|
|
|
const name = this.expectToken(SyntaxKind.IdentifierAlt);
|
2022-08-28 21:12:25 +02:00
|
|
|
return new ReferenceTypeExpression([], name);
|
|
|
|
}
|
|
|
|
|
2022-09-09 22:37:14 +02:00
|
|
|
public parsePrimitiveTypeExpression(): TypeExpression {
|
2022-08-28 21:12:25 +02:00
|
|
|
const t0 = this.peekToken();
|
|
|
|
switch (t0.kind) {
|
2022-09-10 16:52:14 +02:00
|
|
|
case SyntaxKind.Identifier:
|
|
|
|
{
|
|
|
|
this.getToken();
|
|
|
|
return new VarTypeExpression(t0);
|
|
|
|
}
|
2022-09-14 16:46:30 +02:00
|
|
|
case SyntaxKind.LParen:
|
|
|
|
{
|
|
|
|
this.getToken();
|
|
|
|
const typeExpr = this.parseTypeExpression();
|
|
|
|
const t2 = this.expectToken(SyntaxKind.RParen);
|
|
|
|
return new NestedTypeExpression(t0, typeExpr, t2);
|
|
|
|
}
|
2022-09-01 20:18:47 +02:00
|
|
|
case SyntaxKind.IdentifierAlt:
|
2022-08-28 21:12:25 +02:00
|
|
|
return this.parseReferenceTypeExpression();
|
|
|
|
default:
|
2022-09-01 20:18:47 +02:00
|
|
|
this.raiseParseError(t0, [ SyntaxKind.IdentifierAlt ]);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-11 11:20:21 +02:00
|
|
|
private tryParseAppTypeExpression(): TypeExpression {
|
|
|
|
const operator = this.parsePrimitiveTypeExpression();
|
|
|
|
const args = [];
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind === SyntaxKind.RParen
|
|
|
|
|| t1.kind === SyntaxKind.RBrace
|
|
|
|
|| t1.kind === SyntaxKind.RBracket
|
|
|
|
|| t1.kind === SyntaxKind.Equals
|
|
|
|
|| t1.kind === SyntaxKind.BlockStart
|
|
|
|
|| t1.kind === SyntaxKind.LineFoldEnd
|
|
|
|
|| t1.kind === SyntaxKind.RArrow) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
args.push(this.parsePrimitiveTypeExpression());
|
|
|
|
}
|
|
|
|
if (args.length === 0) {
|
|
|
|
return operator;
|
|
|
|
}
|
|
|
|
return new AppTypeExpression(operator, args);
|
|
|
|
}
|
|
|
|
|
2022-09-09 22:37:14 +02:00
|
|
|
public parseTypeExpression(): TypeExpression {
|
2022-09-11 11:20:21 +02:00
|
|
|
let returnType = this.tryParseAppTypeExpression();
|
2022-09-09 22:37:14 +02:00
|
|
|
const paramTypes = [];
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind !== SyntaxKind.RArrow) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.getToken();
|
|
|
|
paramTypes.push(returnType);
|
2022-09-11 11:20:21 +02:00
|
|
|
returnType = this.tryParseAppTypeExpression();
|
2022-09-09 22:37:14 +02:00
|
|
|
}
|
|
|
|
if (paramTypes.length === 0) {
|
|
|
|
return returnType;
|
|
|
|
}
|
|
|
|
return new ArrowTypeExpression(paramTypes, returnType);
|
|
|
|
}
|
|
|
|
|
2022-08-28 21:12:25 +02:00
|
|
|
public parseConstantExpression(): ConstantExpression {
|
|
|
|
const token = this.getToken()
|
|
|
|
if (token.kind !== SyntaxKind.StringLiteral
|
|
|
|
&& token.kind !== SyntaxKind.Integer) {
|
|
|
|
this.raiseParseError(token, [ SyntaxKind.StringLiteral, SyntaxKind.Integer ])
|
|
|
|
}
|
|
|
|
return new ConstantExpression(token);
|
|
|
|
}
|
|
|
|
|
2022-09-15 20:33:34 +02:00
|
|
|
public parseReferenceExpression(): ReferenceExpression {
|
2022-09-09 00:00:28 +02:00
|
|
|
const modulePath: Array<[IdentifierAlt, Dot]> = [];
|
2022-08-28 21:12:25 +02:00
|
|
|
for (;;) {
|
2022-09-09 00:00:28 +02:00
|
|
|
const t0 = this.peekToken(1);
|
|
|
|
const t1 = this.peekToken(2);
|
|
|
|
if (t0.kind !== SyntaxKind.IdentifierAlt || t1.kind !== SyntaxKind.Dot) {
|
2022-08-28 21:12:25 +02:00
|
|
|
break;
|
|
|
|
}
|
2022-09-09 00:00:28 +02:00
|
|
|
modulePath.push([t0, t1]);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
2022-09-15 20:33:34 +02:00
|
|
|
const name = this.getToken();
|
|
|
|
if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.IdentifierAlt) {
|
|
|
|
this.raiseParseError(name, [ SyntaxKind.Identifier, SyntaxKind.IdentifierAlt ]);
|
|
|
|
}
|
|
|
|
return new ReferenceExpression(modulePath, name);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private parseExpressionWithParens(): Expression {
|
2022-09-16 10:25:24 +02:00
|
|
|
const elements = [];
|
2022-08-29 16:17:55 +02:00
|
|
|
const lparen = this.expectToken(SyntaxKind.LParen)
|
2022-09-16 10:25:24 +02:00
|
|
|
let rparen;
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind === SyntaxKind.RParen) {
|
|
|
|
rparen = t1;
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
}
|
2022-08-29 16:17:55 +02:00
|
|
|
const expression = this.parseExpression();
|
2022-09-16 10:25:24 +02:00
|
|
|
elements.push(expression);
|
|
|
|
const t2 = this.getToken();
|
|
|
|
if (t2.kind === SyntaxKind.Comma) {
|
|
|
|
continue;
|
|
|
|
} else if (t2.kind === SyntaxKind.RParen) {
|
|
|
|
rparen = t2;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
this.raiseParseError(t2, [ SyntaxKind.Comma, SyntaxKind.RParen ]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (elements.length === 1) {
|
|
|
|
return new NestedExpression(lparen, elements[0], rparen);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
2022-09-16 10:25:24 +02:00
|
|
|
return new TupleExpression(lparen, elements, rparen);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
2022-08-31 13:29:56 +02:00
|
|
|
private parsePrimitiveExpression(): Expression {
|
2022-08-28 21:12:25 +02:00
|
|
|
const t0 = this.peekToken();
|
|
|
|
switch (t0.kind) {
|
|
|
|
case SyntaxKind.LParen:
|
|
|
|
return this.parseExpressionWithParens();
|
|
|
|
case SyntaxKind.Identifier:
|
2022-09-01 20:18:47 +02:00
|
|
|
case SyntaxKind.IdentifierAlt:
|
2022-09-15 20:33:34 +02:00
|
|
|
return this.parseReferenceExpression();
|
2022-09-16 11:31:34 +02:00
|
|
|
case SyntaxKind.Integer:
|
|
|
|
case SyntaxKind.StringLiteral:
|
|
|
|
return this.parseConstantExpression();
|
|
|
|
case SyntaxKind.MatchKeyword:
|
|
|
|
{
|
|
|
|
this.getToken();
|
|
|
|
let expression = null
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind !== SyntaxKind.BlockStart) {
|
|
|
|
expression = this.parseExpression();
|
|
|
|
}
|
|
|
|
this.expectToken(SyntaxKind.BlockStart);
|
|
|
|
const arms = [];
|
|
|
|
for (;;) {
|
|
|
|
const t2 = this.peekToken();
|
|
|
|
if (t2.kind === SyntaxKind.BlockEnd) {
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const pattern = this.parsePattern();
|
|
|
|
const rarrowAlt = this.expectToken(SyntaxKind.RArrowAlt);
|
|
|
|
const expression = this.parseExpression();
|
|
|
|
arms.push(new MatchArm(pattern, rarrowAlt, expression));
|
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
|
|
|
}
|
|
|
|
return new MatchExpression(t0, expression, arms);
|
|
|
|
}
|
2022-09-15 20:33:34 +02:00
|
|
|
case SyntaxKind.LBrace:
|
2022-08-31 13:29:56 +02:00
|
|
|
{
|
|
|
|
this.getToken();
|
2022-09-15 20:33:34 +02:00
|
|
|
const fields = [];
|
|
|
|
let rbrace;
|
|
|
|
for (;;) {
|
|
|
|
const t2 = this.peekToken();
|
|
|
|
if (t2.kind === SyntaxKind.RBrace) {
|
|
|
|
this.getToken();
|
|
|
|
rbrace = t2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
let field;
|
|
|
|
const t3 = this.getToken();
|
|
|
|
if (t3.kind === SyntaxKind.Identifier) {
|
|
|
|
const t4 = this.peekToken();
|
|
|
|
if (t4.kind === SyntaxKind.Equals) {
|
2022-09-07 12:45:38 +02:00
|
|
|
this.getToken();
|
2022-09-15 20:33:34 +02:00
|
|
|
const expression = this.parseExpression();
|
|
|
|
field = new StructExpressionField(t3, t4, expression);
|
2022-09-01 20:06:43 +02:00
|
|
|
} else {
|
2022-09-15 20:33:34 +02:00
|
|
|
field = new PunnedStructExpressionField(t3);
|
2022-09-01 20:06:43 +02:00
|
|
|
}
|
2022-09-15 20:33:34 +02:00
|
|
|
} else {
|
|
|
|
// TODO add spread fields
|
|
|
|
this.raiseParseError(t3, [ SyntaxKind.Identifier ]);
|
2022-08-31 13:29:56 +02:00
|
|
|
}
|
2022-09-15 20:33:34 +02:00
|
|
|
fields.push(field);
|
|
|
|
const t5 = this.peekToken();
|
|
|
|
if (t5.kind === SyntaxKind.Comma) {
|
|
|
|
this.getToken();
|
|
|
|
continue;
|
|
|
|
} else if (t5.kind === SyntaxKind.RBrace) {
|
|
|
|
this.getToken();
|
|
|
|
rbrace = t5;
|
2022-08-31 13:29:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-09-15 20:33:34 +02:00
|
|
|
return new StructExpression(t0, fields, rbrace);
|
2022-08-31 13:29:56 +02:00
|
|
|
}
|
2022-08-28 21:12:25 +02:00
|
|
|
default:
|
|
|
|
this.raiseParseError(t0, [
|
|
|
|
SyntaxKind.TupleExpression,
|
|
|
|
SyntaxKind.NestedExpression,
|
|
|
|
SyntaxKind.ConstantExpression,
|
|
|
|
SyntaxKind.ReferenceExpression
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-09 00:00:28 +02:00
|
|
|
private tryParseMemberExpression(): Expression {
|
|
|
|
const expression = this.parsePrimitiveExpression();
|
|
|
|
const path: Array<[Dot, Identifier]> = [];
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind !== SyntaxKind.Dot) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.getToken();
|
|
|
|
const name = this.expectToken(SyntaxKind.Identifier);
|
|
|
|
path.push([t1, name]);
|
|
|
|
}
|
|
|
|
if (path.length === 0) {
|
|
|
|
return expression;
|
|
|
|
}
|
|
|
|
return new MemberExpression(expression, path);
|
|
|
|
}
|
|
|
|
|
|
|
|
private tryParseCallExpression(): Expression {
|
|
|
|
const func = this.tryParseMemberExpression();
|
2022-08-31 13:29:56 +02:00
|
|
|
const args = [];
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind === SyntaxKind.LineFoldEnd
|
2022-09-07 12:45:38 +02:00
|
|
|
|| t1.kind === SyntaxKind.RBrace
|
|
|
|
|| t1.kind === SyntaxKind.RBracket
|
2022-08-31 13:29:56 +02:00
|
|
|
|| t1.kind === SyntaxKind.RParen
|
2022-09-01 20:06:43 +02:00
|
|
|
|| t1.kind === SyntaxKind.BlockStart
|
2022-09-07 12:45:38 +02:00
|
|
|
|| t1.kind === SyntaxKind.Comma
|
2022-08-31 13:29:56 +02:00
|
|
|
|| isBinaryOperatorLike(t1)
|
|
|
|
|| isPrefixOperatorLike(t1)) {
|
|
|
|
break;
|
|
|
|
}
|
2022-09-09 00:00:28 +02:00
|
|
|
args.push(this.tryParseMemberExpression());
|
2022-08-31 13:29:56 +02:00
|
|
|
}
|
|
|
|
if (args.length === 0) {
|
|
|
|
return func
|
|
|
|
}
|
|
|
|
return new CallExpression(func, args);
|
|
|
|
}
|
|
|
|
|
2022-08-28 21:12:25 +02:00
|
|
|
private parseUnaryExpression(): Expression {
|
2022-09-09 00:00:28 +02:00
|
|
|
let result = this.tryParseCallExpression()
|
2022-08-29 16:17:55 +02:00
|
|
|
const prefixes = [];
|
2022-08-28 21:12:25 +02:00
|
|
|
for (;;) {
|
|
|
|
const t0 = this.peekToken();
|
2022-08-29 16:17:55 +02:00
|
|
|
if (!isPrefixOperatorLike(t0)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!this.prefixExprOperators.has(t0.text)) {
|
2022-08-28 21:12:25 +02:00
|
|
|
break;
|
|
|
|
}
|
2022-08-29 16:17:55 +02:00
|
|
|
prefixes.push(t0);
|
2022-08-28 21:12:25 +02:00
|
|
|
this.getToken()
|
|
|
|
}
|
2022-08-29 16:17:55 +02:00
|
|
|
for (let i = prefixes.length-1; i >= 0; i--) {
|
|
|
|
const operator = prefixes[i];
|
|
|
|
result = new PrefixExpression(operator, result);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
2022-08-29 16:17:55 +02:00
|
|
|
return result;
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
2022-08-29 16:17:55 +02:00
|
|
|
private parseBinaryOperatorAfterExpr(lhs: Expression, minPrecedence: number) {
|
2022-08-28 21:12:25 +02:00
|
|
|
for (;;) {
|
|
|
|
const t0 = this.peekToken();
|
2022-08-29 16:17:55 +02:00
|
|
|
if (!isBinaryOperatorLike(t0)) {
|
2022-08-28 21:12:25 +02:00
|
|
|
break;
|
|
|
|
}
|
2022-08-29 16:17:55 +02:00
|
|
|
const info0 = this.binaryExprOperators.get(t0.text);
|
|
|
|
if (info0 === undefined || info0.precedence < minPrecedence) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.getToken();
|
|
|
|
let rhs = this.parseUnaryExpression();
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (!isBinaryOperatorLike(t1)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const info1 = this.binaryExprOperators.get(t1.text);
|
|
|
|
if (info1 === undefined
|
|
|
|
|| info1.precedence < info0.precedence
|
|
|
|
|| (info1.precedence === info0.precedence && (info1.mode & OperatorMode.InfixR) === 0)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rhs = this.parseBinaryOperatorAfterExpr(rhs, info0.precedence);
|
|
|
|
}
|
|
|
|
lhs = new InfixExpression(lhs, t0, rhs);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
public parseExpression(): Expression {
|
|
|
|
const lhs = this.parseUnaryExpression();
|
2022-08-29 16:17:55 +02:00
|
|
|
return this.parseBinaryOperatorAfterExpr(lhs, 0);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
2022-09-11 11:20:21 +02:00
|
|
|
public parseTypeDeclaration(): TypeDeclaration {
|
|
|
|
let pubKeyword = null;
|
|
|
|
let t0 = this.getToken();
|
|
|
|
if (t0.kind === SyntaxKind.PubKeyword) {
|
|
|
|
pubKeyword = t0;
|
|
|
|
t0 = this.getToken();
|
|
|
|
}
|
|
|
|
if (t0.kind !== SyntaxKind.TypeKeyword) {
|
|
|
|
this.raiseParseError(t0, [ SyntaxKind.TypeKeyword ]);
|
|
|
|
}
|
|
|
|
const name = this.expectToken(SyntaxKind.IdentifierAlt);
|
|
|
|
const typeVars = [];
|
|
|
|
let t1 = this.getToken();
|
|
|
|
while (t1.kind === SyntaxKind.Identifier) {
|
|
|
|
typeVars.push(t1);
|
|
|
|
t1 = this.getToken();
|
|
|
|
}
|
|
|
|
if (t1.kind !== SyntaxKind.Equals) {
|
|
|
|
this.raiseParseError(t1, [ SyntaxKind.Equals ]);
|
|
|
|
}
|
|
|
|
const typeExpr = this.parseTypeExpression();
|
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
|
|
|
return new TypeDeclaration(pubKeyword, t0, name, typeVars, t1, typeExpr);
|
|
|
|
}
|
|
|
|
|
2022-09-10 14:11:04 +02:00
|
|
|
public parseEnumDeclaration(): EnumDeclaration {
|
|
|
|
let pubKeyword = null;
|
|
|
|
let t0 = this.getToken();
|
|
|
|
if (t0.kind == SyntaxKind.PubKeyword) {
|
|
|
|
pubKeyword = t0;
|
|
|
|
t0 = this.getToken();
|
|
|
|
}
|
|
|
|
if (t0.kind !== SyntaxKind.EnumKeyword) {
|
|
|
|
this.raiseParseError(t0, [ SyntaxKind.EnumKeyword ]);
|
|
|
|
}
|
|
|
|
const name = this.expectToken(SyntaxKind.IdentifierAlt);
|
2022-09-14 16:46:30 +02:00
|
|
|
let t1 = this.getToken();
|
|
|
|
const varExps = [];
|
|
|
|
while (t1.kind === SyntaxKind.Identifier) {
|
|
|
|
varExps.push(t1);
|
|
|
|
t1 = this.getToken();
|
|
|
|
}
|
2022-09-10 14:11:04 +02:00
|
|
|
let members = null;
|
|
|
|
if (t1.kind === SyntaxKind.BlockStart) {
|
|
|
|
members = [];
|
|
|
|
for (;;) {
|
|
|
|
const t2 = this.peekToken();
|
|
|
|
if (t2.kind === SyntaxKind.BlockEnd) {
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const name = this.expectToken(SyntaxKind.IdentifierAlt);
|
|
|
|
const t3 = this.peekToken();
|
|
|
|
let member;
|
|
|
|
if (t3.kind === SyntaxKind.BlockStart) {
|
|
|
|
this.getToken();
|
|
|
|
const members = [];
|
|
|
|
for (;;) {
|
|
|
|
const name = this.expectToken(SyntaxKind.Identifier);
|
|
|
|
const colon = this.expectToken(SyntaxKind.Colon);
|
|
|
|
const typeExpr = this.parseTypeExpression();
|
2022-09-14 16:46:30 +02:00
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
2022-09-10 14:11:04 +02:00
|
|
|
members.push(new StructDeclarationField(name, colon, typeExpr));
|
|
|
|
const t4 = this.peekToken();
|
|
|
|
if (t4.kind === SyntaxKind.BlockEnd) {
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
member = new EnumDeclarationStructElement(name, t3, members);
|
|
|
|
} else {
|
|
|
|
const typeExps = [];
|
|
|
|
for (;;) {
|
|
|
|
const t3 = this.peekToken();
|
|
|
|
if (t3.kind === SyntaxKind.LineFoldEnd) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
const typeExpr = this.parsePrimitiveTypeExpression();
|
|
|
|
typeExps.push(typeExpr);
|
|
|
|
}
|
|
|
|
member = new EnumDeclarationTupleElement(name, typeExps);
|
|
|
|
}
|
|
|
|
members.push(member);
|
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
|
|
|
}
|
2022-09-14 16:46:30 +02:00
|
|
|
t1 = this.getToken();
|
2022-09-10 14:11:04 +02:00
|
|
|
}
|
2022-09-14 16:46:30 +02:00
|
|
|
if (t1.kind !== SyntaxKind.LineFoldEnd) {
|
|
|
|
this.raiseParseError(t1, [ SyntaxKind.Identifier, SyntaxKind.BlockStart, SyntaxKind.LineFoldEnd ]);
|
|
|
|
}
|
|
|
|
return new EnumDeclaration(pubKeyword, t0, name, varExps, members);
|
2022-09-10 14:11:04 +02:00
|
|
|
}
|
|
|
|
|
2022-08-28 21:12:25 +02:00
|
|
|
public parseStructDeclaration(): StructDeclaration {
|
2022-09-10 14:11:04 +02:00
|
|
|
let pubKeyword = null;
|
|
|
|
let t0 = this.getToken();
|
|
|
|
if (t0.kind === SyntaxKind.PubKeyword) {
|
|
|
|
pubKeyword = t0;
|
|
|
|
t0 = this.getToken();
|
|
|
|
}
|
|
|
|
if (t0.kind !== SyntaxKind.StructKeyword) {
|
|
|
|
this.raiseParseError(t0, [ SyntaxKind.StructKeyword ]);
|
|
|
|
}
|
2022-09-07 12:45:38 +02:00
|
|
|
const name = this.expectToken(SyntaxKind.IdentifierAlt);
|
2022-09-10 16:52:14 +02:00
|
|
|
let t2 = this.getToken();
|
|
|
|
const typeVars = [];
|
|
|
|
while (t2.kind === SyntaxKind.Identifier) {
|
|
|
|
typeVars.push(t2);
|
|
|
|
t2 = this.getToken();
|
|
|
|
}
|
2022-08-28 21:12:25 +02:00
|
|
|
let members = null;
|
|
|
|
if (t2.kind === SyntaxKind.BlockStart) {
|
|
|
|
members = [];
|
|
|
|
for (;;) {
|
2022-09-07 12:45:38 +02:00
|
|
|
const t3 = this.peekToken();
|
|
|
|
if (t3.kind === SyntaxKind.BlockEnd) {
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
}
|
2022-08-28 21:12:25 +02:00
|
|
|
const name = this.expectToken(SyntaxKind.Identifier);
|
|
|
|
const colon = this.expectToken(SyntaxKind.Colon);
|
|
|
|
const typeExpr = this.parseTypeExpression();
|
2022-09-07 12:45:38 +02:00
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
2022-08-28 21:12:25 +02:00
|
|
|
const member = new StructDeclarationField(name, colon, typeExpr);
|
|
|
|
members.push(member);
|
|
|
|
}
|
2022-09-10 16:52:14 +02:00
|
|
|
t2 = this.getToken();
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
2022-09-10 16:52:14 +02:00
|
|
|
if (t2.kind !== SyntaxKind.LineFoldEnd) {
|
|
|
|
this.raiseParseError(t2, [ SyntaxKind.LineFoldEnd, SyntaxKind.BlockStart, SyntaxKind.Identifier ]);
|
|
|
|
}
|
|
|
|
return new StructDeclaration(pubKeyword, t0, name, typeVars, members);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
2022-08-29 16:17:55 +02:00
|
|
|
private parsePatternStartingWithConstructor() {
|
2022-09-01 20:18:47 +02:00
|
|
|
const name = this.expectToken(SyntaxKind.IdentifierAlt);
|
2022-08-29 16:17:55 +02:00
|
|
|
const t2 = this.peekToken();
|
|
|
|
if (t2.kind === SyntaxKind.LBrace) {
|
|
|
|
this.getToken();
|
|
|
|
const fields = [];
|
|
|
|
let rbrace;
|
|
|
|
for (;;) {
|
|
|
|
const t3 = this.peekToken();
|
|
|
|
if (t3.kind === SyntaxKind.RBrace) {
|
2022-09-07 12:45:38 +02:00
|
|
|
this.getToken();
|
2022-08-29 16:17:55 +02:00
|
|
|
rbrace = t3;
|
|
|
|
break;
|
|
|
|
} else if (t3.kind === SyntaxKind.Identifier) {
|
|
|
|
this.getToken();
|
|
|
|
const t4 = this.peekToken();
|
|
|
|
if (t4.kind === SyntaxKind.Equals) {
|
|
|
|
this.getToken();
|
|
|
|
const pattern = this.parsePattern();
|
2022-09-01 20:06:43 +02:00
|
|
|
fields.push(new StructPatternField(t3, t4, pattern));
|
2022-08-29 16:17:55 +02:00
|
|
|
} else {
|
2022-09-01 20:06:43 +02:00
|
|
|
fields.push(new PunnedStructPatternField(t3));
|
2022-08-29 16:17:55 +02:00
|
|
|
}
|
|
|
|
} else if (t3.kind === SyntaxKind.DotDot) {
|
|
|
|
this.getToken();
|
|
|
|
fields.push(new VariadicStructPatternElement(t3, null));
|
|
|
|
} else {
|
|
|
|
this.raiseParseError(t3, [ SyntaxKind.Identifier, SyntaxKind.DotDot ]);
|
|
|
|
}
|
|
|
|
const t5 = this.peekToken();
|
|
|
|
if (t5.kind === SyntaxKind.Comma) {
|
|
|
|
this.getToken();
|
|
|
|
} else if (t5.kind === SyntaxKind.RBrace) {
|
2022-09-07 12:45:38 +02:00
|
|
|
this.getToken();
|
2022-08-29 16:17:55 +02:00
|
|
|
rbrace = t5;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
this.raiseParseError(t5, [ SyntaxKind.Comma, SyntaxKind.RBrace ]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new StructPattern(name, t2, fields, rbrace);
|
|
|
|
} else {
|
|
|
|
const patterns = [];
|
|
|
|
for (;;) {
|
|
|
|
const t3 = this.peekToken();
|
|
|
|
if (t3.kind === SyntaxKind.RParen) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
patterns.push(this.parsePattern());
|
|
|
|
}
|
|
|
|
return new NamedTuplePattern(name, patterns);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public parseTuplePattern(): TuplePattern {
|
|
|
|
const lparen = this.expectToken(SyntaxKind.LParen);
|
|
|
|
const elements = [];
|
|
|
|
let rparen;
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind === SyntaxKind.RParen) {
|
|
|
|
rparen = t1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
elements.push(this.parsePattern());
|
|
|
|
const t2 = this.peekToken();
|
|
|
|
if (t2.kind === SyntaxKind.Comma) {
|
|
|
|
this.getToken();
|
|
|
|
} else if (t2.kind === SyntaxKind.RParen) {
|
|
|
|
rparen = t2;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
this.raiseParseError(t2, [ SyntaxKind.Comma, SyntaxKind.RParen ]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.getToken();
|
|
|
|
return new TuplePattern(lparen, elements, rparen);
|
|
|
|
}
|
|
|
|
|
2022-09-16 11:31:34 +02:00
|
|
|
public parsePrimitivePattern(): Pattern {
|
2022-08-28 21:12:25 +02:00
|
|
|
const t0 = this.peekToken();
|
|
|
|
switch (t0.kind) {
|
2022-08-29 16:17:55 +02:00
|
|
|
case SyntaxKind.LParen:
|
|
|
|
{
|
2022-09-14 16:46:30 +02:00
|
|
|
const t1 = this.peekToken(2);
|
2022-09-01 20:18:47 +02:00
|
|
|
if (t1.kind === SyntaxKind.IdentifierAlt) {
|
2022-09-09 22:37:14 +02:00
|
|
|
this.getToken();
|
2022-09-14 16:46:30 +02:00
|
|
|
const pattern = this.parsePatternStartingWithConstructor();
|
|
|
|
const t3 = this.expectToken(SyntaxKind.RParen);
|
|
|
|
return new NestedPattern(t0, pattern, t3);
|
2022-08-29 16:17:55 +02:00
|
|
|
} else {
|
|
|
|
return this.parseTuplePattern();
|
|
|
|
}
|
|
|
|
}
|
2022-09-07 12:45:38 +02:00
|
|
|
case SyntaxKind.IdentifierAlt:
|
2022-09-14 16:46:30 +02:00
|
|
|
{
|
|
|
|
this.getToken();
|
|
|
|
return new NamedTuplePattern(t0, []);
|
|
|
|
}
|
2022-08-28 21:12:25 +02:00
|
|
|
case SyntaxKind.Identifier:
|
2022-09-14 16:46:30 +02:00
|
|
|
{
|
2022-08-28 21:12:25 +02:00
|
|
|
this.getToken();
|
|
|
|
return new BindPattern(t0);
|
2022-09-14 16:46:30 +02:00
|
|
|
}
|
2022-09-16 11:31:34 +02:00
|
|
|
case SyntaxKind.StringLiteral:
|
|
|
|
case SyntaxKind.Integer:
|
|
|
|
{
|
|
|
|
this.getToken();
|
|
|
|
return new LiteralPattern(t0);
|
|
|
|
}
|
2022-08-28 21:12:25 +02:00
|
|
|
default:
|
|
|
|
this.raiseParseError(t0, [ SyntaxKind.Identifier ]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-16 11:31:34 +02:00
|
|
|
public parsePattern(): Pattern {
|
|
|
|
let result: Pattern = this.parsePrimitivePattern();
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind !== SyntaxKind.VBar) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.getToken();
|
|
|
|
const right = this.parsePrimitivePattern();
|
|
|
|
result = new DisjunctivePattern(result, t1, right);
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-28 21:12:25 +02:00
|
|
|
public parseParam(): Param {
|
|
|
|
const pattern = this.parsePattern();
|
|
|
|
return new Param(pattern);
|
|
|
|
}
|
|
|
|
|
2022-08-31 13:53:57 +02:00
|
|
|
public parseLetBodyElement(): LetBodyElement {
|
|
|
|
const t0 = this.peekTokenAfterModifiers();
|
|
|
|
switch (t0.kind) {
|
|
|
|
case SyntaxKind.LetKeyword:
|
|
|
|
return this.parseLetDeclaration();
|
|
|
|
case SyntaxKind.ReturnKeyword:
|
|
|
|
return this.parseReturnStatement();
|
2022-09-01 20:06:43 +02:00
|
|
|
case SyntaxKind.IfKeyword:
|
|
|
|
return this.parseIfStatement();
|
2022-08-31 13:53:57 +02:00
|
|
|
default:
|
|
|
|
// TODO convert parse errors to include LetKeyword and ReturnKeyword
|
|
|
|
return this.parseExpressionStatement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public parseLetDeclaration(): LetDeclaration {
|
2022-08-28 21:12:25 +02:00
|
|
|
let t0 = this.getToken();
|
|
|
|
let pubKeyword = null;
|
|
|
|
let mutKeyword = null;
|
|
|
|
if (t0.kind === SyntaxKind.PubKeyword) {
|
|
|
|
pubKeyword = t0;
|
|
|
|
t0 = this.getToken();
|
|
|
|
}
|
|
|
|
if (t0.kind !== SyntaxKind.LetKeyword) {
|
|
|
|
this.raiseParseError(t0, [ SyntaxKind.LetKeyword ]);
|
|
|
|
}
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind === SyntaxKind.MutKeyword) {
|
|
|
|
this.getToken();
|
|
|
|
mutKeyword = t1;
|
|
|
|
}
|
2022-09-09 22:37:14 +02:00
|
|
|
const t2 = this.peekToken();
|
|
|
|
const t3 = this.peekToken(2);
|
|
|
|
const t4 = this.peekToken(3);
|
|
|
|
let pattern;
|
|
|
|
if (t2.kind === SyntaxKind.LParen && t3.kind === SyntaxKind.CustomOperator && t4.kind === SyntaxKind.RParen) {
|
|
|
|
this.getToken()
|
|
|
|
this.getToken();
|
|
|
|
this.getToken();
|
|
|
|
pattern = new WrappedOperator(t2, t3, t4);
|
|
|
|
} else {
|
|
|
|
pattern = this.parsePattern();
|
|
|
|
}
|
2022-08-28 21:12:25 +02:00
|
|
|
const params = [];
|
|
|
|
for (;;) {
|
|
|
|
const t2 = this.peekToken();
|
|
|
|
if (t2.kind === SyntaxKind.Colon
|
|
|
|
|| t2.kind === SyntaxKind.BlockStart
|
|
|
|
|| t2.kind === SyntaxKind.Equals
|
|
|
|
|| t2.kind === SyntaxKind.LineFoldEnd) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
params.push(this.parseParam());
|
|
|
|
}
|
|
|
|
let typeAssert = null;
|
2022-09-09 22:37:14 +02:00
|
|
|
let t5 = this.getToken();
|
|
|
|
if (t5.kind === SyntaxKind.Colon) {
|
2022-08-28 21:12:25 +02:00
|
|
|
const typeExpression = this.parseTypeExpression();
|
2022-09-09 22:37:14 +02:00
|
|
|
typeAssert = new TypeAssert(t5, typeExpression);
|
|
|
|
t5 = this.getToken();
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
let body = null;
|
2022-09-09 22:37:14 +02:00
|
|
|
switch (t5.kind) {
|
2022-08-28 21:12:25 +02:00
|
|
|
case SyntaxKind.BlockStart:
|
|
|
|
{
|
|
|
|
const elements = [];
|
|
|
|
for (;;) {
|
|
|
|
const t4 = this.peekToken();
|
|
|
|
if (t4.kind === SyntaxKind.BlockEnd) {
|
2022-08-31 13:46:18 +02:00
|
|
|
this.getToken();
|
2022-08-28 21:12:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
elements.push(this.parseLetBodyElement());
|
|
|
|
}
|
2022-09-09 22:37:14 +02:00
|
|
|
body = new BlockBody(t5, elements);
|
|
|
|
t5 = this.getToken();
|
2022-08-28 21:12:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SyntaxKind.Equals:
|
|
|
|
{
|
|
|
|
const expression = this.parseExpression();
|
2022-09-09 22:37:14 +02:00
|
|
|
body = new ExprBody(t5, expression);
|
|
|
|
t5 = this.getToken();
|
2022-08-28 21:12:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SyntaxKind.LineFoldEnd:
|
|
|
|
break;
|
|
|
|
}
|
2022-09-09 22:37:14 +02:00
|
|
|
if (t5.kind !== SyntaxKind.LineFoldEnd) {
|
|
|
|
this.raiseParseError(t5, [ SyntaxKind.LineFoldEnd ]);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
return new LetDeclaration(
|
|
|
|
pubKeyword,
|
|
|
|
t0,
|
|
|
|
mutKeyword,
|
|
|
|
pattern,
|
|
|
|
params,
|
|
|
|
typeAssert,
|
|
|
|
body
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public parseExpressionStatement(): ExpressionStatement {
|
|
|
|
const expression = this.parseExpression();
|
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd)
|
|
|
|
return new ExpressionStatement(expression);
|
|
|
|
}
|
|
|
|
|
2022-09-01 20:06:43 +02:00
|
|
|
public parseIfStatement(): IfStatement {
|
|
|
|
const ifKeyword = this.expectToken(SyntaxKind.IfKeyword);
|
|
|
|
const test = this.parseExpression();
|
|
|
|
const blockStart = this.expectToken(SyntaxKind.BlockStart);
|
|
|
|
const elements = [];
|
|
|
|
for (;;) {
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind === SyntaxKind.BlockEnd) {
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
elements.push(this.parseLetBodyElement());
|
|
|
|
}
|
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
|
|
|
const cases = [];
|
|
|
|
cases.push(new IfStatementCase(ifKeyword, test, blockStart, elements));
|
|
|
|
for (;;) {
|
|
|
|
const t2 = this.peekToken();
|
|
|
|
if (t2.kind === SyntaxKind.ElseKeyword) {
|
|
|
|
this.getToken();
|
|
|
|
const blockStart = this.expectToken(SyntaxKind.BlockStart);
|
|
|
|
const elements = [];
|
|
|
|
for (;;) {
|
|
|
|
const t3 = this.peekToken();
|
|
|
|
if (t3.kind === SyntaxKind.BlockEnd) {
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
elements.push(this.parseLetBodyElement());
|
|
|
|
}
|
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
|
|
|
cases.push(new IfStatementCase(t2, null, blockStart, elements));
|
|
|
|
break;
|
|
|
|
} else if (t2.kind === SyntaxKind.ElifKeyword) {
|
|
|
|
this.getToken();
|
|
|
|
const test = this.parseExpression();
|
|
|
|
const blockStart = this.expectToken(SyntaxKind.BlockStart);
|
|
|
|
for (;;) {
|
|
|
|
const t4 = this.peekToken();
|
|
|
|
if (t4.kind === SyntaxKind.BlockEnd) {
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
elements.push(this.parseLetBodyElement());
|
|
|
|
}
|
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
|
|
|
cases.push(new IfStatementCase(t2, test, blockStart, elements));
|
|
|
|
} else if (t2.kind === SyntaxKind.LineFoldEnd) {
|
|
|
|
this.getToken();
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
this.raiseParseError(t2, [ SyntaxKind.ElifKeyword, SyntaxKind.ElseKeyword, SyntaxKind.LineFoldEnd ]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return new IfStatement(cases);
|
|
|
|
}
|
|
|
|
|
2022-08-31 13:53:57 +02:00
|
|
|
public parseReturnStatement(): ReturnStatement {
|
|
|
|
const returnKeyword = this.expectToken(SyntaxKind.ReturnKeyword);
|
|
|
|
let expression = null;
|
|
|
|
const t1 = this.peekToken();
|
|
|
|
if (t1.kind !== SyntaxKind.LineFoldEnd) {
|
|
|
|
expression = this.parseExpression();
|
|
|
|
}
|
|
|
|
this.expectToken(SyntaxKind.LineFoldEnd);
|
|
|
|
return new ReturnStatement(returnKeyword, expression);
|
|
|
|
}
|
|
|
|
|
2022-08-28 21:12:25 +02:00
|
|
|
public parseImportDeclaration(): ImportDeclaration {
|
|
|
|
const importKeyword = this.expectToken(SyntaxKind.ImportKeyword);
|
|
|
|
const importSource = this.expectToken(SyntaxKind.StringLiteral);
|
|
|
|
return new ImportDeclaration(importKeyword, importSource);
|
|
|
|
}
|
|
|
|
|
|
|
|
public parseSourceFileElement(): SourceFileElement {
|
|
|
|
const t0 = this.peekTokenAfterModifiers();
|
|
|
|
switch (t0.kind) {
|
|
|
|
case SyntaxKind.LetKeyword:
|
2022-08-31 13:53:57 +02:00
|
|
|
return this.parseLetDeclaration();
|
2022-08-28 21:12:25 +02:00
|
|
|
case SyntaxKind.ImportKeyword:
|
|
|
|
return this.parseImportDeclaration();
|
|
|
|
case SyntaxKind.StructKeyword:
|
|
|
|
return this.parseStructDeclaration();
|
2022-09-10 14:11:04 +02:00
|
|
|
case SyntaxKind.EnumKeyword:
|
2022-09-14 16:46:30 +02:00
|
|
|
return this.parseEnumDeclaration();
|
2022-09-11 11:20:21 +02:00
|
|
|
case SyntaxKind.TypeKeyword:
|
|
|
|
return this.parseTypeDeclaration();
|
2022-09-01 20:06:43 +02:00
|
|
|
case SyntaxKind.IfKeyword:
|
|
|
|
return this.parseIfStatement();
|
2022-08-28 21:12:25 +02:00
|
|
|
default:
|
|
|
|
return this.parseExpressionStatement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public parseSourceFile(): SourceFile {
|
|
|
|
const elements = [];
|
2022-08-29 16:17:55 +02:00
|
|
|
let eof;
|
2022-08-28 21:12:25 +02:00
|
|
|
for (;;) {
|
|
|
|
const t0 = this.peekToken();
|
|
|
|
if (t0.kind === SyntaxKind.EndOfFile) {
|
2022-08-29 16:17:55 +02:00
|
|
|
eof = t0;
|
2022-08-28 21:12:25 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
const element = this.parseSourceFileElement();
|
|
|
|
elements.push(element);
|
|
|
|
}
|
2022-08-31 13:29:56 +02:00
|
|
|
return new SourceFile(this.file, elements, eof);
|
2022-08-28 21:12:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|