{"id":16538623,"url":"https://github.com/kyleect/locks","last_synced_at":"2026-02-02T01:32:33.590Z","repository":{"id":203544153,"uuid":"709565341","full_name":"kyleect/locks","owner":"kyleect","description":"A toy language branched from Lox to learn language implementation and tooling. Forked from loxcraft","archived":false,"fork":false,"pushed_at":"2024-01-11T04:00:06.000Z","size":1416,"stargazers_count":0,"open_issues_count":93,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-21T06:04:16.480Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://kyleect.github.io/locks/#/docs","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"ajeetdsouza/loxcraft","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kyleect.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-25T00:09:09.000Z","updated_at":"2024-01-03T05:35:33.000Z","dependencies_parsed_at":"2023-12-23T12:03:28.853Z","dependency_job_id":"17289ac2-7e37-4c20-ba35-31a56950940f","html_url":"https://github.com/kyleect/locks","commit_stats":null,"previous_names":["kyleect/locks"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kyleect/locks","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleect%2Flocks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleect%2Flocks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleect%2Flocks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleect%2Flocks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kyleect","download_url":"https://codeload.github.com/kyleect/locks/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kyleect%2Flocks/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28999689,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-02T01:32:03.847Z","status":"ssl_error","status_checked_at":"2026-02-02T01:32:03.458Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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-11T18:46:10.968Z","updated_at":"2026-02-02T01:32:33.568Z","avatar_url":"https://github.com/kyleect.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- markdownlint-configure-file {\n  \"MD033\": false,\n  \"MD041\": false\n} --\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n# 🔓 locks\n\nA toy language branched from [Lox](https://www.craftinginterpreters.com/) to learn language implementation. Forked from [loxcraft](https://github.com/ajeetdsouza/loxcraft).\n\n[![ci](https://github.com/kyleect/locks/actions/workflows/build-artifacts.yml/badge.svg)](https://github.com/kyleect/locks/actions/workflows/build-artifacts.yml)\n\n\u003c/div\u003e\n\n## Features\n\n- Bytecode Compiler\n- Stack Based Virtual Machine\n- Garbage Collection\n- [Online Playground](https://kyleect.github.io/locks/), via WebAssembly (/w shareable [links](https://kyleect.github.io/locks/#/code=GYOwBAFgpgNjD2AKEBDAtlAlGA3gWACgwwAnKAFwFcTwAiACVgTFrAGoxUMBuQgX0KEADiQCWIcpCZJaAdXgkYAE1qZeBIA))\n- [Interactive Documentation](https://kyleect.github.io/locks/#/docs)\n- Language Server\n- REPL\n- [VS Code Extension](#vs-code-extension)\n- [Docker](#docker)\n\n## Getting Started\n\nCheck out the [documentation](https://kyleect.github.io/locks/#/docs) the start running code in the [playground](https://kyleect.github.io/locks/).\n\n### Example\n\n[Playground](https://kyleect.github.io/locks/#/?code=GYOwBMCWBe0EIFdYAoQEowG8CwAoMEA9gE5jIBuAhqZGALxgCMA3GLQDwMiu0O0DUTDDnwExkYGVoBSJgFZ6DAAzC8Y9WAAOxSCAAuYAEQAxGPCTRDzNRoC+N9QFMANgGdHbSchlgAzIrAVLAcNbV0DEzMrEIJ7USc3DwkpMFkFOmVVeNCdfSNEWGjs2JiwF3dg4rEwvMhrKriS3Di8KFgC6GRGJRV6vAB6frBCBD0ALiYBoZHxsAAmKeHRidNYRZmJgBZ15bAOndnV6AOJgHYTsAAOC6OL-dxBpdnGRhuzC8ZfD+2H6d2j+6PDZMABsH3OvyeK3ekOBjAAnHcLG81rDdnMFmjZnMvljoaigbtAX9sWC8WBbuS5tcqYjyQDkeTfK8mZjCYcYeyJr4fly9oy+ZS+b4IcKaYLOSSJsSoWBNiyJQSpXLcXzNrzlQylbLNmS1aLNZKdXS+TLgULlXI2ZbVYbtcCzbs5Hq7cdyXJxZaTa7HbMQQrlSDrbKLbKQRrZb78W6+SCDWHPSGjQ6BcrTgGk-bdqdbbLThHzWYo2BTi68-HC1nZqdvZHU5mY8rLsHgZdc5XG3WqxNLmWOxdLonW7WO8X4RngfCW-9k7t4QWifX++T4RW50OZ93+bAgA)\n\n```\nfn fizzBuzz(n) {\n  for (let i = 1; i \u003c= n; i = i + 1) {\n      if (i % 15 == 0) {\n        println(\"FizzBuzz\");\n      }\n      else if (i % 3 == 0) {\n        println(\"Fizz\");\n      }\n      else if (i % 5 == 0) {\n        println(\"Buzz\");\n      }\n      else {\n        println(i);\n      }\n  }\n}\n\nfizzBuzz(100);\n```\n\n## Usage\n\n### Runtime\n\nDownload the runtime from the [latest build](https://github.com/kyleect/locks/actions/workflows/build-artifacts.yml)\n\n#### REPL\n\n```shell\n$ locks repl\n```\n\n#### Run files\n\n```shell\n$ locks run file.locks\n```\n\n#### Execute locks code as an argument\n\n```shell\n$ locks exec 'println(\"Hello\");' # Hello\n```\n\n#### Execute locks code from stdin\n\n```shell\n$ cat res/benchmarks/fib.locks | locks exec\n```\n\n#### Print the Abstract Syntax Tree (AST) from Locks code\n\n```\n// example.locks\n\nlet value;\nprintln(value); // out: nil\nvalue = 42;\nprintln(value); // out: 42\n```\n\n```shell\n$ locks parse example.locks\n```\n\n```\nProgram {\n  stmts: [\n    (\n      StmtAssign {\n        identifier: Identifier {\n          name: \"value\",\n          depth: None,\n        },\n        value: None,\n      },\n      72..82,\n    ),\n    (\n      StmtPrint {\n        value: (\n          ExprIdentifier {\n            identifier: Identifier {\n              name: \"value\",\n              depth: None,\n            },\n          },\n          89..94,\n        ),\n      },\n      83..95,\n    ),\n    (\n      StmtExpr {\n        value: (\n          ExprAssign {\n            identifier: Identifier {\n              name: \"value\",\n              depth: None,\n            },\n            value: (\n              Number(\n                42.0,\n              ),\n              116..118,\n            ),\n          },\n          108..118,\n        ),\n      },\n      108..119,\n    ),\n    (\n      StmtPrint {\n        value: (\n          ExprIdentifier {\n            identifier: Identifier {\n              name: \"value\",\n              depth: None,\n            },\n          },\n          126..131,\n        ),\n      },\n      120..132,\n    ),\n  ],\n}\n```\n\n#### Print the disassembled bytecode from Locks code\n\n```\n// ./res/examples/number/fizzbuzz.locks\n\nfn fizzBuzz(n) {\n  for (let i = 1; i \u003c= n; i = i + 1) {\n      if (i % 15 == 0) {\n        println(\"FizzBuzz\");\n      }\n      else if (i % 3 == 0) {\n        println(\"Fizz\");\n      }\n      else if (i % 5 == 0) {\n        println(\"Buzz\");\n      }\n      else {\n        println(i);\n      }\n  }\n}\n\nfizzBuzz(100);\n```\n\n```shell\n$ locks disassemble ./res/examples/number/fizzbuzz.locks\n```\n\n```\n0000 OP_CLOSURE          0 == '\u003cfn fizzBuzz arity=1\u003e'\n| 0000 OP_CONSTANT         0 == '1'\n| 0002 OP_GET_LOCAL        2\n| 0004 OP_GET_LOCAL        1\n| 0006 OP_LESS_EQUAL\n| 0007 OP_JUMP_IF_FALSE    7 -\u003e 82\n| 0010 OP_POP\n| 0011 OP_GET_LOCAL        2\n| 0013 OP_CONSTANT         1 == '15'\n| 0015 OP_MODULUS\n| 0016 OP_CONSTANT         2 == '0'\n| 0018 OP_EQUAL\n| 0019 OP_JUMP_IF_FALSE   19 -\u003e 29\n| 0022 OP_POP\n| 0023 OP_CONSTANT         3 == 'FizzBuzz'\n| 0025 OP_PRINT\n| 0026 OP_JUMP            26 -\u003e 71\n| 0029 OP_POP\n| 0030 OP_GET_LOCAL        2\n| 0032 OP_CONSTANT         4 == '3'\n| 0034 OP_MODULUS\n| 0035 OP_CONSTANT         2 == '0'\n| 0037 OP_EQUAL\n| 0038 OP_JUMP_IF_FALSE   38 -\u003e 48\n| 0041 OP_POP\n| 0042 OP_CONSTANT         5 == 'Fizz'\n| 0044 OP_PRINT\n| 0045 OP_JUMP            45 -\u003e 71\n| 0048 OP_POP\n| 0049 OP_GET_LOCAL        2\n| 0051 OP_CONSTANT         6 == '5'\n| 0053 OP_MODULUS\n| 0054 OP_CONSTANT         2 == '0'\n| 0056 OP_EQUAL\n| 0057 OP_JUMP_IF_FALSE   57 -\u003e 67\n| 0060 OP_POP\n| 0061 OP_CONSTANT         7 == 'Buzz'\n| 0063 OP_PRINT\n| 0064 OP_JUMP            64 -\u003e 71\n| 0067 OP_POP\n| 0068 OP_GET_LOCAL        2\n| 0070 OP_PRINT\n| 0071 OP_GET_LOCAL        2\n| 0073 OP_CONSTANT         0 == '1'\n| 0075 OP_ADD\n| 0076 OP_SET_LOCAL        2\n| 0078 OP_POP\n| 0079 OP_LOOP            79 -\u003e 2\n| 0082 OP_POP\n| 0083 OP_POP\n| 0084 OP_NIL\n| 0085 OP_RETURN\n0002 OP_DEFINE_GLOBAL    1 == 'fizzBuzz'\n0004 OP_GET_GLOBAL       1 == 'fizzBuzz'\n0006 OP_CONSTANT         2 == '15'\n0008 OP_CALL             1\n0010 OP_POP\n0011 OP_NIL\n0012 OP_RETURN\n```\n\n#### Run the Locks Language Server\n\n```shell\n$ locks lsp\n```\n\n### Docker\n\n- `$ just build-docker` Build docker image\n- `$ just run-repl-docker` Run `locks repl` inside built docker image\n\n### VS Code Extension\n\nDownload the VS Code extension from the [latest build](https://github.com/kyleect/locks/actions/workflows/build-artifacts.yml)\n\n#### OR\n\n1. Run `just build-all`\n2. Copy `./target/release/locks[.exe]` somewhere in your `PATH`\n3. Install `./vsc/out/locks-language-1.0.0.vsix` in VS Code\n4. Create a new file and save as `*.locks`\n\n#### Features\n\n- Language Server integration\n- Syntax \u0026 error highlighting\n- Commands\n- Snippets\n\n## Development\n\n### Setup\n\n- Install [Rust](https://www.rust-lang.org/tools/install)\n- Install [Docker](https://www.docker.com/)\n- `$ cargo install just` Required for running development scripts\n- `$ cargo install wasm-pack` Required to compile wasm package for playground\n\n### Scripts\n\n- `$ just build-all` Build all packages (locks, playground, \u0026 vs code extension)\n- `$ just lint-all` Run linting on packages\n- `$ just clean-all` Clean build artifacts in all packages\n- `$ just run-playground` Build and run playground\n- `$ just build-docker` Build docker image\n- `$ just run-repl-docker` Run `locks repl` inside built docker image\n- `$ just install` Create a release build of locks and move it to `~/.cargo/bin`\n- `$ just install-debug` Create a debug build of locks and move it to `~/.cargo/bin`\n- `$ just install-trace` Create a debug build of locks with `gc-trace` \u0026 `vm-trace` features enabled then move it to `~/.cargo/bin`\n- `$ just clean-git-branches` Clean up and prune branches merged in to `main`\n\n## Forked\n\nThis project was forked from [loxcraft](https://github.com/ajeetdsouza/loxcraft). The intent of this fork is to learn about bytecode compilers, stack-based virtual machines, programming language design, and the desire to implement new language features.\n\nThere were many potential open source projects that could have been the basis for this toy language but loxcraft had a solid base to start from especially when I was focused on implementing language tooling first. It already had a working language server so the Visual Studio Code extension was a natural place to start.\n\nWith the syntax and implementation changes so far the Locks language has divered from Lox and will continue to do so.\n\n### Changes Made\n\n- Comments added to code base as part of the learning process while implementing changes\n- Rewrote \u0026 decoupled disassembler to build a string of the disassembled bytecode instead of printing it\n- CLI enhancements\n  - Add `parse` command to print the AST from a `*.locks` file.\n  - Add `dissassemble` command to print disassembled bytecode from a `*.locks` file\n  - Add `exec` command to execute Locks code from the arg or piped in from `stdin`\n- Language changes\n  - Function/method declarations: `fun` -\u003e `fn`\n  - Using single expressions as [function](https://kyleect.github.io/locks/#/docs#functions-single-expression-bodies)/[method](https://kyleect.github.io/locks/#/docs#classes-single-expression-method-bodies) bodies with implicit return: `fn sum (a, b) =\u003e a + b;`\n  - Variable declarations: `var` -\u003e `let`\n  - Class fields declared using `let field;` or `let field = \"defaultValue\";`\n  - Setting undeclared fields on classes will generate an error\n  - Class inheritence: `class Child : Parent {}` -\u003e `class Child extends Parent {}`\n  - [Lists](https://kyleect.github.io/locks/#/docs#lists): `[1, 2, 3]`, `arr[0]`, `arr[0] = 123`\n  - Add the `len` native function for lists and strings\n  - Change `print` from a statement to a function: `print`, `println`\n  - Add [`typeof`](https://kyleect.github.io/locks/#/docs#typeof) native function to return a value's type as string\n  - Add [`instanceof`](https://kyleect.github.io/locks/#/docs#instanceof) native function to return `boolean` if the value is an instance of the class or super class.\n  - Add the base class [`Object`](https://kyleect.github.io/locks/#/docs#classes-object) class that all classes extend from.\n  - The file `res/lib/locks.locks` is loaded by the VM before running user code. This is where the base class `Object` is defined.\n  - Implement [static class fields](https://kyleect.github.io/locks/#/docs#classes-static-fields)\n  - Implement [static class methods](https://kyleect.github.io/locks/#/docs#classes-static-methods)\n- Bug Fixes\n  - Add `#[repr(C)]` to `ObjectNative`. This fixes a segfault that occurred when there were multiple entries in the `Native` enum.\n  - [Remove an OP transformation the compiler](https://github.com/kyleect/locks/pull/135/files#diff-23c5734d7de815d5e64ad2291873d96e9f686a8b11d76481f3d02c905c53341dL403) was doing that would cause a segfault when bound methods were passed to functions e.g. `function(instance.method)`\n  - Fix REPL not exiting when pressing \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eC\u003c/kbd\u003e. It now exits with code [`130`](https://tldp.org/LDP/abs/html/exitcodes.html#EXITCODESREF)\n- [Dockerize](Dockerfile) the Locks binary executable\n- Implemented a [VS Code Extension](vsc)\n  - Integrates the existing [language server](src/lsp.rs) to display parsing/compiler errors\n  - Syntax Highlighting, Auto Pair Complete\n  - Snippets\n  - Commands/tasks to run, parse, and disassemble Locks code\n  - Debug config for running VS Code Extension in VS Code\n- Add builds (Locks binary executable \u0026 VS Code extension) as artifacts to the Github workflow\n- Revamped the [Online Playground](https://kyleect.github.io/locks/)\n  - Added a [documentation](https://kyleect.github.io/locks/#/docs) page with runnable code examples. This reuses the same webassembly build of the Locks runtime that the playground uses.\n  - Add a \"Parse \u0026 \"Disassemble\" button to the playground page and to all code examples on the docs page\n  - Restyled playground\n  - Add live updated and shareable playground urls\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyleect%2Flocks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkyleect%2Flocks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkyleect%2Flocks/lists"}