{"id":16017653,"url":"https://github.com/zackradisic/typelalr","last_synced_at":"2025-10-10T12:32:46.718Z","repository":{"id":185099022,"uuid":"522223967","full_name":"zackradisic/typelalr","owner":"zackradisic","description":"A very stupid experiment: LALR(1) lexer/parser generators for type-level Typescript","archived":false,"fork":false,"pushed_at":"2022-11-17T12:48:45.000Z","size":103,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-10T12:32:20.311Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zackradisic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-08-07T13:42:34.000Z","updated_at":"2025-05-14T03:49:30.000Z","dependencies_parsed_at":"2023-07-31T18:08:47.912Z","dependency_job_id":null,"html_url":"https://github.com/zackradisic/typelalr","commit_stats":null,"previous_names":["zackradisic/typelalr"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/zackradisic/typelalr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackradisic%2Ftypelalr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackradisic%2Ftypelalr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackradisic%2Ftypelalr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackradisic%2Ftypelalr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zackradisic","download_url":"https://codeload.github.com/zackradisic/typelalr/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zackradisic%2Ftypelalr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279003897,"owners_count":26083641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-08T16:21:20.783Z","updated_at":"2025-10-10T12:32:46.702Z","avatar_url":"https://github.com/zackradisic.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"## **typelalr** - a very stupid experiment\n\nType-level lexer/parser generators for Typescript. Aka a really bad idea.\n\n## What is this?\n\nThis is a Rust program that generates type-level tokenizers and parsers for Typescript. The lexers support regex and the parsers work on LALR(1) grammars. In theory this will allow you to generate lexers/parsers for any LALR(1) grammar that can run in Typescript's type system, for example one that resembles a programming language (see the Lisp example below).\n\n## Why\n\nThere are some wacky projects implemented entirely within Typescript's type system like: [Hypescript](https://github.com/ronami/HypeScript) (a minimal implementation of Typescript) or [ts-sql](https://github.com/codemix/ts-sql) (an SQL database). All of these require lexing and parsing some grammar (ex/ Typescript code or SQL).\n\nIf you want to build something similar you'll need to write a lexer or parser by hand, which is no fun, lexer/parser generators alleviate you from that problem. So I whipped out the Dragon Book and started hacking on this very stupid idea.\n\n## How does it work?\n\nYou write your grammar in a Typescript-esque language like so:\n\n```typescript\n// basic_lisp.tlalr\n\nexport start SExpr: ({ kind: \"sexpr\", exprs: Expr[] }) = [\n    \"(\" \u003cexprs: Exprs\u003e \")\" =\u003e ({ kind: \"sexpr\", exprs })\n]\n\nexport Exprs: (Expr[]) = [\n    \u003ce1: Expr\u003e \u003ce2: Exprs\u003e =\u003e ([e1, ...e2]),\n    \u003ce: Expr\u003e =\u003e ([e])\n]\n\nexport Expr: () = [\n    \u003cint: Int\u003e =\u003e ({ kind: \"expr\", value: int }),\n    \u003csym: Symbol\u003e =\u003e ({ kind: \"expr\", value: sym }),\n]\n\nexport Int: ({ kind: \"int\", int: number }) = [\n    \u003cint: r\"[1-9][0-9]*\"\u003e =\u003e ({ kind: \"int\", int: parseInt(int) })\n]\n\nexport Symbol: ({ kind: \"sym\", sym: string }) = [\n    \u003csym: r\"[^() ]*\"\u003e =\u003e ({ kind: \"sym\", sym })\n]\n```\n\nRunning the Rust program will generate Typescript types containing the DFA state machine to lex the input, and the parsing tables and parser to parse the tokens. Then you can import it and use it like so:\n\n```typescript\nimport { Lex } from \"./lexer.gen.ts\";\nimport { Parse } from \"./parser.gen.ts\";\n\n// Tokens result:\n// [\n//   { kind: \"(\", value: \"(\" },\n//   { kind: \"sym\", value: \"add\" },\n//   { kind: \"[1-9][0-9]+]\", value: \"34\" },\n//   { kind: \"[1-9][0-9]+]\", value: \"35\" },\n//   { kind: \")\", value: \")\" },\n// ];\ntype tokens = Lex\u003c\"(add 34 35)\"\u003e;\n\n// Parse result:\n// {\n//     kind: \"sexpr\",\n//     exprs: [\n//         { kind: \"sym\", sym: \"add\" },\n//         { kind: \"int\", int: \"34\" },\n//         { kind: \"int\", int: \"35\" },\n//     ]\n// }\ntype ast = Parse\u003ctokens\u003e;\n```\n\nYou can try out this lisp example by cloning the repo and opening the [ts/parse.ts](ts/parse.ts) file.\n\n## Status\n\nThis was an experiment I made several months ago, the above Lisp example works perfectly. However with longer/more complex inputs Typescript hits the\nrecursion limit, even though the type-level code is all tail calls so it should be tail call optimized.\n\nI tried to see if there was a bug in the generated code causing an infinite loop, but it's very difficult to debug type-level code. The best you can do is return template literal strings as an adhoc way of\nachieving \"printf debugging\", but for some reason the string placeholders print out garbage when the recursion level is high 🤷‍♀️\n\nLaying the project to rest now, maybe later I'll come back to it and fix the type-level code using a modified version of the Typescript compiler altered to enable debugging.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzackradisic%2Ftypelalr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzackradisic%2Ftypelalr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzackradisic%2Ftypelalr/lists"}