Add support for AssignStatement in lexical analysis and CST
This commit is contained in:
parent
af996c13fe
commit
1b918dcaf0
3 changed files with 70 additions and 2 deletions
32
src/cst.ts
32
src/cst.ts
|
@ -168,6 +168,7 @@ export const enum SyntaxKind {
|
|||
ReturnStatement,
|
||||
ExpressionStatement,
|
||||
IfStatement,
|
||||
AssignStatement,
|
||||
|
||||
// If statement elements
|
||||
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 {
|
||||
|
||||
public readonly kind = SyntaxKind.ExpressionStatement;
|
||||
|
@ -2263,6 +2294,7 @@ export type Statement
|
|||
= ReturnStatement
|
||||
| ExpressionStatement
|
||||
| IfStatement
|
||||
| AssignStatement
|
||||
|
||||
export class Param extends SyntaxBase {
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ import {
|
|||
ClassKeyword,
|
||||
InstanceDeclaration,
|
||||
ClassConstraintClause,
|
||||
AssignStatement,
|
||||
} from "./cst"
|
||||
import { Stream } from "./util";
|
||||
|
||||
|
@ -782,6 +783,27 @@ export class Parser {
|
|||
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 {
|
||||
const t0 = this.peekTokenAfterModifiers();
|
||||
switch (t0.kind) {
|
||||
|
@ -792,6 +814,9 @@ export class Parser {
|
|||
case SyntaxKind.IfKeyword:
|
||||
return this.parseIfStatement();
|
||||
default:
|
||||
if (this.lookaheadIsAssignment()) {
|
||||
return this.parseAssignStatement();
|
||||
}
|
||||
// TODO convert parse errors to include LetKeyword and ReturnKeyword
|
||||
return this.parseExpressionStatement();
|
||||
}
|
||||
|
@ -1165,6 +1190,9 @@ export class Parser {
|
|||
case SyntaxKind.IfKeyword:
|
||||
return this.parseIfStatement();
|
||||
default:
|
||||
if (this.lookaheadIsAssignment()) {
|
||||
return this.parseAssignStatement();
|
||||
}
|
||||
return this.parseExpressionStatement();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -229,7 +229,15 @@ export class Scanner extends BufferedStream<Token> {
|
|||
case '{': return new LBrace(startPos);
|
||||
case '}': return new RBrace(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 '.': {
|
||||
const dots = c0 + this.takeWhile(ch => ch === '.');
|
||||
if (dots === '.') {
|
||||
|
@ -266,7 +274,7 @@ export class Scanner extends BufferedStream<Token> {
|
|||
} else if (text === '=') {
|
||||
return new Equals(startPos);
|
||||
} else if (text.endsWith('=') && text[text.length-2] !== '=') {
|
||||
return new Assignment(text, startPos);
|
||||
return new Assignment(text.substring(0, text.length-1), startPos);
|
||||
} else {
|
||||
return new CustomOperator(text, startPos);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue