118 releases (30 breaking)
new 0.38.3 | Oct 24, 2024 |
---|---|
0.37.1 | Oct 10, 2024 |
0.22.0 | Jul 26, 2024 |
0.12.8 | Mar 16, 2024 |
0.0.1 | Sep 13, 2022 |
#122 in Graphics APIs
923 downloads per month
Used in 3 crates
4MB
30K
SLoC
Contains (Mach-o exe, 2MB) PaxCartridge
Pax-Compiler
This document describes the high-level architecture of pax-compiler.
For more information refer to our docs.
Bird's Eye View
Roughly it can be broken down into three steps:
- Analyze the user Pax project (Pax Template + Rust) and generate a Pax Manifest (data structure summarizing the Pax project)
- Code-gen a Pax Manifest into a Pax Cartridge (Rust target agnostic library).
- Build a target platform executable (chassis) with this rust cartridge included.
The main entry-point for all of this is perform_build
found in lib.rs
.
Step 1: Pax Project -> Pax Manifest
Pax projects decorate their associated Rust with a special macro #[derive(Pax)]
. These macros generate code to dynamically analyze their tagged structs. They each add a parse_to_manifest
function for every #[derive(Pax)]
tagged struct. This parse_to_manifest
function (template found here) stores its associated structs information in a ParsingContext object and calls parse_to_manifest
on its Pax Template dependencies. It utilizes logic in parsing.rs
and relies on our pest grammar (pax.pest
) to understand the template dependencies. For the root struct (tagged #[main]
e.g. here), we generate a binary target as well that starts the process and writes the accumulated information into a Pax Manifest and serializes it to stdout. This binary (named parser
) is kicked off (run_parser_binary
) as our first step of the compilation process to generate the Manifest in the lib.rs/perform_build
function.
Step 2: Pax Manifest -> Pax Cartridge
Next we generate the Pax Cartridge. This work is roughly two steps: compiling expressions and generating the cartridge code. The former involves parsing Paxel (Pax's expression language) and generating the equivalent rust code. This work lives in expressions.rs
. Once expressions are compiled, the second step is generating the cartridge code. This lives in the code_generation
module. We utilize Tera templates for the code-gen and the bulk of this work is translating a Pax Manifest into a Tera context. The main entry point is generate_and_overwrite_cartridge
in code_generation/mod.rs
.
Step 3: Building a Chassis with our Pax Cartridge
The last step of this process involves building our target platform (e.g. Web/MacOS/..) scaffolding (see chassis) with our cartridge included. This work lives in the building
module. This mainly involves building the generated cartridge, loading it into our specific chassis and then building that chassis. Currently we support 3 targets (Web/MacOS/iOS). We load our cartridge as WASM for Web and as .dylib
s for our Apple targets.
Consumers
The main consumers of pax-compiler
are pax-cli
and pax-macro
. pax-cli
is the CLI that Pax user's invoke to build Pax projects. pax-macro
is the crate the defines the #[derive(Pax)]
macro that we use for dynamic analysis of the Pax Project (see Step 1).
Dependencies
~40–57MB
~1M SLoC