{"id":16528439,"url":"https://github.com/danvk/gravlax","last_synced_at":"2025-07-10T19:33:16.408Z","repository":{"id":216338864,"uuid":"740646014","full_name":"danvk/gravlax","owner":"danvk","description":"A Lox interpreter with tasty TypeScript seasoning","archived":false,"fork":false,"pushed_at":"2025-07-01T11:53:15.000Z","size":1066,"stargazers_count":3,"open_issues_count":12,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-01T12:46:43.694Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danvk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-01-08T19:15:14.000Z","updated_at":"2025-01-22T06:32:42.000Z","dependencies_parsed_at":"2024-01-19T15:42:23.360Z","dependency_job_id":"685e698c-a63d-43b2-b44d-5c0dd92f70cd","html_url":"https://github.com/danvk/gravlax","commit_stats":null,"previous_names":["danvk/gravlax"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/danvk/gravlax","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fgravlax","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fgravlax/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fgravlax/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fgravlax/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danvk","download_url":"https://codeload.github.com/danvk/gravlax/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fgravlax/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264639844,"owners_count":23642313,"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","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-11T17:40:24.462Z","updated_at":"2025-07-10T19:33:16.391Z","avatar_url":"https://github.com/danvk.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eGravlax\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003eA Lox interpreter with tasty TypeScript seasoning\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n\t\u003c!-- prettier-ignore-start --\u003e\n\t\u003c!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --\u003e\n\t\u003ca href=\"#contributors\" target=\"_blank\"\u003e\u003cimg alt=\"👪 All Contributors: 2\" src=\"https://img.shields.io/badge/%F0%9F%91%AA_all_contributors-2-21bb42.svg\" /\u003e\u003c/a\u003e\n\u003c!-- ALL-CONTRIBUTORS-BADGE:END --\u003e\n\t\u003c!-- prettier-ignore-end --\u003e\n\t\u003ca href=\"https://github.com/danvk/gravlax/blob/main/.github/CODE_OF_CONDUCT.md\" target=\"_blank\"\u003e\u003cimg alt=\"🤝 Code of Conduct: Kept\" src=\"https://img.shields.io/badge/%F0%9F%A4%9D_code_of_conduct-kept-21bb42\" /\u003e\u003c/a\u003e\n\t\u003ca href=\"https://codecov.io/gh/danvk/gravlax\" target=\"_blank\"\u003e\u003cimg alt=\"🧪 Coverage\" src=\"https://img.shields.io/codecov/c/github/danvk/gravlax?label=%F0%9F%A7%AA%20coverage\" /\u003e\u003c/a\u003e\n\t\u003ca href=\"https://github.com/danvk/gravlax/blob/main/LICENSE.md\" target=\"_blank\"\u003e\u003cimg alt=\"📝 License: MIT\" src=\"https://img.shields.io/badge/%F0%9F%93%9D_license-MIT-21bb42.svg\"\u003e\u003c/a\u003e\n\t\u003ca href=\"http://npmjs.com/package/gravlax\"\u003e\u003cimg alt=\"📦 npm version\" src=\"https://img.shields.io/npm/v/gravlax?color=21bb42\u0026label=%F0%9F%93%A6%20npm\" /\u003e\u003c/a\u003e\n\t\u003cimg alt=\"💪 TypeScript: Strict\" src=\"https://img.shields.io/badge/%F0%9F%92%AA_typescript-strict-21bb42.svg\" /\u003e\n\u003c/p\u003e\n\nThis is my implementation of an interpreter for the Lox language from Robert Nystrom's _[Crafting Interpreters]_.\nI'm building this as part of my Winter 2024 batch at the [Recurse Center].\n\n## Usage\n\n```shell\nnpx gravlax [file.lox]\n```\n\n## Departures from the book\n\n### Features not in the book\n\nThere's one notable feature I added beyond what's in the text of _Crafting Interpreters_: support for commas as numeric separators and currencies as first-class values.\n\nYou can write `1,234 + 2,456` and gravlax will happily print out `3690`.\nNote that this has the… interesting side effect of making the grammar whitespace-sensitive:\n`f(1,2)` and `f(1, 2)` parse differently (the former is a one-argument call).\n\nYou can also write out currency values like `$123` or `€456` and do math on them.\nThe operations you'd expect to work will work: adding or subtracting values from the\nsame currency is OK, multiply a currency by a scalar is OK, etc:\n\n```text\n\u003e ($1,234 + $2,345) / 10\n$357.9\n\u003e $12 + €23\nMixedCurrencyError: Operands must be the same currency.\n```\n\nTwo other niceties:\n\n1. Support for expressions in the REPL ([Chapter 8 Challenge 1]).\n   If you run `npx gravlax` and then `1+2`, it will print `3`.\n   No need to write a `print` statement.\n   This makes it possible to use gravlax as a calculator.\n\n2. The REPL uses readline so you can hit up arrow to get the previous expression and edit it.\n\n### Implementation details\n\nRather than representing AST nodes as classes, I used TypeScript `interface`s and\na discriminated union for `Expr` and `Stmt`.\nThis means that we don't need a codegen step.\nIt also means that we [don't need the visitor pattern]:\npattern-matching with `switch`/`case` is more idiomatic and less code.\n\nWhile I used a class for the Scanner (same as the book), I used a closure for the parser.\nMostly this just means less writing `this` dot whatever.\n\n## Performance\n\nOn my machine, gravlax runs the [Fibonacci code] from Chapter 14 in ~3 minutes (174 seconds).\nCompare this with 27s for jlox.\nSo we're ~6x slower than Java.\n\nIn jlox and gravlax, returning from a function is implemented by throwing an exception.\nIt's critical that this class not derive from `Error`, so that it doesn't carry\nalong stack traces:\n\n```text\n- class ReturnCall extends Error {\n+ class ReturnCall {\n```\n\nThe latter winds up being ~10x faster than the former.\nThis is the JS equivalent of the [weird] `super(null, null, false, false)` call in jlox.\nSee [#37].\n\n## Development\n\n```shell\npnpm install\npnpm test\npnpm repl\n```\n\n## Contributors\n\n\u003c!-- spellchecker: disable --\u003e\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://effectivetypescript.com/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/98301?v=4?s=100\" width=\"100px;\" alt=\"Dan Vanderkam\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eDan Vanderkam\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/danvk/gravlax/commits?author=danvk\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"#content-danvk\" title=\"Content\"\u003e🖋\u003c/a\u003e \u003ca href=\"https://github.com/danvk/gravlax/commits?author=danvk\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"#ideas-danvk\" title=\"Ideas, Planning, \u0026 Feedback\"\u003e🤔\u003c/a\u003e \u003ca href=\"#infra-danvk\" title=\"Infrastructure (Hosting, Build-Tools, etc)\"\u003e🚇\u003c/a\u003e \u003ca href=\"#maintenance-danvk\" title=\"Maintenance\"\u003e🚧\u003c/a\u003e \u003ca href=\"#projectManagement-danvk\" title=\"Project Management\"\u003e📆\u003c/a\u003e \u003ca href=\"#tool-danvk\" title=\"Tools\"\u003e🔧\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://www.joshuakgoldberg.com/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/3335181?v=4?s=100\" width=\"100px;\" alt=\"Josh Goldberg ✨\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eJosh Goldberg ✨\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"#tool-JoshuaKGoldberg\" title=\"Tools\"\u003e🔧\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\u003c!-- spellchecker: enable --\u003e\n\n\u003c!-- You can remove this notice if you don't want it 🙂 no worries! --\u003e\n\n\u003e 💙 This package was templated with [`create-typescript-app`](https://github.com/JoshuaKGoldberg/create-typescript-app).\n\n[Crafting Interpreters]: https://craftinginterpreters.com/contents.html\n[Recurse Center]: https://www.recurse.com/\n[Chapter 8 Challenge 1]: https://craftinginterpreters.com/statements-and-state.html#challenges\n[don't need the visitor pattern]: https://github.com/danvk/gravlax/pull/35\n[Fibonacci code]: https://craftinginterpreters.com/chunks-of-bytecode.html\n[#37]: https://github.com/danvk/gravlax/pull/37\n[weird]: https://craftinginterpreters.com/functions.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanvk%2Fgravlax","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanvk%2Fgravlax","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanvk%2Fgravlax/lists"}