// tests/native/test_compiler.el — comprehensive tests for the El compiler pipeline. // // Tests the lexer (lexer.el), parser (parser.el), and codegen (codegen.el) // through the compile() entry point in compiler.el. // // Compiled and run via the native test harness: // elc --test tests/native/test_compiler.el > /tmp/el_compiler_tests.c // gcc -O2 -I runtime /tmp/el_compiler_tests.c runtime/el_runtime.c -lcurl -lpthread -lm -o /tmp/el_compiler_tests // /tmp/el_compiler_tests import "../../el-compiler/src/lexer.el" import "../../el-compiler/src/parser.el" import "../../el-compiler/src/codegen.el" import "../../el-compiler/src/codegen-js.el" import "../../el-compiler/src/compiler.el" // ── Lexer helpers ───────────────────────────────────────────────────────────── fn tok_count(tokens: [Any]) -> Int { native_list_len(tokens) / 2 } // ── Codegen helper: capture compile() stdout to a string ───────────────────── fn compile_capture(src: String) -> String { let tmp: String = "/tmp/el_compiler_test_" + int_to_str(time_now()) + ".c" stdout_to_file(tmp) compile(src) stdout_restore() fs_read(tmp) } // ── Lexer tests ─────────────────────────────────────────────────────────────── test "lex-empty" { let tokens: [Any] = lex("") assert tok_count(tokens) == 1, "empty source yields only Eof" assert tok_kind(tokens, 0) == "Eof", "single token is Eof" } test "lex-whitespace-stripped" { let tokens: [Any] = lex(" \t\n\r ") assert tok_count(tokens) == 1, "whitespace-only yields only Eof" } test "lex-comment-stripped" { let tokens: [Any] = lex("// this is a comment\n// another") assert tok_count(tokens) == 1, "comments stripped — only Eof" } test "lex-int-literals" { let tokens: [Any] = lex("0 1 42 100 999") assert tok_count(tokens) == 6, "five int literals + Eof" assert tok_kind(tokens, 0) == "Int", "first is Int" assert tok_value(tokens, 0) == "0", "value is 0" assert tok_kind(tokens, 2) == "Int", "third is Int" assert tok_value(tokens, 2) == "42", "value is 42" assert tok_kind(tokens, 4) == "Int", "fifth is Int" assert tok_value(tokens, 4) == "999", "value is 999" } test "lex-float-literals" { let tokens: [Any] = lex("3.14 0.0 1.5") assert tok_count(tokens) == 4, "three float literals + Eof" assert tok_kind(tokens, 0) == "Float", "first is Float" assert tok_value(tokens, 0) == "3.14", "value is 3.14" assert tok_kind(tokens, 1) == "Float", "second is Float" assert tok_value(tokens, 1) == "0.0", "value is 0.0" } test "lex-string-literals" { let tokens: [Any] = lex("\"hello\" \"world\" \"\"") assert tok_count(tokens) == 4, "three string literals + Eof" assert tok_kind(tokens, 0) == "Str", "first is Str" assert tok_value(tokens, 0) == "hello", "value is hello" assert tok_kind(tokens, 2) == "Str", "third is Str" assert tok_value(tokens, 2) == "", "empty string value is empty" } test "lex-string-escape-newline" { let tokens: [Any] = lex("\"hello\\nworld\"") assert tok_count(tokens) == 2, "one Str token + Eof" assert tok_kind(tokens, 0) == "Str", "is Str" let val: String = tok_value(tokens, 0) assert str_contains(val, "hello"), "value contains hello" assert str_contains(val, "world"), "value contains world" assert str_len(val) == 11, "hello + newline + world = 11 chars" } test "lex-string-escape-tab" { let tokens: [Any] = lex("\"a\\tb\"") assert tok_count(tokens) == 2, "one Str + Eof" let val: String = tok_value(tokens, 0) assert str_len(val) == 3, "a + tab + b = 3 chars" } test "lex-string-escape-backslash" { let tokens: [Any] = lex("\"a\\\\b\"") assert tok_count(tokens) == 2, "one Str + Eof" let val: String = tok_value(tokens, 0) assert str_len(val) == 3, "a + backslash + b = 3 chars" } test "lex-bool-literals" { let tokens: [Any] = lex("true false") assert tok_count(tokens) == 3, "two Bool tokens + Eof" assert tok_kind(tokens, 0) == "Bool", "first is Bool" assert tok_value(tokens, 0) == "true", "first is true" assert tok_kind(tokens, 1) == "Bool", "second is Bool" assert tok_value(tokens, 1) == "false", "second is false" } test "lex-identifier" { let tokens: [Any] = lex("foo bar _under _123") assert tok_count(tokens) == 5, "four idents + Eof" assert tok_kind(tokens, 0) == "Ident", "foo is Ident" assert tok_value(tokens, 0) == "foo", "value is foo" assert tok_kind(tokens, 2) == "Ident", "underscore ident recognized" assert tok_value(tokens, 2) == "_under", "value is _under" } test "lex-keywords" { let tokens: [Any] = lex("let fn if else while for return import type enum match") assert tok_count(tokens) == 12, "eleven keywords + Eof" assert tok_kind(tokens, 0) == "Let", "let keyword" assert tok_kind(tokens, 1) == "Fn", "fn keyword" assert tok_kind(tokens, 2) == "If", "if keyword" assert tok_kind(tokens, 3) == "Else", "else keyword" assert tok_kind(tokens, 4) == "While", "while keyword" assert tok_kind(tokens, 5) == "For", "for keyword" assert tok_kind(tokens, 6) == "Return", "return keyword" assert tok_kind(tokens, 7) == "Import", "import keyword" assert tok_kind(tokens, 8) == "Type", "type keyword" assert tok_kind(tokens, 9) == "Enum", "enum keyword" assert tok_kind(tokens, 10) == "Match", "match keyword" } test "lex-more-keywords" { let tokens: [Any] = lex("extern break continue") assert tok_count(tokens) == 4, "three keywords + Eof" assert tok_kind(tokens, 0) == "Extern", "extern keyword" assert tok_kind(tokens, 1) == "Break", "break keyword" assert tok_kind(tokens, 2) == "Continue", "continue keyword" } test "lex-keyword-values" { let tokens: [Any] = lex("let fn return") assert tok_value(tokens, 0) == "let", "let value is let" assert tok_value(tokens, 1) == "fn", "fn value is fn" assert tok_value(tokens, 2) == "return", "return value is return" } test "lex-arithmetic-operators" { let tokens: [Any] = lex("+ - * / %") assert tok_count(tokens) == 6, "five ops + Eof" assert tok_kind(tokens, 0) == "Plus", "plus" assert tok_kind(tokens, 1) == "Minus", "minus" assert tok_kind(tokens, 2) == "Star", "star" assert tok_kind(tokens, 3) == "Slash", "slash" assert tok_kind(tokens, 4) == "Percent", "percent" } test "lex-comparison-operators" { let tokens: [Any] = lex("== != < > <= >=") assert tok_count(tokens) == 7, "six ops + Eof" assert tok_kind(tokens, 0) == "EqEq", "eqeq" assert tok_value(tokens, 0) == "==", "eqeq value" assert tok_kind(tokens, 1) == "NotEq", "noteq" assert tok_kind(tokens, 2) == "Lt", "lt" assert tok_kind(tokens, 3) == "Gt", "gt" assert tok_kind(tokens, 4) == "LtEq", "lteq" assert tok_kind(tokens, 5) == "GtEq", "gteq" } test "lex-logical-operators" { let tokens: [Any] = lex("&& || !") assert tok_count(tokens) == 4, "three logical ops + Eof" assert tok_kind(tokens, 0) == "And", "and" assert tok_value(tokens, 0) == "&&", "and value" assert tok_kind(tokens, 1) == "Or", "or" assert tok_kind(tokens, 2) == "Not", "not" } test "lex-arrow-tokens" { let tokens: [Any] = lex("-> =>") assert tok_count(tokens) == 3, "arrow + fat-arrow + Eof" assert tok_kind(tokens, 0) == "Arrow", "thin arrow" assert tok_value(tokens, 0) == "->", "arrow value" assert tok_kind(tokens, 1) == "FatArrow", "fat arrow" } test "lex-delimiters" { let tokens: [Any] = lex("( ) [ ] { } , : ; .") assert tok_count(tokens) == 11, "ten delimiters + Eof" assert tok_kind(tokens, 0) == "LParen", "lparen" assert tok_kind(tokens, 1) == "RParen", "rparen" assert tok_kind(tokens, 2) == "LBracket", "lbracket" assert tok_kind(tokens, 3) == "RBracket", "rbracket" assert tok_kind(tokens, 4) == "LBrace", "lbrace" assert tok_kind(tokens, 5) == "RBrace", "rbrace" assert tok_kind(tokens, 6) == "Comma", "comma" assert tok_kind(tokens, 7) == "Colon", "colon" assert tok_kind(tokens, 8) == "Semicolon", "semicolon" assert tok_kind(tokens, 9) == "Dot", "dot" } test "lex-double-colon" { let tokens: [Any] = lex("::") assert tok_count(tokens) == 2, "colons + Eof" assert tok_kind(tokens, 0) == "ColonColon", "double colon" assert tok_value(tokens, 0) == "::", "double colon value" } test "lex-dot-dot" { let tokens: [Any] = lex(".. ..=") assert tok_count(tokens) == 3, "two range tokens + Eof" assert tok_kind(tokens, 0) == "DotDot", "dotdot" assert tok_kind(tokens, 1) == "DotDotEq", "dotdoteq" } test "lex-pipe-operators" { let tokens: [Any] = lex("| || |>") assert tok_count(tokens) == 4, "three pipe tokens + Eof" assert tok_kind(tokens, 0) == "Pipe", "pipe" assert tok_kind(tokens, 1) == "Or", "or" assert tok_kind(tokens, 2) == "PipeOp", "pipe-op" } test "lex-at-and-question" { let tokens: [Any] = lex("@ ?") assert tok_count(tokens) == 3, "at + question + Eof" assert tok_kind(tokens, 0) == "At", "at sign" assert tok_kind(tokens, 1) == "QuestionMark", "question mark" } test "lex-eof-always-last" { let t1: [Any] = lex("x") let t2: [Any] = lex("let x = 1") let t3: [Any] = lex("") let n1: Int = tok_count(t1) let n2: Int = tok_count(t2) let n3: Int = tok_count(t3) assert tok_kind(t1, n1 - 1) == "Eof", "eof last after single ident" assert tok_kind(t2, n2 - 1) == "Eof", "eof last after let stmt" assert tok_kind(t3, n3 - 1) == "Eof", "eof last after empty" } test "lex-string-with-spaces" { let tokens: [Any] = lex("\"hello world\"") assert tok_count(tokens) == 2, "string with space: 1 Str + Eof" assert tok_value(tokens, 0) == "hello world", "internal space preserved" } test "lex-multiline-source" { let src: String = "let x: Int = 1\nlet y: Int = 2\n" let tokens: [Any] = lex(src) assert tok_count(tokens) > 5, "multiline source produces multiple tokens" assert tok_kind(tokens, 0) == "Let", "first token is Let" } test "lex-flat-stride-2-layout" { // Verify that the flat stride-2 layout: token i has kind at index 2*i, value at 2*i+1 let tokens: [Any] = lex("fn foo") // tokens[0] = "Fn", tokens[1] = "fn", tokens[2] = "Ident", tokens[3] = "foo", ... let raw_len: Int = native_list_len(tokens) assert raw_len == 6, "fn + foo + Eof = 3 tokens = 6 raw entries" let kind0: String = native_list_get(tokens, 0) let val0: String = native_list_get(tokens, 1) let kind1: String = native_list_get(tokens, 2) let val1: String = native_list_get(tokens, 3) assert kind0 == "Fn", "raw[0] is Fn kind" assert val0 == "fn", "raw[1] is fn value" assert kind1 == "Ident", "raw[2] is Ident kind" assert val1 == "foo", "raw[3] is foo value" } // ── Parser tests ────────────────────────────────────────────────────────────── fn get_first_stmt_kind(src: String) -> String { let tokens: [Any] = lex(src) let stmts: [Map] = parse(tokens) if native_list_len(stmts) == 0 { return "" } let first: Map = native_list_get(stmts, 0) first["stmt"] } fn get_first_stmt(src: String) -> Map { let tokens: [Any] = lex(src) let stmts: [Map] = parse(tokens) native_list_get(stmts, 0) } test "parse-let-stmt" { assert get_first_stmt_kind("let x: Int = 5") == "Let", "let int stmt" assert get_first_stmt_kind("let s: String = \"hi\"") == "Let", "let string stmt" assert get_first_stmt_kind("let b: Bool = true") == "Let", "let bool stmt" let stmt: Map = get_first_stmt("let x: Int = 42") let name: String = stmt["name"] assert name == "x", "let name is x" } test "parse-fn-decl" { assert get_first_stmt_kind("fn foo() -> Void { }") == "FnDef", "fn declaration" assert get_first_stmt_kind("fn bar(x: Int) -> Int { return x }") == "FnDef", "fn with param" let stmt: Map = get_first_stmt("fn foo() -> Void { }") let name: String = stmt["name"] assert name == "foo", "fn name is foo" } test "parse-fn-params" { let stmt: Map = get_first_stmt("fn bar(x: Int, y: String) -> Int { return 0 }") let params = stmt["params"] let n: Int = native_list_len(params) assert n == 2, "fn has 2 params" let p0: Map = native_list_get(params, 0) let p1: Map = native_list_get(params, 1) assert p0["name"] == "x", "first param name x" assert p1["name"] == "y", "second param name y" } test "parse-return-stmt" { let tokens: [Any] = lex("fn f() -> Int { return 42 }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let n: Int = native_list_len(body) assert n > 0, "fn body non-empty" let ret: Map = native_list_get(body, 0) assert ret["stmt"] == "Return", "return stmt kind" } test "parse-if-stmt" { // In El, `if` is an expression. Standalone `if` in a fn body is wrapped // as Expr stmt with value.expr == "If". let tokens: [Any] = lex("fn f() -> Int { if x > 0 { return 1 } return 0 }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let first_body: Map = native_list_get(body, 0) assert first_body["stmt"] == "Expr", "if stmt in fn body is Expr wrapper" let val = first_body["value"] assert val["expr"] == "If", "Expr wraps If expression" } test "parse-if-else" { let tokens: [Any] = lex("fn f() -> Int { if x > 0 { return 1 } else { return 0 } }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] // if-else is also an Expr stmt wrapping an If expression let expr_stmt: Map = native_list_get(body, 0) assert expr_stmt["stmt"] == "Expr", "if-else is Expr stmt" let if_node = expr_stmt["value"] assert if_node["expr"] == "If", "Expr wraps If expression" let has_else: Bool = if_node["has_else"] assert has_else, "if-else has else branch" } test "parse-while-stmt" { let tokens: [Any] = lex("fn f() -> Void { while i < 10 { i = i + 1 } }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let while_node: Map = native_list_get(body, 0) assert while_node["stmt"] == "While", "while stmt kind" } test "parse-import-stmt" { assert get_first_stmt_kind("import \"some/module.el\"") == "Import", "import stmt" } test "parse-extern-fn" { assert get_first_stmt_kind("extern fn native_op(x: Int) -> Int") == "ExternFn", "extern fn" } test "parse-let-int-value" { let stmt: Map = get_first_stmt("let n: Int = 99") let val = stmt["value"] let val_kind: String = val["expr"] assert val_kind == "Int", "let value is Int expr" let v: String = val["value"] assert v == "99", "int literal value 99" } test "parse-let-string-value" { let stmt: Map = get_first_stmt("let s: String = \"hello\"") let val = stmt["value"] let val_kind: String = val["expr"] assert val_kind == "Str", "let value is Str expr" let v: String = val["value"] assert v == "hello", "string literal value hello" } test "parse-let-bool-value" { let stmt: Map = get_first_stmt("let b: Bool = true") let val = stmt["value"] let val_kind: String = val["expr"] assert val_kind == "Bool", "let value is Bool expr" } test "parse-binop-expr" { let stmt: Map = get_first_stmt("let x: Int = 1 + 2") let val = stmt["value"] let val_kind: String = val["expr"] assert val_kind == "BinOp", "let value is BinOp" let op: String = val["op"] assert op == "Plus", "binop is Plus" } test "parse-call-expr" { let tokens: [Any] = lex("fn f() -> Void { println(\"hi\") }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let expr_stmt: Map = native_list_get(body, 0) assert expr_stmt["stmt"] == "Expr", "call is Expr stmt" let val = expr_stmt["value"] let val_kind: String = val["expr"] assert val_kind == "Call", "expr is Call" } test "parse-multiple-fns" { let src: String = "fn a() -> Int { return 1 }\nfn b() -> Int { return 2 }" let tokens: [Any] = lex(src) let stmts: [Map] = parse(tokens) assert native_list_len(stmts) == 2, "two fn declarations parsed" let s0: Map = native_list_get(stmts, 0) let s1: Map = native_list_get(stmts, 1) assert s0["name"] == "a", "first fn name a" assert s1["name"] == "b", "second fn name b" } test "parse-assign-stmt" { let tokens: [Any] = lex("fn f() -> Void { x = 42 }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let a: Map = native_list_get(body, 0) assert a["stmt"] == "Assign", "assign stmt kind" assert a["name"] == "x", "assign target x" } test "parse-for-stmt" { let tokens: [Any] = lex("fn f() -> Void { for x in items { println(x) } }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let for_node: Map = native_list_get(body, 0) assert for_node["stmt"] == "For", "for stmt kind" assert for_node["item"] == "x", "for item is x" } test "parse-unary-not" { let tokens: [Any] = lex("fn f() -> Bool { return !x }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let ret: Map = native_list_get(body, 0) let val = ret["value"] assert val["expr"] == "Not", "unary not is Not expr" } test "parse-unary-neg" { let tokens: [Any] = lex("fn f() -> Int { return -5 }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let ret: Map = native_list_get(body, 0) let val = ret["value"] assert val["expr"] == "Neg", "unary minus is Neg expr" } test "parse-array-literal" { let tokens: [Any] = lex("fn f() -> [Int] { return [1, 2, 3] }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let ret: Map = native_list_get(body, 0) let val = ret["value"] assert val["expr"] == "Array", "array literal is Array expr" let elems = val["elems"] assert native_list_len(elems) == 3, "array has 3 elements" } test "parse-empty-array" { let tokens: [Any] = lex("fn f() -> [Int] { return [] }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let ret: Map = native_list_get(body, 0) let val = ret["value"] assert val["expr"] == "Array", "empty array is Array expr" let elems = val["elems"] assert native_list_len(elems) == 0, "empty array has 0 elements" } test "parse-index-expr" { let tokens: [Any] = lex("fn f() -> Any { return arr[0] }") let stmts: [Map] = parse(tokens) let fn_node: Map = native_list_get(stmts, 0) let body = fn_node["body"] let ret: Map = native_list_get(body, 0) let val = ret["value"] assert val["expr"] == "Index", "array index is Index expr" } // ── Codegen tests ───────────────────────────────────────────────────────────── test "codegen-includes" { let out: String = compile_capture("fn main() -> Void { }") assert str_contains(out, "#include"), "output has #include" assert str_contains(out, "el_runtime.h"), "output includes el_runtime.h" } test "codegen-int-main" { let out: String = compile_capture("fn main() -> Void { }") assert str_contains(out, "int main("), "output has int main()" } test "codegen-runtime-init" { let out: String = compile_capture("fn main() -> Void { }") assert str_contains(out, "el_runtime_init_args("), "runtime init in main" } test "codegen-void-function-signature" { let out: String = compile_capture("fn f() -> Int { return 0 }") assert str_contains(out, "f(void)"), "no-param fn uses void signature" } test "codegen-function-with-params" { let out: String = compile_capture("fn add(x: Int, y: Int) -> Int { return x + y }") assert str_contains(out, "add("), "function add in output" assert str_contains(out, "el_val_t x"), "param x in output" assert str_contains(out, "el_val_t y"), "param y in output" } test "codegen-int-literal" { let out: String = compile_capture("fn answer() -> Int { return 42 }") assert str_contains(out, "42"), "integer literal 42 in output" assert str_contains(out, "return"), "return statement in output" } test "codegen-string-literal" { let out: String = compile_capture("fn greet() -> String { return \"hello\" }") assert str_contains(out, "hello"), "string literal hello in output" } test "codegen-if-statement" { let src: String = "fn check(x: Int) -> Int { if x > 0 { return 1 } return 0 }" let out: String = compile_capture(src) assert str_contains(out, "if ("), "if statement in C output" } test "codegen-if-else" { let src: String = "fn check(x: Int) -> Int { if x > 0 { return 1 } else { return 0 } }" let out: String = compile_capture(src) assert str_contains(out, "if ("), "if in output" assert str_contains(out, "} else {"), "else branch in output" } test "codegen-while-loop" { let src: String = "fn f() -> Int { let i: Int = 0 while i < 10 { i = i + 1 } return i }" let out: String = compile_capture(src) assert str_contains(out, "while ("), "while loop in C output" } test "codegen-let-binding" { let src: String = "fn f() -> Int { let n: Int = 5 return n }" let out: String = compile_capture(src) assert str_contains(out, "el_val_t n"), "let binding in output" } test "codegen-function-call" { let src: String = "fn f() -> Void { println(\"hi\") }" let out: String = compile_capture(src) assert str_contains(out, "println("), "function call in output" } test "codegen-string-concat" { let src: String = "fn f() -> String { let a: String = \"x\" let b: String = \"y\" return a + b }" let out: String = compile_capture(src) assert str_contains(out, "el_str_concat"), "string concat uses el_str_concat" } test "codegen-int-arithmetic" { let src: String = "fn f(x: Int, y: Int) -> Int { return x + y }" let out: String = compile_capture(src) assert !str_contains(out, "el_str_concat(x"), "int add does not use el_str_concat" } test "codegen-comparison" { let src: String = "fn f(x: Int) -> Bool { return x > 0 }" let out: String = compile_capture(src) assert str_contains(out, ">"), "comparison in output" } test "codegen-string-equality" { let src: String = "fn f(s: String) -> Bool { return s == \"hello\" }" let out: String = compile_capture(src) assert str_contains(out, "str_eq("), "string equality uses str_eq" } test "codegen-logical-and" { let src: String = "fn f(a: Bool, b: Bool) -> Bool { return a && b }" let out: String = compile_capture(src) assert str_contains(out, "&&"), "logical and in output" } test "codegen-logical-or" { let src: String = "fn f(a: Bool, b: Bool) -> Bool { return a || b }" let out: String = compile_capture(src) assert str_contains(out, "||"), "logical or in output" } test "codegen-unary-not" { let src: String = "fn f(b: Bool) -> Bool { return !b }" let out: String = compile_capture(src) assert str_contains(out, "!"), "unary not in output" } test "codegen-string-escape-in-c" { let src: String = "fn msg() -> String { return \"hello\\nworld\\t!\" }" let out: String = compile_capture(src) assert str_contains(out, "\\n"), "newline escape in C output" assert str_contains(out, "\\t"), "tab escape in C output" } test "codegen-many-functions" { // Multiple functions — exercises streaming loop + per-function arena scoping let src: String = "fn a() -> Int { return 1 }\nfn b() -> Int { return 2 }\nfn c() -> Int { return 3 }\nfn d() -> Int { return 4 }\nfn e() -> Int { return 5 }" let out: String = compile_capture(src) assert str_contains(out, "el_val_t a("), "function a in output" assert str_contains(out, "el_val_t b("), "function b in output" assert str_contains(out, "el_val_t c("), "function c in output" assert str_contains(out, "el_val_t d("), "function d in output" assert str_contains(out, "el_val_t e("), "function e in output" } test "codegen-deep-expression" { // Deeply nested arithmetic — exercises recursive cg_expr + per-statement arena let src: String = "fn deep() -> Int { return 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 }" let out: String = compile_capture(src) assert str_contains(out, "return"), "deep expr: return present" assert str_contains(out, "8"), "deep expr: literal 8 present" } test "codegen-forward-declarations" { // Functions should have forward declarations before definitions let src: String = "fn b() -> Int { return a() }\nfn a() -> Int { return 1 }" let out: String = compile_capture(src) assert str_contains(out, "el_val_t a("), "function a in output" assert str_contains(out, "el_val_t b("), "function b in output" } test "codegen-for-loop" { let src: String = "fn f() -> Void { let items: [Int] = native_list_empty() for item in items { println(item) } }" let out: String = compile_capture(src) assert str_contains(out, "for ("), "for loop in C output" assert str_contains(out, "el_list_get("), "for loop uses el_list_get" } test "codegen-extern-fn" { let src: String = "extern fn my_native(x: Int) -> Int\nfn use_it() -> Int { return my_native(1) }" let out: String = compile_capture(src) assert str_contains(out, "my_native("), "extern fn referenced in output" } test "codegen-nested-calls" { let src: String = "fn f() -> String { return str_concat(int_to_str(42), \" ok\") }" let out: String = compile_capture(src) assert str_contains(out, "str_concat"), "nested calls: str_concat in output" assert str_contains(out, "int_to_str"), "nested calls: int_to_str in output" } // ── Self-host / smoke tests ─────────────────────────────────────────────────── test "compiler-minimal-program" { let src: String = "fn main() -> Void { println(\"ok\") }" let out: String = compile_capture(src) assert str_contains(out, "#include"), "has #include" assert str_contains(out, "int main("), "has int main()" assert str_contains(out, "println("), "calls println" assert str_contains(out, "el_runtime.h"), "links el_runtime.h" } test "compiler-pure-library" { // No fn main = library mode: codegen_streaming returns before emitting main() let src: String = "fn helper(x: Int) -> Int { return x + 1 }" let out: String = compile_capture(src) assert !str_contains(out, "int main("), "library: no int main" assert str_contains(out, "#include"), "library: has includes" assert str_contains(out, "helper("), "library: helper function present" } test "compiler-multiple-fns-with-main" { let src: String = "fn greet(name: String) -> String { return \"Hello \" + name }\nfn main() -> Void { println(greet(\"world\")) }" let out: String = compile_capture(src) assert str_contains(out, "greet("), "greet in output" assert str_contains(out, "int main("), "main in output" assert str_contains(out, "println("), "println in output" } test "compiler-let-in-main" { let src: String = "fn main() -> Void { let x: Int = 42 println(int_to_str(x)) }" let out: String = compile_capture(src) assert str_contains(out, "el_val_t x"), "let binding x in output" assert str_contains(out, "42"), "literal 42 in output" } test "compiler-string-concat-chain" { let src: String = "fn f() -> String { let a: String = \"x\" let b: String = \"y\" let c: String = \"z\" return a + b + c }" let out: String = compile_capture(src) assert str_contains(out, "el_str_concat"), "string chain uses el_str_concat" } test "compiler-negative-literal" { let src: String = "fn f() -> Int { return -42 }" let out: String = compile_capture(src) assert str_contains(out, "42"), "negative literal value in output" } test "compiler-stdint-include" { // The generated C should include stdint.h for int64_t let src: String = "fn f() -> Int { return 0 }" let out: String = compile_capture(src) assert str_contains(out, "stdint.h"), "output includes stdint.h" }