diff --git a/src/lang/recast.test.ts b/src/lang/recast.test.ts new file mode 100644 index 000000000..1424d30d7 --- /dev/null +++ b/src/lang/recast.test.ts @@ -0,0 +1,25 @@ +import { recast } from "./recast"; +import { Program } from "./abstractSyntaxTree"; +import { abstractSyntaxTree } from "./abstractSyntaxTree"; +import { lexer } from "./tokeniser"; +import { Token } from "./tokeniser"; + +describe("recast", () => { + it("recasts a simple program", () => { + const code = "1 + 2"; + const {ast, tokens } = code2ast(code); + const recasted = recast(ast); + expect(recasted).toBe(code); + }); +}); + +// helpers + +function code2ast(code: string): { ast: Program; tokens: Token[]} { + const tokens = lexer(code); + const ast = abstractSyntaxTree(tokens); + return { + ast, + tokens + } +} diff --git a/src/lang/recast.ts b/src/lang/recast.ts new file mode 100644 index 000000000..39bb342bc --- /dev/null +++ b/src/lang/recast.ts @@ -0,0 +1,27 @@ +import { Program, BinaryExpression, BinaryPart } from "./abstractSyntaxTree"; + +export function recast(ast: Program, previousWrittenCode = ''): string { + return ast.body + .map((statement) => { + if(statement.type === "ExpressionStatement") { + if(statement.expression.type === "BinaryExpression") { + return recastBinaryExpression(statement.expression); + } + } + return statement.type; + }) + .join("\n"); +} + +function recastBinaryExpression(expression: BinaryExpression): string { + return `${recastBinaryPart(expression.left)} ${expression.operator} ${recastBinaryPart(expression.right)}` +} + +function recastBinaryPart(part: BinaryPart): string { + if(part.type === "Literal") { + return String(part?.value); + } else if(part.type === "Identifier") { + return part.name; + } + throw new Error(`Cannot recast ${part}`); +}