chrysanthemum

A small experiment in making a toy programming language that compiles to SPIR-V shaders for Vulkan.

Basically, I want a compiler targeting SPIRV that is easier to embed than shaderc, and I want to have a mostly-pure-functional shading language (because shaders are, you know, basically pure functions already), so here we are. I'll probably never finish it.

Building

So far it's only been tested on Linux. Probably will work fine on whatever, since there's no platform-specific dependencies.

Running unit tests requires the spirv-val command line program from the official Khronos SPIR-V tools; on Debian you just have to run apt install spirv-tools. glslang-tools may also be useful.

To actually see specifics of what's going on it may also be useful to test with cargo test -- --nocapture --test-threads=1.

Design

This is an experiment on making something compile to SPIR-V more than anything else, so. It's going to be a strongly-typed, pure functional language that probably looks kinda like ML. But I'm starting with the IR and backend for now, 'cause writing parsers is frustrating and slow.

Actually, having no mutation really doesn't make anything harder, since SPIR-V is a SSA form anyway.

Though traditionally the way to handle loops in such language is via recursion, and shaders generally can't be recursive, so that's going to be tricky. We're probably going to either have to introduce loops with attendant mutation (fake or real), or only allow recursion that can be flattened into loops. Though the SPIR-V spec is oddly mostly silent on whether recursion is allowed...

I guess it's not even a real functional language yet either, since it doesn't yet implement functions as values, though it looks like SPIR-V can support it.

Goals

Anti-goals

TODO

Actually to do:

To think about:

To compare against code generated by a (hopefully) known-valid compiler:

```

-G for GLSL semantics, -V for Vulkan semantics.

glslangValidator -V test.frag.glsl; spirv-dis frag.spv ```

To not do YET:

Syntax notes

ML-y syntax or Lispy syntax?

Let's go with ML-y to start, just to see what it looks like.

Really I'm not sure how to handle math operations; we have no generics or traits, so making an Add trait doesn't really work. However, we also have no type inference, so we don't necessarily need OCaml style + vs +. Seems like we can either do it C style and overload math operators as a special case, which I dislike but which is easy in practice, or we can do it ML style and overload nothing, which is simpler but annoying to write.

But we could make it so that adding integers is +, floats is +., vectors is +/ and matrices is ++. Which is almost too cute to resist. For now though, undefined.

``` -- Yes, Lua style comments -- just to mess with people. /- Because why not -/

-- DECLARATIONS

-- Anyway, two types of decl's, functions and structs.

fn foo x: F32, y: F32 -> bool -- ... end

-- Types must start with a capital letter struct SomeStruct x: F32, y: F32, end

-- EXPRESSIONS

-- Floats must have a decimal point let foo: F32 = 10.0

-- Math x + y x - y x * y x / y x % y -- Comparison x == y x != y x > y x >= y x < y x <= y

-- Logic, on booleans. No bitwise stuff yet. x or y x and y x xor y not x

-- Blocks do ... end

-- Function calls foo(x, y, z)

-- Structure literals SomeStruct { x: 1.0, y: 2.0 }

-- Pattern matches

match foo | 1.0 -> foo * 2.0 | 2.0 -> foo / 2.0 | _ -> -9999.0 end

-- Destructuring matches -- variables always are lowercase.

let SomeStruct { x, _ } = foo -- x is now bound

```