|
|
|
|
@ -68,11 +68,35 @@ export class Parser {
|
|
|
|
|
kind === 'open-brace';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private isLambdaStart(): boolean {
|
|
|
|
|
const kind = this.current().kind;
|
|
|
|
|
|
|
|
|
|
if (kind === 'backslash') {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (kind !== 'ident') {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let offset = 1;
|
|
|
|
|
while (true) {
|
|
|
|
|
const token = this.peek(offset);
|
|
|
|
|
if (token.kind === 'backslash') return true;
|
|
|
|
|
if (token.kind !== 'ident') return false;
|
|
|
|
|
offset++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parse(): AST {
|
|
|
|
|
return this.parseExpression();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private parseExpression(): AST {
|
|
|
|
|
if (this.isLambdaStart()) {
|
|
|
|
|
return this.parseLambda();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.current().kind === 'ident' && this.peek().kind === 'equals') {
|
|
|
|
|
return this.parseLet();
|
|
|
|
|
}
|
|
|
|
|
@ -80,6 +104,20 @@ export class Parser {
|
|
|
|
|
return this.parseInfix();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private parseLambda(): AST {
|
|
|
|
|
const params: string[] = [];
|
|
|
|
|
|
|
|
|
|
while (this.current().kind === 'ident') {
|
|
|
|
|
const param = this.advance();
|
|
|
|
|
params.push((param as { value: string }).value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.expect('backslash');
|
|
|
|
|
const body = this.parseExpression();
|
|
|
|
|
|
|
|
|
|
return { kind: 'lambda', params, body };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private parseLet(): AST {
|
|
|
|
|
const nameToken = this.expect('ident');
|
|
|
|
|
const name = (nameToken as { value: string }).value;
|
|
|
|
|
@ -198,55 +236,4 @@ export class Parser {
|
|
|
|
|
|
|
|
|
|
throw new Error(`Unexpected token: ${token.kind}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
private parseLambda(): AST {
|
|
|
|
|
this.expect('open-paren');
|
|
|
|
|
|
|
|
|
|
const params: string[] = [];
|
|
|
|
|
|
|
|
|
|
if (this.current().kind !== 'close-paren') {
|
|
|
|
|
const first = this.expect('ident');
|
|
|
|
|
params.push((first as { value: string }).value);
|
|
|
|
|
|
|
|
|
|
while (this.current().kind === 'comma') {
|
|
|
|
|
this.advance();
|
|
|
|
|
const param = this.expect('ident');
|
|
|
|
|
params.push((param as { value: string }).value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.expect('close-paren');
|
|
|
|
|
this.expect('arrow');
|
|
|
|
|
|
|
|
|
|
const body = this.parseExpression();
|
|
|
|
|
|
|
|
|
|
return { kind: 'lambda', params, body }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private parsePostfix(): AST {
|
|
|
|
|
let expr = this.parsePrimary();
|
|
|
|
|
|
|
|
|
|
while (this.current().kind === 'open-paren') {
|
|
|
|
|
this.advance();
|
|
|
|
|
|
|
|
|
|
const args: AST[] = [];
|
|
|
|
|
if (this.current().kind !== 'close-paren') {
|
|
|
|
|
args.push(this.parseExpression());
|
|
|
|
|
|
|
|
|
|
while (this.current().kind === 'comma') {
|
|
|
|
|
this.advance();
|
|
|
|
|
args.push(this.parseExpression());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.expect('close-paren');
|
|
|
|
|
|
|
|
|
|
expr = { kind: 'apply', func: expr, args };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return expr;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|