{"id":32418577,"url":"https://github.com/britannio/lox","last_synced_at":"2026-04-17T04:32:56.971Z","repository":{"id":113973936,"uuid":"391674966","full_name":"britannio/lox","owner":"britannio","description":"A full-featured, efficient scripting language from Robert Nystrom's book: craftinginterpreters.com","archived":false,"fork":false,"pushed_at":"2024-06-23T18:44:29.000Z","size":297,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-25T16:59:37.264Z","etag":null,"topics":["bytecode-interpreter","clox","interpreter","java","jlox","lox","lox-interpreter","lox-language","recursive-descent-parser"],"latest_commit_sha":null,"homepage":"","language":"C","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/britannio.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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-01T16:09:03.000Z","updated_at":"2025-09-28T14:18:45.000Z","dependencies_parsed_at":null,"dependency_job_id":"9c61c5e0-684a-479e-8541-2bb308245a45","html_url":"https://github.com/britannio/lox","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/britannio/lox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britannio%2Flox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britannio%2Flox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britannio%2Flox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britannio%2Flox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/britannio","download_url":"https://codeload.github.com/britannio/lox/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britannio%2Flox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31915189,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-16T18:22:33.417Z","status":"online","status_checked_at":"2026-04-17T02:00:06.879Z","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":["bytecode-interpreter","clox","interpreter","java","jlox","lox","lox-interpreter","lox-language","recursive-descent-parser"],"created_at":"2025-10-25T16:59:26.803Z","updated_at":"2026-04-17T04:32:56.967Z","avatar_url":"https://github.com/britannio.png","language":"C","readme":"# Lox\n\nLox is a full-featured, efficient scripting language from Robert Nystrom's book, [Crafting Interpreters](https://craftinginterpreters.com/). \n\nIn Jlox, the Java implementation of Lox, scripts are parsed using a recursive descent parser then interpreted by traversing the generated AST.\n\nIn Clox, the C implementation of Lox, scripts are compiled to bytecode then executed using a Bytecode Virtual Machine.\n\nA more complete description of the features of Lox can be found at https://craftinginterpreters.com/the-lox-language.html.\n\n# Jlox Setup\n\n## Requirements\n\n* Java 16\n* Maven\n* A Unix shell\n\n## Setup\n\n```sh\ncd jlox/\nmvn clean compile\n./bin/run.sh \u003cscript-name|optional\u003e\n```\n# Progress\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eJlox Progress Log\u003c/b\u003e\u003c/summary\u003e\n\n## 1 - Scanning\n\nA raw expression can be scanned into a series of tokens.\n\n```java\nInput: var tau = 6.283185307;\n\nOutput (type, lexeme, literal):\n[\u003cVAR, var, null\u003e, \u003cIDENTIFIER, tau, null\u003e, \u003cBANG, =, null\u003e, \u003cNUMBER, 6.283, 6.283\u003e, \u003cEOF, , null\u003e]\n```\n\n\n## 2 - Representing Code\n\nAn expression tree can be manually constructed and pretty printed!\n\n```java\nExpr expression = new Expr.Binary(\n            new Expr.Unary(\n                new Token(TokenType.MINUS, \"-\", null, 1),\n                new Expr.Literal(123)\n            ),\n            new Token(TokenType.STAR, \"*\", null, 1),\n            new Expr.Grouping(new Expr.Literal(45.67))\n);\n    \nSystem.out.println(new AstPrinter().print(expression));\n```\n\n```java\nOutput: (* (- 123) (group 45.67))\nInfix: -123 * 45.67\n```\n\n## 3 - Parsing Expressions\n\nA list of tokens can be parsed and pretty printed!\n\n```java\nList\u003cToken\u003e tokens = scanner.scanTokens();\n\nvar parser = new Parser(tokens);\nExpr expression  = parser.parse();\n\nSystem.out.println(new AstPrinter().print(expression));\n```\n\n```java\nInput: 1 + 2 * -3 / 4 == -0.5\nOutput: (== (+ 1.0 (/ (* 2.0 (- 3.0)) 4.0)) (- 0.5))\n```\n\n## 4 - Evaluating Expressions\n\nAn AST can be evaluated!\n\n```java\nvar scanner = new Scanner(source);\n// [\u003cNUMBER, 1, 1.0\u003e, \u003cPLUS, +, null\u003e, \u003cNUMBER, 2, 2.0\u003e, \u003cSTAR, *, null\u003e, \u003cMINUS, -, null\u003e, \u003cNUMBER, 3, 3.0\u003e, \u003cSLASH, /, null\u003e, \u003cNUMBER, 4, 4.0\u003e, \u003cEOF, , null\u003e]\nvar tokens = scanner.scanTokens();\n\nvar parser = new Parser(tokens);\nvar expression = parser.parse();\n\ninterpreter.interpret(expression);\n```\n\n```java\nInput: 1 + 2 * -3 / 4\nOutput: -0.5\n\n\nInput: 1 + 2 * -3 / 4 == -0.5\nOutput: true\n```\n\n## 5 - Statements and State\n\n- Variables can be declared, assigned and referenced in expressions.\n- Statements can be grouped into blocks with local variable scope.\n- Expressions can be printed.\n\nInput:\n```dart\nvar a = \"global a\";\nvar b = \"global b\";\n{\n    var a = \"local a\";\n    print a;\n    print b;\n}\nprint a;\nprint b;\n```\n\nOutput:\n```\nlocal a\nglobal b\nglobal a\nglobal b\n```\n\n## 6 - Control Flow\n\n- With the addition of while/for loops and more importantly **if statements**, Jlox is now Turing Complete!\n- Logical expressions (AND/OR) can be evaluated.\n\n```dart\nif (2 + 2 - 1 == 3) print \"Quick math!\"; \nelse print \"Slow math :(\";\n// prints Quick math!\n\nvar result = 0;\nwhile (result != 5) {\n    result = result + 1;\n}\nprint result; // prints 5\n\nprint false and false or true; // prints true\n```\n\n## 7 - Functions\n\nFunctions can be declared and invoked!\n\n```kotlin \nfun fib(n) {\n  if (n \u003c= 1) return n;\n  return fib(n - 2) + fib(n - 1);\n}\n\nprint fib(10); // prints 55\n\n// A native function\nprint clock(); // prints seconds since Jan 1, 1970\n```\n\n## 8 - Resolving and Binding\n\nVariables resolve to the correct scope.\n\n```java\nvar a = \"global\";\n{\n  fun showA() {\n    print a;\n  }\n\n  showA();\n  var a = \"block\";\n  showA();\n}\n ```\n\nPreviously this would output:\n```\nglobal\nblock\n```\nIt now outputs:\n```\nglobal\nglobal\n```\n\n---\n\nThis code now produces an error during semantic analysis.\n```java\n{\n    var a = 1;\n    var a = 2;\n}\n```\n\n\n## 9 - Classes\n\nClasses can be created!\n\n```java\nclass Person {\n  // Class initialiser.\n  init(name) {\n    this.name = name;\n  }\n\n  // Class method.\n  greet() {\n    print \"My name is \" + this.name + \" \" + this.nameSuffix;\n  }\n}\n\nvar britannio = Person(\"Britannio\");\nbritannio.nameSuffix = \":)\";\nbritannio.greet(); // prints \"My name is Britannio :)\"\n```\n\n## 10 - Inheritance\n\nClasses can inherit from super classes!\n\n\n```java\nclass Keyboard {\n  type() {\n    print \"Keyboard noises\";\n   }\n}\n\nclass MechanicalKeyboard \u003c Keyboard {\n  type() {\n    // super.type();\n    print \"Loud mechanical keyboard noises :)\";\n   }\n}\n\nMechanicalKeyboard().type(); // Loud mechanical keyboard noises :)\n```\n  \n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cb\u003eClox Progress Log\u003c/b\u003e\u003c/summary\u003e\n\n## 1 - Chunks of Bytecode\n\nA chunk containing bytecode instructions can be created.\n\n```\n== test chunk ==\n0000  123 OP_CONSTANT         0 '1.2'\n0002    | OP_RETURN\n```\n\n## ...\n\nforgot to take notes :(\n\n## 5 - Types of Values\n\nUntil now, the only type was a number (double). This update introduces bool and \nnil values.\n\n## 6 - Strings\n\nStrings can be created. Strings are the first 'instance' of the `Obj` type.\nC doesn't have struct inheritance but by making `Obj` the first field of \n`ObjString`, it becomes safe to cast one to the other.\n\nAs a challenge, I leveraged the *flexible array member* feature of C to store\nthe string character array within the `ObjString` struct rather than having\nthe struct store a pointer as this removes an indirection (better memory locality).\n\n\n## 7 - Hash Tables\n\nHash tables that dynamically grow can be created.\n\nThe first use case for this is string interning where we use the hash table\nas if it were a hash set. The benefit of mandatory string interning is that\nstring equality becomes a trivial pointer comparison. \n\nAs a challenge, I switched out the `ObjString` key type for `Value` so that the\nhash table key can be a string, bool, double, nil or any future object such as\nfunctions and classes.\n\nIn doing so, I hit a bug where dereferencing a pointer was corrupting a struct.\nIt turns out that the pointer originated from a variable in another function and\nsince the function had completed, the pointer was no longer valid :(.\n\n## 8 - Local Variables\n\nGrammar:\n\n```\nstatement      → exprStmt\n| printStmt ;\n\ndeclaration    → varDecl\n| statement ;\n```\n\n## 9 - Global Variables\n\n\n\n  \n\u003c/details\u003e","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbritannio%2Flox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbritannio%2Flox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbritannio%2Flox/lists"}