Skip to content

Commit 9bd3ee1

Browse files
committed
prototype parsing ANF if-then-else
1 parent 50abc97 commit 9bd3ee1

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

proto/anf_parser.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -293,16 +293,34 @@ function call(tokens: readonly Token[]): [(undefined | ParseError), (undefined |
293293
}
294294

295295
function if_then_else(tokens: readonly Token[]): [(undefined | ParseError), (undefined | _IfThenElse), Token[]] {
296-
const [first, ...rest] = tokens;
296+
let error: undefined | ParseError = undefined;
297+
let ast: undefined | _Binding | _Atomic | _Call = undefined;
298+
const first = tokens[0];
299+
let [...rest] = tokens;
300+
let condition: undefined | _Atomic;
301+
let then_branch: undefined | _Block;
302+
let else_branch: undefined | _Block;
297303

298-
// TODO
299-
// _IfThenElse = {token: number, tag: '_IfThenElse', condition: _Atomic, then_branch: _Block, else_branch: _Block};
304+
[error, ast, rest] = consume(rest, 'IF');
305+
if (error) return [error, ast, [...tokens]];
300306

301-
return [{
302-
tag: 'ParseError',
303-
token: first.id,
304-
message: `Expected ?????. Got '${first.value}' of type '${first.lexeme}' instead.`,
305-
}, undefined, [...tokens]];
307+
[error, condition, rest] = atomic(rest);
308+
if (error) return [error, ast, [...tokens]];
309+
310+
[error, ast, rest] = consume(rest, 'THEN');
311+
if (error) return [error, ast, [...tokens]];
312+
313+
[error, then_branch, rest] = block(rest);
314+
if (error) return [error, ast, [...tokens]];
315+
316+
[error, ast, rest] = consume(rest, 'ELSE');
317+
if (error) return [error, ast, [...tokens]];
318+
319+
[error, else_branch, rest] = block(rest);
320+
if (error) return [error, ast, [...tokens]];
321+
322+
const result: _IfThenElse = { token: first.id, tag: '_IfThenElse', condition: (condition as _Atomic), then_branch: (then_branch as _Block), else_branch: (else_branch as _Block) };
323+
return [undefined, result, rest];
306324
}
307325

308326
function binding(tokens: readonly Token[]): [(undefined | ParseError), (undefined | _Binding), Token[]] {

test/proto_anf_parser.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,18 @@ describe('expressions', () => {
131131
expect(ast.tail.arg.tag).toBe("_Number");
132132
expect(ast.tail.arg.value).toBe(2);
133133
});
134+
135+
it('must produce a valid AST for a simple if expression', () => {
136+
const tokens = lex("(if true then (42) else (0))");
137+
const ast = parse(tokens);
138+
expect(ast.tag).toBe("_Block");
139+
expect(ast.tail.tag).toBe("_IfThenElse");
140+
expect(ast.tail.condition.tag).toBe("_Boolean");
141+
expect(ast.tail.then_branch.tag).toBe("_Block");
142+
expect(ast.tail.then_branch.tail.tag).toBe("_Number");
143+
expect(ast.tail.then_branch.tail.value).toBe(42);
144+
expect(ast.tail.else_branch.tag).toBe("_Block");
145+
expect(ast.tail.else_branch.tail.tag).toBe("_Number");
146+
expect(ast.tail.else_branch.tail.value).toBe(0);
147+
});
134148
});

0 commit comments

Comments
 (0)