{"id":18674049,"url":"https://github.com/jmaczan/0x6b73746b","last_synced_at":"2025-08-30T22:31:07.393Z","repository":{"id":64688104,"uuid":"542202486","full_name":"jmaczan/0x6b73746b","owner":"jmaczan","description":"🐱 Tree-Walk Interpreter","archived":false,"fork":false,"pushed_at":"2023-08-16T12:51:08.000Z","size":47,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-01T07:23:41.939Z","etag":null,"topics":["ast","compiler","interpreter","lox","programming-language","rust","tree-walk-interpreter"],"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/jmaczan.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}},"created_at":"2022-09-27T17:14:00.000Z","updated_at":"2024-11-08T16:15:38.000Z","dependencies_parsed_at":"2023-02-15T17:46:20.701Z","dependency_job_id":null,"html_url":"https://github.com/jmaczan/0x6b73746b","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jmaczan/0x6b73746b","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmaczan%2F0x6b73746b","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmaczan%2F0x6b73746b/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmaczan%2F0x6b73746b/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmaczan%2F0x6b73746b/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jmaczan","download_url":"https://codeload.github.com/jmaczan/0x6b73746b/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jmaczan%2F0x6b73746b/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272917686,"owners_count":25014933,"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-08-30T02:00:09.474Z","response_time":77,"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":["ast","compiler","interpreter","lox","programming-language","rust","tree-walk-interpreter"],"created_at":"2024-11-07T09:17:20.984Z","updated_at":"2025-08-30T22:31:07.086Z","avatar_url":"https://github.com/jmaczan.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003cimg width=\"150\" src=\"0x6b73746b.png\" alt=\"0x6b73746b\"\u003e\u003c/p\u003e\n\n# 0x6b73746b\n\nPartial tree-walk interpreter based on Robert Nystrom's \"Crafting Interpreters\" book https://craftinginterpreters.com/ and Lox Programming Language\n\n## Docs\nDirectory `lang/src` contains source code of the interpreter. In order to run the interpreter, you need `cargo` installed. Obtain a copy of this repository by i.e. cloning it, go to `lang` folder and in a terminal type `cargo run`. If you want to have an executable file to distribute it, run `cargo build --release`. The output file `0x6b73746b` is present in `lang/target/release/` directory. To run it, invoke it in a terminal `./0x6b73746b`.\n\nThe interpreter is written in Rust. It doesn't use any external crates. From the language's standard library, it uses `fs` for file system operations, `io` for handling standard input and output, `path` for cross-plaform path manipulation, `collections` for `HashMap` data structure and `env` to handle program arguments.\n\nThis project is not finished. What has been already implemented is:\n1. Lexical analysis\n2. Abstract Syntax Tree\n3. Visitor pattern\n4. AST Prettyprint\n5. REPL\n6. Recursive Descent Parser with error handling - in progress\n\n## Notes\n\nThis README is also a log of how the language was built and what I learn during this. It serves me as notes to memorize new things better and be able to get back to them easier\n\n**self-hosting** - it's when a compiler of language X is written in language X\n\n**bootstrapping** - it's when you use a language Y to compile a compiler of language X, which now can compile compilers for language X, so a former compiler of language Y is not needed anymore\n\nlanguage is too long word for this log, I replace it with lang since now\n\ncompilation is a process of transforming code from complex form to basic structure\n\nsteps of programming lang compilation:\n1. **scanning** (lexing, lexical analysis) - take text, output text divided on meaningful tokens like \"function\", \"(\", \"'A'\", \"=\" and so on; we get syntax as an output here\n2. **parsing** - organize tokens into a tree (AST; abstract syntax tree; parse tree), so it becomes a binary (?) tree with top operation as a root node and two (maybe more, not sure yet) children nodes; it is a structure of meaning of tokens; **parser** discovers **syntax errors**\n3. **static analysis** - gives a meaning to the syntax; \n   1. **binding (resolution)** - take an **identifier** (i.e. variable) and find its declaration and connect them; **scope** becomes important here, a declaration needs to be in a scope of a usage\n   2. **type checking** for statically typed langs; discover **type errors**\n   3. storing a result of static analysis:\n      1. attach it to AST as additional **attributes**\n      2. store them in a separate table with i.e. variable names as keys\n      3. transform AST to something different\n   \neverything up to this point is **frontend** of compiler; it's about lang\nthen there's **middle end**, which starts from **intermediate representation** (IR) \nlast is **backend**, which is about something deeper but don't know it yet\n\n4. **intermediate representation**\n   1. **control-flow graph** - representation of all possible paths in a program, shown on a graph\n   2. **static single assignment** - when a value is reassigned to a variable, a variable becomes a version of the original one, so in intermediate representation there will never be more than a single declaration and a single assignment to a given variable; **use-define chain** is a data structure storing uses and definitions of a variable; for static single assignment, use-define chain stores a single element\n   3. **continuation-passing style** - it's a code written in a way that a function X has a callback (function Y) as a parameter; function X doesn't return a value Z; it calls function Y with parameter Z instead; \"No procedure is allowed to return to its caller - ever.\" ~Matt Might https://matt.might.net/articles/by-example-continuation-passing-style/\n   4. **three-address code** - `a := b [operation c]`, i.e. `a := 4 + c`; more complex code might be split into a sequence of multiple three-address code instructions; three-address code notation is easier to parse to assembly than a regular code\n5. **optimization** - it's possible to do optimization now, because a desired logic behind code is known; the open issue is how to implement this code as a low-level instructions (?)\n   1. **constant propagation** - replacing all occurences of a constant with its value;\n   2. **constant folding** - when expression is a constant, evaluate them and replace all of their occurences with an evaluated value\n   3. **dead-code elimination** - removing a code that can't be reached by a program's execution and a code that is related to variables which are never used but are declared (dead variables)\n   4. **register allocation** - optimization by assigning variables to registers; not sure yet how \n   5. **instruction selection** - ran before register allocation; I think it's choosing a machine instruction for a IR code\n   6. **instruction scheduling** - optimization for organizing the order of instructions;\n\nhere the backend starts\n\n**intrinsic function** - a function that is known for a compiler ('built-in') and is used directly from compiler, instead of being linked to some library\n\n6. **code generation** - generate assembly code for a real processor or pseudo-assembly code for a virtual processor (VM?); real assembly code is executed by a physical chip; it means that the assembly code is dedicated to a specific processor architecture; a code generated for a virtual machine is called **bytecode** and this code is universal because the target architecture is a virtual one; if **code generation** produces **bytecode**, you can either write multiple compilers to transform bytecode to a platform specific code; bytecode is an intermediate representation here or create **virtual machine**\n\n7. **virtual machine** - it's either:\n   1. (lang || process) vm - a program written in X lang that emulates a hypothetical processor and might be ran on any platform which has X compiler installed\n   2. (system) vm - emulator for a full hardware and operating system\n8. **runtime** - if code generation produces a machine code, operating system loads an executable; if code generation produces a bytecode, start virtual machine and load a program; things like garbage collector are in runtime; compiled langs might have copy of runtime inside of a compiled executable; langs with vm have runtime inside vm\n\ntypes of compilers:\n1. **single-pass compilers** - do all steps in a single pass, no going back with anything\n2. **tree-walk interpreters** - slow; program runs by traversing through an abstract syntax tree and evaluating nodes during a traversal\n3. **transpilers** - transcompiler; this is i.e. TypeScript I think; write frontend (scanner and parser) of X lang and compile it to a frontend of another Y lang; when X and Y are different, you might do more additional steps in between and generate Y code in code generation step\n4. **just-in-time compilation** - compile to bytecode to machine code when a program is loaded, so a compiler known to which architecture it should compile the code; examples: HotSpot JVM, JS (V8 engine), Microsoft Common Language Runtime; it has HotSpot in name because it has an optimization technique of finding important places in code which affect performance\n\n**compiling**: translate lang X to lang Y; transpiling is a compling as well\n\n**compiler**: translate code but not execute\n\n**interpreter**: execute code from source\n\nsomething might be both compiler and interpreter, i.e. JS (V8)\n\ntypes of memory management (a spectrum of it):\n1. **reference counting** - it's when a lang keeps track on amount of references and pointers to each variable \n2. **garbage collection** - it's when program frees those parts of memory to which there are no references anymore; prevents **dangling pointers** - it's when you empty a memory but there are still some pointers to this memory and you try to get access to this memory (dereference a pointer) using this pointer; prevents **double-free** - trying to empty a memory that is already emptied - and some **memory leaks**\n\ntypes of operators:\n1. **infix** - between two operands, i.e. `a + b`\n2. **prefix** - before an operand, i.e. `!a`\n3. **postfix** - after an operand, i.e. `a!`\n\n**short-circuit evaluation** - when compiler omits evaluation of right side of `and` - `a and b` - when `a` is false or right side of `or` - `a or b` - when `a` is true\n\n**declaring a function** is when you assign a type to a function's name\n\n**defining a function** is when you add a body with code to a function\n\n**parameter of a function** - a formal parameter; variable declared as a parameter of function, i.e. `a` and `b` in `func(a, b) { do_something(); }`\n\n**argument of a function** - an actual parameter; value of a parameter which you use a inside function's body, i.e. value of `a`, like `5` or `\"word\"`\n\n**class vs prototype** - in classes we have inheritance; an instance refers to a class for a method; in prototypes there are only instances (objects) and their relation is that one can **delegate** to another to invoke a method\n\n**maximal munch** - a principle saying that when you decide about how to parse a lexeme, you should pick the one that matches as many characters as possible; it's the best match in other words, where 'best' is when more characters fit to the template than to others\n\n**postorder traversal** - it's kind of traversing a graph (i.e. tree); depth-first; do recursively traversal to the left subtree, then recursively to the right subtree; https://medium.com/data-structure-and-algorithms/binary-tree-post-order-traversal-9e7174b87cda\n\nin formal languages, which programming languages like this one belongs to, there are two (?) types of symbols. \n1. **non-terminal symbols** - like variable; it can be replaced with some other change; a concept of digit is non-terminal, because it might take different terminal values (like 0, 1, 2, etc)\n2. **terminal symbols** - a defined value of variable, i.e. '0'; it can't be changed in something else, so that's why it's terminal\n\n**chomsky hierarchy** - hierarchy of formal grammars; it consists of: \n1. **type-0** - \"**recursively enumerable**\"; turing machine; non-empty string of terminals and/or non-terminals produces possibly empty string of terminals and/or non-terminals\n2. **type-1** - \"**context-sensitive**\"; non-deterministic turing machine; \n3. **type-2** - \"**context-free**\"; non-deterministic pushdown automation; non-terminal produces string of maybe empty terminals and/or non-terminals\n4. **type-3** - \"**regular**\"; finite state automaton; non-terminal produces terminal and non-terminal produces terminal with non-terminal\n\nthe language's grammar consists of\n1. **expression**, which may be literal, unary, binary or grouping\n2. **literal**, which may be any number, string, true, false or nil\n3. **grouping**, which is an expression inside parenthesis \n4. **unary**, which consists of ! or - followed by an expression\n5. **binary**, which has infix operator, surrounded by expressions\n6. **operator**, which might be one of allowed operators for math and comparing\n\n**visitor pattern** is one of possible ways to traverse the AST. For each type of expression (binary, literal, unary, grouping, etc.) we implement the same interface which has a visitor's method, which takes a visitor as a param, i.e. `accept(visitor)` and invokes a proper method from Visitor interface, like visit_binary_expr when visiting binary expression etc. \n\n**pretty-print** utilizes visitor pattern and each node (?) with `accept` method invokes a proper visitor's method which produces a `string`.\n\n**recursive descent parser** starts parsing the code from from highest level rules from lang's grammar (in case of this lang it's expression/equality) and recursively applies them until on bottom (in this case primary, like number, string, boolean, nil or expression in parenthesis)\n\n## Author\nNotes is bunch of my notes from working through Robert Nystrom's \"Crafting Interpreters\" book and a result of searching through web to learn about programming languages and compilers and trying to explain those things in a written form\n\nDesign of 0x6b73746b lang is derived from Lox lang and modified\n\nImplementation of 0x6b73746b lang is based on C and Java implementations of Lox lang and written from a scratch in Rust\n\n© Copyright [Jędrzej Paweł Maczan](https://maczan.pl/). Made in [Poland](https://en.wikipedia.org/wiki/Poland), 2022\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmaczan%2F0x6b73746b","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjmaczan%2F0x6b73746b","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjmaczan%2F0x6b73746b/lists"}