type vec2 = [2]f32 type Sprite = enum u8 { BLANK, PLAYER } type Player = struct { pos, vel vec2 } extern { blit proc(spr Sprite, x, y i32), exp func(v f32) f32 } proc frame(dt f32) { /* unary .. can splat an array as parameters */ blit(.PLAYER, ..plr.pos) plr.pos += plr.vel * dt plr.vel *= exp(-dt * 5) } /* statements type Ident = T Alias Ident to type T extern Ident T Define an external variable (or function!) of the given type extern { a A, b B... } Block of extern declarations, formatted like a struct */ /* expressions N Integer N.N | NeN | N.NeN Float [-+~] A Unary operator on term A A [+-/*%&|^] B Binary operator on term A and expression B A := B Type inference assignment A, B, C := D T { ... } Literal of type T; mostly only makes sense for structs, but this can be used to do something like u8 { 2 } too. /* types IDENT type of the given identifier ^T pointer to type T enum { FOO, BAR... } enum enum T { FOO, BAR... } enum with backing type T, which must be an integer type struct { a A, b B... } struct A..B range (kinda an anonymous enum) A and B must be ordinal types (enum value, integer, or character) [N]T array of T of length N [E]T array of T indexed by enum or range E []T slice (Ta, Tb...) tuple of given types; can be destructured to multiple assignment set[E] a set of enum or range E proc(a A, b B...) function pointer func(a A, b B...) T function pointer with return value T */ Expr = LValue | Literal LValue = Ident | LValue '.' Ident Literal = Number Number = Integer | Float Integer = /[0-9]+/ Float = Integer 'e' Integer | Integer '.' Integer | Integer '.' Integer 'e' Integer IDENT Variable LVALUE . IDENT Member access [0-9]+ Integer [0-9]+ . [0-9]+ Float [0-9]+ . [0-9]+ e [0-9]+ Float F(E1, E2...) function call with the given expression arguments */ /* import first tries to scan local directory for the package, then standard * system directory; in said directory it will look for an IR cache file, * or compile a new one if it's not present (or if its last-modified time * is older than the compiler executable), which is imported with a name * equivalent to the last part of the path. * * codegen is only performed on procedures that get called from main and their * own dependencies, recursively. this allows to keep output binaries small. * maybe supply some sort of export qualifier to do something similar for * procedures that aren't main. */ import "io" proc main { io.print("Hello, world!") }