created_at2019-08-07 20:35:02.171419
updated_at2019-08-07 20:35:02.171419
descriptionA toy pure-functional language that compiles to SPIR-V



# 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 * Compiles to SPIR-V * Executes vertex+fragment shaders on a real GPU * Simple to use * Simple/fast(?) to build * Runs as a library or as a standalone program ## Anti-goals * Optimized * Super complete * Super ergonomic * Other sorts of shaders * Type inference * Modules # TODO Actually to do: * Replace unwrap with expect. * Ponder error handling better. * Get entry points working better. * Make an actual CLI -- final generated code testing with `spirv-val` maybe should be part of that? * Names/labels/stuff for better debugging. To think about: * Vector swizzling -- do we need it? Can we just do it all with pattern matching? Let's try. * Vector types -- can they just be structs? That would work well with pattern matching. * Enums/option types * Structure layouts and binding * Loops (recursion?) * Math and type system * Play with fuzzing? 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: * Entry point decl's * Scalars besides f32 * Better struct and vector handling # 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 ```
Commit count: 0

cargo fmt