// The syntax tree of the self-hosted compiler. // A type as written or resolved. // kind: "void" "int" "bool" "char" "float" "str" "null" "ptr" "array" "named" "struct" // elem: the element of an array or the target of a ptr (zero or one entry) // name, module: structs ("" module = the main file) struct Type { str kind []Type elem str name str module int count // "fixed": [N]T, only inside C structs } fn simple(str kind) -> Type { return Type(kind: kind) } fn arrayOf(Type t) -> Type { out := Type(kind: "array") out.elem.push(t) return out } // map[K]V: elem holds the key, then the value fn mapOf(Type k, Type v) -> Type { out := Type(kind: "map") out.elem.push(k) out.elem.push(v) return out } fn ptrTo(Type t) -> Type { out := Type(kind: "ptr") out.elem.push(t) return out } // f32x8, i8x32, u16x16, f64x4: N numbers of one type side by side, worked on all at once (SIMD). // Its kind is "vec", elem[0] the type of one lane, count the number of lanes. kind "" if `name` is no such type. fn vecType(str name) -> Type { x := name.find("x") if x < 2 || x + 1 >= name.len { return Type() } lane := name.sub(0, x) if !["i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "f32", "f64"].contains(lane) { return Type() } n := 0 for c in name.sub(x + 1, name.len) { if c < '0' || c > '9' { return Type() } n = n * 10 + (int(c) - int('0')) } if n != 2 && n != 4 && n != 8 && n != 16 && n != 32 && n != 64 { return Type() } bits := int(lane.sub(1, lane.len)) or 0 if n * bits > 512 { return Type() // the widest registers (AVX-512) hold 512 bits } if lane == "i64" { lane = "int" } else if lane == "f64" { lane = "float" } out := Type(kind: "vec", count: n) out.elem.push(simple(lane)) return out } fn same(Type a, Type b) -> bool { if a.kind != b.kind { return false } if a.kind == "struct" || a.kind == "named" || a.kind == "enum" { return a.name == b.name && a.module == b.module } if (a.kind == "fixed" || a.kind == "vec") && a.count != b.count { return false } if a.kind == "array" || a.kind == "ptr" || a.kind == "map" || a.kind == "fixed" || a.kind == "vec" { if a.elem.len != b.elem.len { return false } for i in 0..a.elem.len { if !same(a.elem[i], b.elem[i]) { return false } } return true } return true } fn show(Type t) -> str { if t.kind == "array" { return "[]" + show(t.elem[0]) } if t.kind == "fixed" { return "[" + str(t.count) + "]" + show(t.elem[0]) } if t.kind == "vec" { lane := t.elem[0].kind if lane == "int" { lane = "i64" } else if lane == "float" { lane = "f64" } return lane + "x" + str(t.count) } if t.kind == "map" { return "map[" + show(t.elem[0]) + "]" + show(t.elem[1]) } if t.kind == "ptr" { if t.elem.len == 0 { return "ptr" } return "ptr[" + show(t.elem[0]) + "]" } if t.kind == "struct" || t.kind == "named" || t.kind == "enum" { if t.module.len > 0 { return t.module + "." + t.name } return t.name } if t.kind == "void" { return "nothing" } return t.kind } // One node of the tree, for expressions, statements, functions and structs alike. // expressions: int float str char bool null var unary binary call member index array method // statements: decl assign expr if while for each return break continue block // top level: fn param struct field enum variant // match: match (kids: subject, arms...), arm (kids: patterns node, body; flag: the else arm), patterns struct Node { str kind str name // identifier, operator, callee, field or method name str recv // fn Point.move(...): "Point"; empty for a plain function []str tparams // fn max[T](...), struct Stack[T], fn Stack[T].push: the type parameters str text // literal text Type ty // declared type (decl, param, field, fn result) bool flag // decl: has a type; or: the right side is a { block } bool fallible // fn: -> T! or -> ! bool exported // export fn: a C function of a library (finch build --shared) []Node kids []str names // named arguments: Point(x: 1) int line int col int file int endLine // block, fn: the line of the closing } } struct Program { str module str path []str imports // Finch modules, by the name this file uses: import ui/button -> "button" []str modules // which module each is: "ui/button" (import path as p: "path") []str cimports // C headers: import "stdio.h" []str cwhere // where each was written, for error messages []str links // link "glfw", link "mine.c" []Node structs []Node enums []Node fns []Node consts // const NAME = value []str tests // the functions made from test "..." { } blocks, in order }