import { ASTNode, NodeType, ParserCtx, Token, TokenType } from "./common"; import { IsWhitespace, Lex } from "./lexer"; /* start if no 'lastName' then: expect nextToken to be a name lastName = nextToken goto start else: if nextToken is name then: // we already have a lastName mutate last element of stack to push lastName as child lastName = nextToken goto start else: //nextToken is openParen or close paren if nextToken is closeParen then: set last element of stack as child of prev element on stack pop stack // [stack[last - 1].children.push(stack.pop) goto start else if nextToken is openParen: push lastName onto stack goto start finally: // only one element remains on the stack return stack[0] CALL ( param, CALL2 ( param2 ) ) param2 ret call2 param ret call | call |-- param |-- | call2 |-- param2 */ export type Error = ASTNode; export type PushChild = { type: Node["type"]; name: Node["name"]; children: [...Node["children"], Child]; }; export type PushChildToLastElementOfStack< Stack extends ParserCtx["stack"], Child extends ASTNode > = Stack extends [...infer Head, infer Tail extends ASTNode] ? [...Head, PushChild] : Stack extends [infer Only extends ASTNode] ? [PushChild] : never; export type PushChildToSecondLastElementOfStack< Stack extends ParserCtx["stack"], Child extends ASTNode > = Stack extends [ ...infer Head, infer Tail extends ASTNode, infer Final extends ASTNode ] ? [...Head, PushChild, Final] : Stack extends [infer Only extends ASTNode, infer Final extends ASTNode] ? [PushChild, Final] : never; export type GetLastOnStack = Stack extends [ ...infer Head, infer Tail extends ASTNode ] ? Tail : Stack extends [infer Only extends ASTNode] ? Only : never; export type StackWithoutLast = Stack extends [ ...infer Head extends ASTNode[], infer Tail ] ? [...Head] : Stack extends [infer Only extends ASTNode] ? [] : never; export type _Parse = Ctx["remainingTokens"] extends [ infer Head extends Token, ...infer Tail extends readonly Token[] ] ? Ctx["lastName"] extends string ? Head["type"] extends TokenType.UNIQUE_SYMBOL ? // we already have a lastName // mutate last element of stack to push lastName as child // lastName = nextToken // goto start _Parse<{ lastName: Head["name"]; remainingTokens: Tail; stack: PushChildToLastElementOfStack< Ctx["stack"], ASTNode >; }> : //nextToken is openParen or close paren Head["type"] extends TokenType.CLOSE_PAREN ? // handle lastName // set last element of stack as child of prev element on stack // pop stack // [stack[last - 1].children.push(stack.pop) // goto start _Parse<{ lastName: null; remainingTokens: Tail; // first push the last name onto the children of the top // then push the top onto the children of the next // then remove the top stack: StackWithoutLast< PushChildToSecondLastElementOfStack< Ctx["stack"], PushChild< GetLastOnStack, ASTNode > > >; }> : Head["type"] extends TokenType.OPEN_PAREN ? // push lastName onto stack // goto start _Parse<{ lastName: null; remainingTokens: Tail; stack: [...Ctx["stack"], ASTNode]; }> : Ctx & Error<`Was not expecting ${Head["type"]}`> : // expect nextToken to be a name or close paren Head["type"] extends TokenType.UNIQUE_SYMBOL ? // lastName = nextToken // goto start _Parse<{ lastName: Head["name"]; remainingTokens: Tail; stack: Ctx["stack"]; }> : Head["type"] extends TokenType.CLOSE_PAREN ? _Parse<{ lastName: null; remainingTokens: Tail; // push the top onto the children of the next // then remove the top stack: StackWithoutLast< PushChildToSecondLastElementOfStack< Ctx["stack"], GetLastOnStack > >; }> : Ctx & Error<`Expected nextToken to be a name or close paren at ${Head["type"]}`> : Ctx["stack"]; // v1 // ? Ctx["isCollecting"] extends true // ? Head["type"] extends TokenType.CLOSE_PAREN // ? "return" // : Head["type"] extends TokenType.UNIQUE_SYMBOL // ? _Parse<{ // remainingTokens: Tail; // isCollecting: true; // name: Ctx["name"]; // // fuck, how to do this without advancing seek pointer?? // ret: [...Ctx["ret"], ASTNode; // }> // : Error<"Expected another name, or `)`"> // : Head["type"] extends TokenType.OPEN_PAREN // ? _Parse<{ // remainingTokens: Tail; // isCollecting: true; // name: Ctx["name"]; // ret: Ctx["ret"]; // }> // : Error<"Expected open paren"> // : Ctx["ret"]; //v2 // ? Ctx["previousName"] extends null // ? Head["type"] extends TokenType.UNIQUE_SYMBOL // ? _Parse<{ remainingTokens: Tail; previousName: Head; node: Ctx["node"] }> // : ASTNode // : IsWhitespace<`${Head["type"]}`> extends true // ? ASTNode // : ASTNode // : Ctx["node"]; export type Parse = _Parse<{ lastName: null; remainingTokens: Raw; stack: [ASTNode]; }>; const a = "a" as any as Parse>;