about summary refs log tree commit diff
path: root/boot/tests/lower
diff options
context:
space:
mode:
authorMel <mel@rnrd.eu>2026-05-06 18:49:26 +0200
committerMel <mel@rnrd.eu>2026-05-06 18:49:26 +0200
commit952250b6d79063aa1066b0e945d58360bd70d09f (patch)
tree8eff74504b558d5a83485cebd4d8c5808e0064a9 /boot/tests/lower
parentac696b22b3f03ae9670a9d1d154ce7ff848b5e55 (diff)
downloadcatskill-952250b6d79063aa1066b0e945d58360bd70d09f.tar.zst
catskill-952250b6d79063aa1066b0e945d58360bd70d09f.zip
Lowering pass test harness, and initial pass test suite
Signed-off-by: Mel <mel@rnrd.eu>
Diffstat (limited to 'boot/tests/lower')
-rw-r--r--boot/tests/lower/c_for_loop.cskt35
-rw-r--r--boot/tests/lower/compound_assigns.cskt31
-rw-r--r--boot/tests/lower/empty_main.cskt23
-rw-r--r--boot/tests/lower/if_else_chain.cskt38
-rw-r--r--boot/tests/lower/range_for_loop.cskt33
-rw-r--r--boot/tests/lower/shadowing_error.cskt29
-rw-r--r--boot/tests/lower/simple_var.cskt26
-rw-r--r--boot/tests/lower/structural_dedup.cskt29
-rw-r--r--boot/tests/lower/type_cycle_error.cskt29
-rw-r--r--boot/tests/lower/type_simple_struct.cskt23
-rw-r--r--boot/tests/lower/type_with_pointer_self.cskt21
-rw-r--r--boot/tests/lower/while_loop.cskt34
12 files changed, 351 insertions, 0 deletions
diff --git a/boot/tests/lower/c_for_loop.cskt b/boot/tests/lower/c_for_loop.cskt
new file mode 100644
index 0000000..98d78f0
--- /dev/null
+++ b/boot/tests/lower/c_for_loop.cskt
@@ -0,0 +1,35 @@
+c-style for loops are turned into the single loop kind,
+with the initializer and the iteration step statements synthesized into
+statements within the block.
+
+<<<
+
+main = fun () {
+    for i int = 0, i < 10, i++ {
+        var x int = i
+    }
+}
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive))
+	(functions
+		(function 0 main main (returns (ref void)) (block
+			(block
+				(declaration i (ref int) (initializer (expr 0)))
+				(loop (condition (expr (binary < (expr (name i)) (expr 10)))) (block
+					(declaration x (ref int) (initializer (expr (name i))))
+					(assign (expr (name i)) (expr (binary + (expr (name i)) (expr 1))))
+				))
+			)
+		)))
+	(emission_order 0 1 2 3 4 5 6 7))
diff --git a/boot/tests/lower/compound_assigns.cskt b/boot/tests/lower/compound_assigns.cskt
new file mode 100644
index 0000000..214fe59
--- /dev/null
+++ b/boot/tests/lower/compound_assigns.cskt
@@ -0,0 +1,31 @@
+compound assignment operators are split during lowering.
+
+<<<
+
+main = fun () {
+    var x int = 0
+    x += 1
+    x *= 2
+    x -= 3
+}
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive))
+	(functions
+		(function 0 main main (returns (ref void)) (block
+			(declaration x (ref int) (initializer (expr 0)))
+			(assign (expr (name x)) (expr (binary + (expr (name x)) (expr 1))))
+			(assign (expr (name x)) (expr (binary * (expr (name x)) (expr 2))))
+			(assign (expr (name x)) (expr (binary - (expr (name x)) (expr 3))))
+		)))
+	(emission_order 0 1 2 3 4 5 6 7))
diff --git a/boot/tests/lower/empty_main.cskt b/boot/tests/lower/empty_main.cskt
new file mode 100644
index 0000000..8e4635f
--- /dev/null
+++ b/boot/tests/lower/empty_main.cskt
@@ -0,0 +1,23 @@
+the simplest possible translation unit. seeds the eight primitive
+types and registers a single, empty `main` function.
+
+<<<
+
+main = fun () {
+}
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive))
+	(functions
+		(function 0 main main (returns (ref void)) (block)))
+	(emission_order 0 1 2 3 4 5 6 7))
\ No newline at end of file
diff --git a/boot/tests/lower/if_else_chain.cskt b/boot/tests/lower/if_else_chain.cskt
new file mode 100644
index 0000000..a8bf358
--- /dev/null
+++ b/boot/tests/lower/if_else_chain.cskt
@@ -0,0 +1,38 @@
+a three-branch if/else-if/else chain lowers to a single flat
+conditional.
+
+<<<
+
+classify = fun (n int) int {
+    if n < 0 {
+        return -1
+    } else if n == 0 {
+        return 0
+    } else {
+        return 1
+    }
+}
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive))
+	(functions
+		(function 0 classify (returns (ref int)) (param n (ref int)) (block
+			(conditional (when (expr (binary < (expr (name n)) (expr 0)))) (block
+				(return (expr (unary - (expr 1))))
+			) (when (expr (binary == (expr (name n)) (expr 0)))) (block
+				(return (expr 0))
+			) (else) (block
+				(return (expr 1))
+			))
+		)))
+	(emission_order 0 1 2 3 4 5 6 7))
diff --git a/boot/tests/lower/range_for_loop.cskt b/boot/tests/lower/range_for_loop.cskt
new file mode 100644
index 0000000..64ffe0b
--- /dev/null
+++ b/boot/tests/lower/range_for_loop.cskt
@@ -0,0 +1,33 @@
+a range for-each is rewritten into a c-style loop.
+
+<<<
+
+main = fun () {
+    for i int = 0..10 {
+        var x int = i
+    }
+}
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive))
+	(functions
+		(function 0 main main (returns (ref void)) (block
+			(block
+				(declaration i (ref int) (initializer (expr 0)))
+				(loop (condition (expr (binary < (expr (name i)) (expr 10)))) (block
+					(declaration x (ref int) (initializer (expr (name i))))
+					(assign (expr (name i)) (expr (binary + (expr (name i)) (expr 1))))
+				))
+			)
+		)))
+	(emission_order 0 1 2 3 4 5 6 7))
diff --git a/boot/tests/lower/shadowing_error.cskt b/boot/tests/lower/shadowing_error.cskt
new file mode 100644
index 0000000..b22dddf
--- /dev/null
+++ b/boot/tests/lower/shadowing_error.cskt
@@ -0,0 +1,29 @@
+declaring two locals with the same name in overlapping scopes is
+a hard error.
+
+<<<
+
+main = fun () {
+    var x int = 1
+    var x int = 2
+}
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive))
+	(functions
+		(function 0 main main (returns (ref void)) (block
+			(declaration x (ref int) (initializer (expr 1)))
+		)))
+	(emission_order 0 1 2 3 4 5 6 7)
+	(diagnostics
+		(error "name 'x' shadows an existing binding")))
diff --git a/boot/tests/lower/simple_var.cskt b/boot/tests/lower/simple_var.cskt
new file mode 100644
index 0000000..b1b0c92
--- /dev/null
+++ b/boot/tests/lower/simple_var.cskt
@@ -0,0 +1,26 @@
+a single typed variable declaration with an integer initializer
+inside the body of `main`.
+
+<<<
+
+main = fun () {
+    var x int = 5
+}
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive))
+	(functions
+		(function 0 main main (returns (ref void)) (block
+			(declaration x (ref int) (initializer (expr 5)))
+		)))
+	(emission_order 0 1 2 3 4 5 6 7))
\ No newline at end of file
diff --git a/boot/tests/lower/structural_dedup.cskt b/boot/tests/lower/structural_dedup.cskt
new file mode 100644
index 0000000..ee4bcd3
--- /dev/null
+++ b/boot/tests/lower/structural_dedup.cskt
@@ -0,0 +1,29 @@
+two functions taking the same anonymous tuple type produce just
+one synthesized type entry.
+
+<<<
+
+f = fun (a (int, int)) int { return 0 }
+g = fun (b (int, int)) int { return 0 }
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive)
+		(type 8 __cat_type_0 synthetic structure (field _0 (ref int)) (field _1 (ref int)) (depends_on 0 0)))
+	(functions
+		(function 0 f (returns (ref int)) (param a (ref __cat_type_0)) (block
+			(return (expr 0))
+		))
+		(function 1 g (returns (ref int)) (param b (ref __cat_type_0)) (block
+			(return (expr 0))
+		)))
+	(emission_order 0 1 2 3 4 5 6 7 8))
diff --git a/boot/tests/lower/type_cycle_error.cskt b/boot/tests/lower/type_cycle_error.cskt
new file mode 100644
index 0000000..29b791e
--- /dev/null
+++ b/boot/tests/lower/type_cycle_error.cskt
@@ -0,0 +1,29 @@
+two types referencing each other by value form a cycle that
+we cannot resolve.
+the diagnostic should point out the correct cycle.
+
+<<<
+
+A = type { b B }
+B = type { a A }
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive)
+		(type 8 A structure (field b (ref B)) (depends_on 9))
+		(type 9 B structure (field a (ref A)) (depends_on 8)))
+	(emission_order 0 1 2 3 4 5 6 7)
+	(diagnostics
+		(error "type cycle detected:
+  A (line 1) depends on B
+  B (line 2) depends on A
+hint: break the cycle with a reference (use `&T` instead of `T`). :)")))
diff --git a/boot/tests/lower/type_simple_struct.cskt b/boot/tests/lower/type_simple_struct.cskt
new file mode 100644
index 0000000..085d9db
--- /dev/null
+++ b/boot/tests/lower/type_simple_struct.cskt
@@ -0,0 +1,23 @@
+a top-level struct declaration produces a structure type entry
+with each field's type interned.
+the by-value dependencies are correctly added as dependencies
+and contribute to the ordering.
+
+<<<
+
+Point = type { x int, y int }
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive)
+		(type 8 Point structure (field x (ref int)) (field y (ref int)) (depends_on 0 0)))
+	(emission_order 0 1 2 3 4 5 6 7 8))
diff --git a/boot/tests/lower/type_with_pointer_self.cskt b/boot/tests/lower/type_with_pointer_self.cskt
new file mode 100644
index 0000000..6a0b689
--- /dev/null
+++ b/boot/tests/lower/type_with_pointer_self.cskt
@@ -0,0 +1,21 @@
+a self-referential structure relying on indirection via a reference.
+a dependency should not be added as the reference is not by-value.
+
+<<<
+
+Node = type { value int, next &Node }
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive)
+		(type 8 Node structure (field value (ref int)) (field next (ref & Node)) (depends_on 0)))
+	(emission_order 0 1 2 3 4 5 6 7 8))
diff --git a/boot/tests/lower/while_loop.cskt b/boot/tests/lower/while_loop.cskt
new file mode 100644
index 0000000..b191df5
--- /dev/null
+++ b/boot/tests/lower/while_loop.cskt
@@ -0,0 +1,34 @@
+while loops are 1:1 with the intermediate representation's
+single loop kind.
+compound assignments desugar into a simple pair of a simple
+assignment and binary operation.
+
+<<<
+
+main = fun () {
+    var i int = 0
+    while i < 10 {
+        i++
+    }
+}
+
+>>>
+
+(unit
+	(types
+		(type 0 int primitive)
+		(type 1 uint primitive)
+		(type 2 bool primitive)
+		(type 3 string primitive)
+		(type 4 float primitive)
+		(type 5 byte primitive)
+		(type 6 ascii primitive)
+		(type 7 void primitive))
+	(functions
+		(function 0 main main (returns (ref void)) (block
+			(declaration i (ref int) (initializer (expr 0)))
+			(loop (condition (expr (binary < (expr (name i)) (expr 10)))) (block
+				(assign (expr (name i)) (expr (binary + (expr (name i)) (expr 1))))
+			))
+		)))
+	(emission_order 0 1 2 3 4 5 6 7))