parsing lambdas
This commit is contained in:
parent
0f0371461d
commit
6e8b5afd3b
3 changed files with 43 additions and 52 deletions
|
|
@ -154,6 +154,10 @@ export function prettyPrint(ast: AST, indent = 0): string {
|
||||||
.join(', ');
|
.join(', ');
|
||||||
return `${i}{${fields}}`;
|
return `${i}{${fields}}`;
|
||||||
|
|
||||||
|
case 'lambda':
|
||||||
|
const params = ast.params.join(', ')
|
||||||
|
return `${i}(${params}) => ${prettyPrint(ast.body)}`
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return `${i}${ast.kind}`
|
return `${i}${ast.kind}`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ console.log(tokenize(str));
|
||||||
// const tokens2 = tokenize("let x = (y) => 5 + y in x(3)");
|
// const tokens2 = tokenize("let x = (y) => 5 + y in x(3)");
|
||||||
// const tokens2 = tokenize("let x = 5 in x * 4");
|
// const tokens2 = tokenize("let x = 5 in x * 4");
|
||||||
// const tokens2 = tokenize("(x, y) => x + y");
|
// const tokens2 = tokenize("(x, y) => x + y");
|
||||||
const tokens2 = tokenize('x = (y = 1; y + 1); x * 2');
|
const tokens2 = tokenize(`a b \\ a + b`);
|
||||||
const p2 = new Parser(tokens2);
|
const p2 = new Parser(tokens2);
|
||||||
const ast3 = p2.parse();
|
const ast3 = p2.parse();
|
||||||
console.log(ast3);
|
console.log(ast3);
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,35 @@ export class Parser {
|
||||||
kind === 'open-brace';
|
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 {
|
parse(): AST {
|
||||||
return this.parseExpression();
|
return this.parseExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseExpression(): AST {
|
private parseExpression(): AST {
|
||||||
|
if (this.isLambdaStart()) {
|
||||||
|
return this.parseLambda();
|
||||||
|
}
|
||||||
|
|
||||||
if (this.current().kind === 'ident' && this.peek().kind === 'equals') {
|
if (this.current().kind === 'ident' && this.peek().kind === 'equals') {
|
||||||
return this.parseLet();
|
return this.parseLet();
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +104,20 @@ export class Parser {
|
||||||
return this.parseInfix();
|
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 {
|
private parseLet(): AST {
|
||||||
const nameToken = this.expect('ident');
|
const nameToken = this.expect('ident');
|
||||||
const name = (nameToken as { value: string }).value;
|
const name = (nameToken as { value: string }).value;
|
||||||
|
|
@ -198,55 +236,4 @@ export class Parser {
|
||||||
|
|
||||||
throw new Error(`Unexpected token: ${token.kind}`);
|
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;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue