{"id":26836654,"url":"https://github.com/mnikander/transpiler","last_synced_at":"2025-06-18T22:36:55.280Z","repository":{"id":275792238,"uuid":"923059050","full_name":"mnikander/transpiler","owner":"mnikander","description":"Transpile symbolic expressions to C++","archived":false,"fork":false,"pushed_at":"2025-03-27T17:11:22.000Z","size":145,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-27T18:24:35.016Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/mnikander.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":"2025-01-27T15:19:30.000Z","updated_at":"2025-03-25T19:18:00.000Z","dependencies_parsed_at":"2025-03-20T12:22:07.222Z","dependency_job_id":"ccad7a1a-0220-4915-8cc0-f6be867cc44a","html_url":"https://github.com/mnikander/transpiler","commit_stats":null,"previous_names":["mnikander/compiler_fragments","mnikander/transpiler"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnikander%2Ftranspiler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnikander%2Ftranspiler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnikander%2Ftranspiler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnikander%2Ftranspiler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mnikander","download_url":"https://codeload.github.com/mnikander/transpiler/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246346831,"owners_count":20762660,"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":"2025-03-30T16:28:53.746Z","updated_at":"2025-03-30T16:28:54.218Z","avatar_url":"https://github.com/mnikander.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Transpiler for Symbolic Expressions\n\nThis project transpiles symbolic expressions similar to those found in Lisp and Scheme to C++.\nThe aim is to experiment with a few language features and learn about compilers and transpilers.\nCurrently, the focus of the codebase is on the _code generation_ stage of the transpiler.\n\n\n## Getting Started\n\n```bash\nsudo apt install nodejs npm g++ cmake\ngit clone git@github.com:mnikander/transpiler.git\ncd transpiler/\nnpm run clean  # the 'clean' target ensures the 'out/' and 'out/artifacts/' directories are created\nnpm run main   # build and run the example\nnpm test       # build and run the unit tests\n```\n\nBoth the main function and the unit tests will automatically transpile their abstract syntax trees to C++ and then compile and execute the resulting programs. \nYou can find all generated source files, executables, and result text files, in the directory `out/artifacts`, and you can run execute the programs manually from there.\n**If** you wish to build the main program without immediately executing it, you can: `npm run build` and then and take a look at the generated code first.\n\n\n## Brief Introduction to Symbolic Expressions\nHere is a basic example of a [symbolic expression](https://en.wikipedia.org/wiki/S-expression) which computes computes `1 + 2`:\n```lisp\n(+ 1 2)\n```\nSymbolic expressions are written in prefix-notation, i.e. Polish notation, so the name of the function, in this case `+` is written first.\nThe function name is followed by its arguments, separated by spaces.\nThe entire expression is enclosed by parentheses, to ensure it is absolutely clear which arguments belong to which function.\nThis also means that the order of execution is made explicit, instead of relying on precedence rules.\nFor a mathematical expression such `1 + 2 * 3`, the usual precedence rule is to compute multiplication before addition.\nIn a symbolic expression, the order of execution is explicit:\n```lisp\n(+ 1 (* 2 3))\n```\n\nIf we want to print something to the console, we can write:\n```lisp\n(display 42)\n```\n\nWe can use a ternary if-expression to do branching.\nSay we wanted to check a condition, `1 \u003e 0`, and if this condition is true we want to print \"All good\", and otherwise we want to print \"Something is wrong\".\nWe could implement this as follows:\n```lisp\n(display\n    (if (\u003e 1 0)\n        \"All good\"\n        \"Something is wrong\"))\n```\n\nWe can create anonymous functions, lambda functions, as follows:\n```lisp\n(-\u003e [a b] (+ 1 (+ a b)))\n```\nThe 'lambda' or 'arrow' function `-\u003e` is an inbuilt function which _creates a new function_.\nThe created function takes a list of arguments `a` and `b`, and returns the value `1 + a + b`.\nThe newly created function is anonymous, i.e. it does not have a name.\nThis lambda function just takes arguments and returns a value.\nGiven a lambda, we can:\n1. provide it argument values and evaluate it immediately\n2. pass it into a higher-order function such as map\n3. assign it a name and use it later via a `let`-binding\n4. assign it a name using `define`, iff we are inside an imperative context such as a `do` block\n\nHere is an example of creating and immediately invoking a lambda:\n```lisp\n((-\u003e [a b] a) 1 2)\n```\nThis creates a very simple function which takes two arguments, `a` and `b`, and returns `a`, i.e. the first of the two arguments.\nThe values `1` and `2` are passed into this lambda function, so this whole expression evaluates to a `1`.\n\n\u003c!-- We can use the keyword `define` to assign names to values, types, and functions, for example to create a variable named `x` with the value `5` we can write:\n```lisp\n(define x 5)\n```\nOr to create a function called `first` which takes two arguments and simply returns the first one of those two, we can write:\n```lisp\n(define first (-\u003e [a b] a))\n```\n\nNote that strictly speaking, `define` is a _procedure_ and not a _function_, since it does not return anything. \nInstead, `define` has side-effects on the context (i.e. environment): it introduces a new name.\nIn this project, the focus lies on symbolic expressions _without_ side-effects, so `define` is only available inside of certain contexts, such as a `do` block. --\u003e\n\n---\n**Copyright (c) 2025 Marco Nikander**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmnikander%2Ftranspiler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmnikander%2Ftranspiler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmnikander%2Ftranspiler/lists"}