Add support for AssignStatement in lexical analysis and CST

This commit is contained in:
Sam Vervaeck 2023-03-19 17:02:59 +01:00
parent af996c13fe
commit 1b918dcaf0
3 changed files with 70 additions and 2 deletions

View file

@ -168,6 +168,7 @@ export const enum SyntaxKind {
ReturnStatement, ReturnStatement,
ExpressionStatement, ExpressionStatement,
IfStatement, IfStatement,
AssignStatement,
// If statement elements // If statement elements
IfStatementCase, IfStatementCase,
@ -2235,6 +2236,36 @@ export class ReturnStatement extends SyntaxBase {
} }
export class AssignStatement extends SyntaxBase {
public readonly kind = SyntaxKind.AssignStatement;
public constructor(
public pattern: Pattern,
public operator: Assignment,
public expression: Expression,
) {
super();
}
public clone(): AssignStatement {
return new AssignStatement(
this.pattern.clone(),
this.operator.clone(),
this.expression.clone()
);
}
public getFirstToken(): Token {
return this.pattern.getFirstToken();
}
public getLastToken(): Token {
return this.expression.getLastToken();
}
}
export class ExpressionStatement extends SyntaxBase { export class ExpressionStatement extends SyntaxBase {
public readonly kind = SyntaxKind.ExpressionStatement; public readonly kind = SyntaxKind.ExpressionStatement;
@ -2263,6 +2294,7 @@ export type Statement
= ReturnStatement = ReturnStatement
| ExpressionStatement | ExpressionStatement
| IfStatement | IfStatement
| AssignStatement
export class Param extends SyntaxBase { export class Param extends SyntaxBase {

View file

@ -66,6 +66,7 @@ import {
ClassKeyword, ClassKeyword,
InstanceDeclaration, InstanceDeclaration,
ClassConstraintClause, ClassConstraintClause,
AssignStatement,
} from "./cst" } from "./cst"
import { Stream } from "./util"; import { Stream } from "./util";
@ -782,6 +783,27 @@ export class Parser {
return new Param(pattern); return new Param(pattern);
} }
private lookaheadIsAssignment(): boolean {
for (let i = 1;; i++) {
const t0 = this.peekToken(i);
switch (t0.kind) {
case SyntaxKind.LineFoldEnd:
case SyntaxKind.BlockStart:
return false;
case SyntaxKind.Assignment:
return true;
}
}
}
public parseAssignStatement(): AssignStatement {
const pattern = this.parsePattern();
const operator = this.expectToken(SyntaxKind.Assignment);
const expression = this.parseExpression();
this.expectToken(SyntaxKind.LineFoldEnd);
return new AssignStatement(pattern, operator, expression);
}
public parseLetBodyElement(): LetBodyElement { public parseLetBodyElement(): LetBodyElement {
const t0 = this.peekTokenAfterModifiers(); const t0 = this.peekTokenAfterModifiers();
switch (t0.kind) { switch (t0.kind) {
@ -792,6 +814,9 @@ export class Parser {
case SyntaxKind.IfKeyword: case SyntaxKind.IfKeyword:
return this.parseIfStatement(); return this.parseIfStatement();
default: default:
if (this.lookaheadIsAssignment()) {
return this.parseAssignStatement();
}
// TODO convert parse errors to include LetKeyword and ReturnKeyword // TODO convert parse errors to include LetKeyword and ReturnKeyword
return this.parseExpressionStatement(); return this.parseExpressionStatement();
} }
@ -1165,6 +1190,9 @@ export class Parser {
case SyntaxKind.IfKeyword: case SyntaxKind.IfKeyword:
return this.parseIfStatement(); return this.parseIfStatement();
default: default:
if (this.lookaheadIsAssignment()) {
return this.parseAssignStatement();
}
return this.parseExpressionStatement(); return this.parseExpressionStatement();
} }
} }

View file

@ -229,7 +229,15 @@ export class Scanner extends BufferedStream<Token> {
case '{': return new LBrace(startPos); case '{': return new LBrace(startPos);
case '}': return new RBrace(startPos); case '}': return new RBrace(startPos);
case ',': return new Comma(startPos); case ',': return new Comma(startPos);
case ':': return new Colon(startPos); case ':':
const text = this.takeWhile(isOperatorPart);
if (text === '') {
return new Colon(startPos);
} else if (text === '=') {
return new Assignment(':', startPos);
} else {
throw new ScanError(this.file, startPos, ':' + text);
}
case '.': { case '.': {
const dots = c0 + this.takeWhile(ch => ch === '.'); const dots = c0 + this.takeWhile(ch => ch === '.');
if (dots === '.') { if (dots === '.') {
@ -266,7 +274,7 @@ export class Scanner extends BufferedStream<Token> {
} else if (text === '=') { } else if (text === '=') {
return new Equals(startPos); return new Equals(startPos);
} else if (text.endsWith('=') && text[text.length-2] !== '=') { } else if (text.endsWith('=') && text[text.length-2] !== '=') {
return new Assignment(text, startPos); return new Assignment(text.substring(0, text.length-1), startPos);
} else { } else {
return new CustomOperator(text, startPos); return new CustomOperator(text, startPos);
} }