import { TokenStream, SyntaxKind, Syntax, SourceFile, Decl, Statement } from "./ast" import { Parser, ParseError } from "./parser" type Transformer = (tokens: TokenStream) => Syntax; export class Expander { transformers = new Map(); constructor(public parser: Parser) { this.transformers.set('fn', parser.parseFuncDecl.bind(parser)) this.transformers.set('foreign', parser.parseFuncDecl.bind(parser)) this.transformers.set('let', parser.parseVarDecl.bind(parser)) this.transformers.set('return', parser.parseRetStmt.bind(parser)) } getFullyExpanded(node: Syntax): Syntax { if (node.kind === SyntaxKind.SourceFile) { const expanded: (Decl | Statement)[] = []; for (const element of node.elements) { if (element.kind === SyntaxKind.Sentence) { const newElement = this.getFullyExpanded(element) expanded.push(newElement as Decl | Statement) } } return new SourceFile(expanded, null, node); } else if (node.kind === SyntaxKind.Sentence) { while (true) { console.log('expanding sententce') const tokens: TokenStream = node.toTokenStream() const t0 = tokens.peek(); if (t0.kind !== SyntaxKind.Identifier) { throw new ParseError(t0, [SyntaxKind.Identifier]); } if (!this.transformers.has(t0.text)) { return this.parser.parseCallExpr(tokens) } node = this.transformers.get(t0.text)!(tokens) if (node.kind !== SyntaxKind.Sentence) { break; } } return node } else { throw new Error(`unrecognised node of kind ${node.kind}`) } } }