From 8b610f2bcfc223333254ce9679730c42dce6d26e Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Mon, 3 Nov 2025 23:41:31 -0800 Subject: add createFn --- src/lang/js-lang/core/parser.ts | 132 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 src/lang/js-lang/core/parser.ts (limited to 'src/lang/js-lang/core/parser.ts') diff --git a/src/lang/js-lang/core/parser.ts b/src/lang/js-lang/core/parser.ts new file mode 100644 index 0000000..f193d6a --- /dev/null +++ b/src/lang/js-lang/core/parser.ts @@ -0,0 +1,132 @@ +import { Token, Parse, TokenType, ASTNode, NodeType } from "../../ts-lang"; +import { lex } from "./lexer"; + +const resolveNodeFromToken = (token: Token): ASTNode => { + // FIXME not correct + if (!isNaN(Number(token.name))) { + return { + type: NodeType.INT, + name: "", + value: Number(token.name), + children: [], + }; + } + if (token.name[0] === '"' && token.name[token.name.length - 1] === '"') { + return { + type: NodeType.INT, + name: "", + value: token.name.slice(1, token.name.length - 1), + children: [], + }; + } + return { + type: NodeType.EXT, + name: token.name, + value: null, + children: [], + }; +}; + +const _parse = ({ + remainingTokens, + lastToken, + stack, +}: { + remainingTokens: Token[]; + lastToken: Token | null; + stack: ASTNode[]; +}): ASTNode | null => { + const head = remainingTokens.shift(); + if (!head) { + if (lastToken) { + (stack[stack.length - 1].children as ASTNode[]).push( + resolveNodeFromToken(lastToken) + ); + + return _parse({ + lastToken: null, + remainingTokens: [], + stack, + }); + } + + return stack[0] ?? null; + } + + if (lastToken) { + if (head.type === TokenType.NAME) { + (stack[stack.length - 1].children as ASTNode[]).push( + resolveNodeFromToken(lastToken) + ); + return _parse({ + lastToken: head, + remainingTokens, + stack, + }); + } + + if (head.type === TokenType.CLOSE_PAREN) { + const top = stack.pop()!; + (top.children as ASTNode[]).push(resolveNodeFromToken(lastToken)); + (stack[stack.length - 1].children as ASTNode[]).push(top); + + return _parse({ + lastToken: null, + remainingTokens, + stack, + }); + } + + if (head.type === TokenType.OPEN_PAREN) { + return _parse({ + lastToken: null, + remainingTokens, + stack: [...stack, resolveNodeFromToken(lastToken)], + }); + } + + throw new Error( + `${JSON.stringify({ + lastToken, + remainingTokens, + stack, + })} Was not expecting ${head.type}` + ); + } + + if (head.type === TokenType.NAME) { + return _parse({ + lastToken: head, + remainingTokens, + stack, + }); + } + + if (head.type === TokenType.CLOSE_PAREN) { + const top = stack.pop()!; + (stack[stack.length - 1].children as ASTNode[]).push(top); + + return _parse({ + lastToken: null, + remainingTokens, + stack, + }); + } + + throw new Error( + `${JSON.stringify({ + lastToken, + remainingTokens, + stack, + })} Expected nextToken to be a name or close paren at ${head.type}` + ); +}; + +export const parse = ( + raw: Raw +): Parse => + _parse({ + remainingTokens: raw as unknown as Token[], + lastToken: null, + stack: [{ type: NodeType.EXT, name: "arr", value: null, children: [] }], + }) as Parse; -- cgit v1.2.3-70-g09d2