https://github.com/mnikander/transpiler
Transpile symbolic expressions to C++
https://github.com/mnikander/transpiler
Last synced: 2 months ago
JSON representation
Transpile symbolic expressions to C++
- Host: GitHub
- URL: https://github.com/mnikander/transpiler
- Owner: mnikander
- License: mit
- Created: 2025-01-27T15:19:30.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2025-03-27T17:11:22.000Z (2 months ago)
- Last Synced: 2025-03-27T18:24:35.016Z (2 months ago)
- Language: TypeScript
- Homepage:
- Size: 142 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Transpiler for Symbolic Expressions
This project transpiles symbolic expressions similar to those found in Lisp and Scheme to C++.
The aim is to experiment with a few language features and learn about compilers and transpilers.
Currently, the focus of the codebase is on the _code generation_ stage of the transpiler.## Getting Started
```bash
sudo apt install nodejs npm g++ cmake
git clone [email protected]:mnikander/transpiler.git
cd transpiler/
npm run clean # the 'clean' target ensures the 'out/' and 'out/artifacts/' directories are created
npm run main # build and run the example
npm test # build and run the unit tests
```Both the main function and the unit tests will automatically transpile their abstract syntax trees to C++ and then compile and execute the resulting programs.
You 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.
**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.## Brief Introduction to Symbolic Expressions
Here is a basic example of a [symbolic expression](https://en.wikipedia.org/wiki/S-expression) which computes computes `1 + 2`:
```lisp
(+ 1 2)
```
Symbolic expressions are written in prefix-notation, i.e. Polish notation, so the name of the function, in this case `+` is written first.
The function name is followed by its arguments, separated by spaces.
The entire expression is enclosed by parentheses, to ensure it is absolutely clear which arguments belong to which function.
This also means that the order of execution is made explicit, instead of relying on precedence rules.
For a mathematical expression such `1 + 2 * 3`, the usual precedence rule is to compute multiplication before addition.
In a symbolic expression, the order of execution is explicit:
```lisp
(+ 1 (* 2 3))
```If we want to print something to the console, we can write:
```lisp
(display 42)
```We can use a ternary if-expression to do branching.
Say we wanted to check a condition, `1 > 0`, and if this condition is true we want to print "All good", and otherwise we want to print "Something is wrong".
We could implement this as follows:
```lisp
(display
(if (> 1 0)
"All good"
"Something is wrong"))
```We can create anonymous functions, lambda functions, as follows:
```lisp
(-> [a b] (+ 1 (+ a b)))
```
The 'lambda' or 'arrow' function `->` is an inbuilt function which _creates a new function_.
The created function takes a list of arguments `a` and `b`, and returns the value `1 + a + b`.
The newly created function is anonymous, i.e. it does not have a name.
This lambda function just takes arguments and returns a value.
Given a lambda, we can:
1. provide it argument values and evaluate it immediately
2. pass it into a higher-order function such as map
3. assign it a name and use it later via a `let`-binding
4. assign it a name using `define`, iff we are inside an imperative context such as a `do` blockHere is an example of creating and immediately invoking a lambda:
```lisp
((-> [a b] a) 1 2)
```
This creates a very simple function which takes two arguments, `a` and `b`, and returns `a`, i.e. the first of the two arguments.
The values `1` and `2` are passed into this lambda function, so this whole expression evaluates to a `1`.---
**Copyright (c) 2025 Marco Nikander**