|
|
|
@ -22,6 +22,14 @@ export class Parser {
|
|
|
|
return this.tokens[this.pos++];
|
|
|
|
return this.tokens[this.pos++];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private peek(offset = 1): Token {
|
|
|
|
|
|
|
|
const pos = this.pos + offset;
|
|
|
|
|
|
|
|
if (pos >= this.tokens.length) {
|
|
|
|
|
|
|
|
return { kind: 'eof' } as Token;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.tokens[pos];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private expect(kind: Token['kind']): Token {
|
|
|
|
private expect(kind: Token['kind']): Token {
|
|
|
|
const token = this.current();
|
|
|
|
const token = this.current();
|
|
|
|
|
|
|
|
|
|
|
|
@ -65,9 +73,24 @@ export class Parser {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private parseExpression(): AST {
|
|
|
|
private parseExpression(): AST {
|
|
|
|
|
|
|
|
if (this.current().kind === 'ident' && this.peek().kind === 'equals') {
|
|
|
|
|
|
|
|
return this.parseLet();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return this.parseInfix();
|
|
|
|
return this.parseInfix();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private parseLet(): AST {
|
|
|
|
|
|
|
|
const nameToken = this.expect('ident');
|
|
|
|
|
|
|
|
const name = (nameToken as { value: string }).value;
|
|
|
|
|
|
|
|
this.expect('equals');
|
|
|
|
|
|
|
|
const value = this.parseInfix();
|
|
|
|
|
|
|
|
this.expect('semicolon');
|
|
|
|
|
|
|
|
const body = this.parseExpression();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { kind: 'let', name, value, body };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private parseInfix(): AST {
|
|
|
|
private parseInfix(): AST {
|
|
|
|
let left = this.parseApplication();
|
|
|
|
let left = this.parseApplication();
|
|
|
|
|
|
|
|
|
|
|
|
@ -177,47 +200,6 @@ export class Parser {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
private parseMultiplicative(): AST {
|
|
|
|
|
|
|
|
let left = this.parsePostfix();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (this.current().kind === 'star' || this.current().kind === 'slash') {
|
|
|
|
|
|
|
|
const op = this.current().kind === 'star' ? '*' : '/';
|
|
|
|
|
|
|
|
this.advance();
|
|
|
|
|
|
|
|
const right = this.parsePostfix();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
left = { kind: 'binaryop', operator: op, left, right };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return left;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private parseAdditive(): AST {
|
|
|
|
|
|
|
|
let left = this.parseMultiplicative();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (this.current().kind === 'plus' || this.current().kind === 'minus') {
|
|
|
|
|
|
|
|
const op = this.current().kind === 'plus' ? '+' : '-';
|
|
|
|
|
|
|
|
this.advance();
|
|
|
|
|
|
|
|
const right = this.parseMultiplicative();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
left = { kind: 'binaryop', operator: op, left, right };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return left;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private parseLet(): AST {
|
|
|
|
|
|
|
|
this.expect('let');
|
|
|
|
|
|
|
|
const nameToken = this.expect('ident');
|
|
|
|
|
|
|
|
const name = (nameToken as { value: string }).value;
|
|
|
|
|
|
|
|
this.expect('equals');
|
|
|
|
|
|
|
|
const value = this.parseExpression();
|
|
|
|
|
|
|
|
this.expect('in');
|
|
|
|
|
|
|
|
const body = this.parseExpression();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return { kind: 'let', name, value, body };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private parseLambda(): AST {
|
|
|
|
private parseLambda(): AST {
|
|
|
|
this.expect('open-paren');
|
|
|
|
this.expect('open-paren');
|
|
|
|
|
|
|
|
|
|
|
|
|