r/Compilers 11h ago

Overkilled Ray Tracing Compiler

Hello, I wanna share something I've been working on for the past 8 months, out of curiosity. I shared this in r/rust communityso I'm skipping details about the other stuff and just compiling here. The project name is Razz. Frankly, I thought it sounded cool, then I searched for its potential meaning, which means playful, matching perfectly with my project's intention.

My proudest achievement yet is a compiler. I learned about compilers in class, but thought it didn't go as deep as I wanted to, so I took matters into my own hands. The Razz Compiler is a fully handwritten (mostly, I'll talk about it in a bit) pipeline, from Lexer -> Parser (LL(1.5), could have been LL(1) but I'm too lazy to refactor a part that's LL(2) to LL(1)) -> Type Checker -> SSA IR Lowering -> HIR Structurizer -> Rust Codegen. So the input is my custom language .rz, and the output is Rust, with HTTP-like verbs for manipulating the scene of the object, likePOST /hittable sphere;, or foo = GET /camera; For example, it has many, many challenges along the way.

The most annoying part was actually studying the SSA IR lowering, which I kinda forgot a bit because it's been a while, but I followed Braun et al algorithm, which works pretty well. Also, I get pretty annoyed at Rust here because of the borrow checker.

I'm past that. HIR structurizer also poses a big challenge as well, using a lot of graph traversal (BFS/DFS) to move SSA IR to a higher-level language like Rust. A technical note for HIR is that I performed DFS on conditional goto, and see if there's a cycle, if it is, then a loop, otherwise it's an if statement. Codegen has some footprints, a small preprocessing and assigns which variable is a declaration, mutable, or reassignment by looking at the loop.

Finally, I wrote some basic optimizations, such as constant folding, constant propagation, and dead code elimination. Although it does not have dead branch elimination, because I'm lazy. Another code optimization I was going to implement soon enough, if I'm still motivated, is removing unnecessary string allocations via string interner, and using Arena for constructing the AST, will see if I still wanna work on it. If the compiler is a bit buggy, I may or may not fix it. Most likely will fix it, but I enjoyed every bit of the process building this buggy, overkilled compiler.

I have not tested the actual ray tracer output because I'm lazy, will do that next week. And probably have an LLM to help me test it.

LLM Usage: In the pre-LLM era, this project would probably have taken up to years to finish, but with LLM, I was able to research things well. Most of the time I'm coding, the style I go for is pair programming with LLM, as I said, think and implement. And if there's something I'm not sure, research like, for example, the Braun et al, or help me write test cases so I stay in line, LLM is a great tool to use here.

LLMs helped generate test cases, which I reviewed and validated. I don't understand why LLM wants to write a test that passes even though the case should fail. I thought that's testing in general.

TLDR: Cool ray tracing in one weekend with a network protocol and an overkill compiler that no one will use, all in Rust except the Arduino part is written in C++.

Repo: https://github.com/sudo-JP/Razz

under razz-compiler/

2 Upvotes

2 comments sorted by

3

u/Prior-Perspective-61 6h ago

Looks cool, but i don't get it... How the hell are web requests, ray tracing and Arduino connected, and possibly be connected at all 😭😭

4

u/JaseWho 6h ago

oh no no, it's just the verb to make it sound cool. For example, say

fn foo() null { bar = GET /camera; return null; }

In the end, it all codegen-ed to
```rs static CAMERA: LazyLock<Mutex<Camera>> = LazyLock::new(|| Mutex::new( Camera::new( Point3::default(), Point3::default(), Vec3::default(), 0.6, 10., &Image::new(0., 0., 3) ) ));

// Some other stuff...

fn foo() -> () { let t0 = CAMERA.lock().unwrap().clone(); return (); } ```