dusty-phillips / macabre

experimental and slightly-functional gleam-to-python transpiler
Apache License 2.0
3 stars 1 forks source link

Macabre

macabre : (adj) tending to produce horror in a beholder

This is an ultra experimental compiler written in Gleam to compile Gleam source code (using the glance package) to Python.

It covers a pretty decent swath of Gleam syntax, and I made a point of prioritizing the hardest syntax. There is a big pile of TODOs at the end of this file if you want to contribute.

My current vision is to have fun while making this a self-hosted compiler. Once it can compile itself to Python (bonus points if it runs on a variation of gleam_otp that uses Python's upcoming new experimental multi-threaded support), well at that point, I'll have to come up with a new vision. Maybe something to do with supporting other compilation targets, such as Gleam's native Erlang and Javascript environments.

Probability of achieving this vision: pretty low. This is a for-fun free time project for me. I'm currently on sabbatical so I have time for odd little projects like this.

Usage

The complier runs on gleam erlang successfully. I think it might work with Javascript as I don't think I'm using any erlang-specific libraries yet. It can't compile itself to python yet, but I'm hoping to get there.

To run it, pass it a properly structured macabre folder as the only argument:

gleam run -- some_package_folder

The package folder should have a structure similar to a normal Gleam project:

folder
├── gleam.toml
├── build
│   └── <generated stuff>
└─ src
    ├── <repo_name>.gleam
    ├── some_folder
    │   ├── something.gleam
    │   └── bindings.py
    ├── some_file.gleam
    └── some_bindings.py

The gleam.toml only supports two keys, name and dependencies:

name = "example"

[dependencies]
macabre_stdlib = "git@github.com:dusty-phillips/macabre_stdlib.git"

Note that dependencies are currently not hex packages like a normal gleam project. Rather, they are git repositories. This is mostly because I didn't feel comfortable cluttering hex with silly dependencies for my silly project.

The compiler expects git to be installed, and will clone any git repos that are listed.

[!WARNING} It currently downloads everything from scratch every time you invoke it, so don't try this on a metered connection!

Macabre copies the src/ folder of each package into the build directory and then builds all dependencies from scratch (every single time). Your source files are also copied into this folder.

Your main module will always be <repo_name>.gleam where <repo_name> is whatever you put in the name in gleam.toml.

Your files are compiled to build/dev/python. If your <repo_name>.gleam has a main function in it, then the compiler will generate a build/dev/python/__main__.py to call that function.

Use this command to invoke it:

python build/dev/python

Development

Run tests with gleeunit:

gleam test

Run tests in watch mode:

fd .gleam | entr gleam test

Contributing

PRs are welcome.

The main entry point is macabre.gleam, which handles all file loading and other side effects.

The package depends on the glance AST parser, and glimpse, a package I wrote to wrap glance to support multiple inter-dependent modules. (Eventually I want it to also be a glance typechecker)

The compiler is pure gleam. Most of the work happens in transformer.gleam and generator.gleam. The former converts the Gleam AST to a Python AST, the latter generates python code. There are tons of helper functions in various other files.

The Python AST is in python.gleam. This doesn't model all of python; just the subset that is needed to map Gleam expressions to.

Some tasks below are marked easy if you want to get started.

Outstanding tasks

High Pri

Low Pri