general update, updated cimport so it parses struct definitions from imported headers, improved the error reporting, added ifdef and ifndef, added proper support for extern variadic functions, added some new sections and pages to the doc tool and added --check to only check the program corectness and run compile time defs without producing a binary

This commit is contained in:
igor
2026-03-11 21:27:48 +01:00
parent 0ac7f26a18
commit ecf90feab9
18 changed files with 1225 additions and 84 deletions

1047
main.py

File diff suppressed because it is too large Load Diff

14
test.py
View File

@@ -152,6 +152,7 @@ class TestCaseConfig:
tags: List[str] = field(default_factory=list)
requires: List[str] = field(default_factory=list)
libs: List[str] = field(default_factory=list)
compile_args: List[str] = field(default_factory=list)
@classmethod
def from_meta(cls, data: Dict[str, Any]) -> "TestCaseConfig":
@@ -207,6 +208,11 @@ class TestCaseConfig:
if not isinstance(libs, list) or not all(isinstance(item, str) for item in libs):
raise ValueError("libs must be a list of strings")
cfg.libs = [item.strip() for item in libs if item.strip()]
if "compile_args" in data:
ca = data["compile_args"]
if not isinstance(ca, list) or not all(isinstance(item, str) for item in ca):
raise ValueError("compile_args must be a list of strings")
cfg.compile_args = list(ca)
return cfg
@@ -442,6 +448,7 @@ class TestRunner:
cmd.extend(["-l", lib])
for lib in (extra_libs or []):
cmd.extend(["-l", lib])
cmd.extend(case.config.compile_args)
if self.args.ct_run_main:
cmd.append("--ct-run-main")
if self.args.verbose:
@@ -477,7 +484,7 @@ class TestRunner:
obj_path = case.build_dir / f"{case.binary_stub}_fixture.o"
archive_path = case.build_dir / f"lib{case.binary_stub}_fixture.a"
compile_cmd = [cc, "-O2", "-c", str(c_source), "-o", str(obj_path)]
compile_cmd = [cc, "-O2", "-fno-stack-protector", "-c", str(c_source), "-o", str(obj_path)]
archive_cmd = [ar, "rcs", str(archive_path), str(obj_path)]
if self.args.verbose:
@@ -655,6 +662,11 @@ class TestRunner:
return self._sort_lines(text)
if case.source.stem == "ct_test" and label == "compile":
return self._mask_build_path(text, case.binary_stub)
if label == "compile":
# Normalize absolute source paths to relative for stable compile error comparison
source_dir = str(case.source.parent.resolve())
if source_dir:
text = text.replace(source_dir + "/", "")
return text
def _sort_lines(self, text: str) -> str:

9
tests/cimport_structs.c Normal file
View File

@@ -0,0 +1,9 @@
#include "cimport_structs.h"
long point_sum_ptr(struct Point *p) {
return p->x + p->y;
}
long pair_sum_ptr(struct Pair *p) {
return p->a + p->b;
}

View File

@@ -0,0 +1,6 @@
16
10
20
30
16
300

18
tests/cimport_structs.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef TEST_STRUCTS_H
#define TEST_STRUCTS_H
struct Point {
long x;
long y;
};
struct Pair {
long a;
long b;
};
/* Pointer-based helpers (simple scalar ABI). */
long point_sum_ptr(struct Point *p);
long pair_sum_ptr(struct Pair *p);
#endif

31
tests/cimport_structs.sl Normal file
View File

@@ -0,0 +1,31 @@
import stdlib.sl
# Test cimport: extract struct definitions and extern functions from a C header.
cimport "cimport_structs.h"
word main
# Verify that cstruct Point was generated with correct layout
Point.size puti cr # 16 bytes (two i64 = 8+8)
# Allocate a Point, set fields, read them back
Point.size alloc dup >r
r@ 10 Point.x!
r@ 20 Point.y!
r@ Point.x@ puti cr # 10
r@ Point.y@ puti cr # 20
# Call C helper that takes a pointer (simple scalar ABI)
r@ point_sum_ptr puti cr # 30
r> Point.size free
# Verify Pair struct layout
Pair.size puti cr # 16
Pair.size alloc dup >r
r@ 100 Pair.a!
r@ 200 Pair.b!
r@ pair_sum_ptr puti cr # 300
r> Pair.size free
0
end

View File

@@ -0,0 +1,12 @@
error: unexpected 'end' at 6:8
--> error_recovery.sl:6:8
|
6 | end end
| ^^^
error: unexpected 'end' at 10:8
--> error_recovery.sl:10:8
|
10 | end end
| ^^^
2 error(s) emitted

View File

@@ -0,0 +1,4 @@
{
"expect_compile_error": true,
"description": "Compiler reports multiple errors via error recovery"
}

15
tests/error_recovery.sl Normal file
View File

@@ -0,0 +1,15 @@
# This file intentionally has multiple errors to test error recovery.
# The compiler should report all of them rather than stopping at the first.
# No stdlib import — keeps line numbers stable.
word foo
end end
end
word bar
end end
end
word main
0
end

7
tests/ifdef.expected Normal file
View File

@@ -0,0 +1,7 @@
flag_on
nope_off
yes
nested_ok

3
tests/ifdef.meta.json Normal file
View File

@@ -0,0 +1,3 @@
{
"compile_args": ["-D", "TESTFLAG"]
}

44
tests/ifdef.sl Normal file
View File

@@ -0,0 +1,44 @@
import stdlib/stdlib.sl
import stdlib/io.sl
# Test ifdef: TESTFLAG is defined via -D TESTFLAG
ifdef TESTFLAG
word show_flag
"flag_on" puts cr
end
endif
# Test ifndef: NOPE is NOT defined
ifndef NOPE
word show_nope
"nope_off" puts cr
end
endif
# Test ifdef with elsedef
ifdef TESTFLAG
word branch
"yes" puts cr
end
elsedef
word branch
"no" puts cr
end
endif
# Test nested: inner depends on outer
ifdef TESTFLAG
ifndef NOPE
word nested
"nested_ok" puts cr
end
endif
endif
word main
show_flag
show_nope
branch
nested
0
end

3
tests/ifndef.expected Normal file
View File

@@ -0,0 +1,3 @@
guard_ok
else_ok

33
tests/ifndef.sl Normal file
View File

@@ -0,0 +1,33 @@
import stdlib/stdlib.sl
import stdlib/io.sl
# No -D flags, so ifdef FOO is false, ifndef FOO is true
ifdef FOO
word dead_code
"BUG" puts cr
end
endif
ifndef FOO
word guarded
"guard_ok" puts cr
end
endif
# elsedef: ifdef FALSE → skip, elsedef → include
ifdef MISSING
word wrong
"BUG" puts cr
end
elsedef
word right
"else_ok" puts cr
end
endif
word main
guarded
right
0
end

20
tests/variadic_extern.c Normal file
View File

@@ -0,0 +1,20 @@
#include <stdarg.h>
/* Sums variadic long args until sentinel -1 is seen. */
long va_sum_sentinel(long first, ...) {
va_list ap;
va_start(ap, first);
long total = first;
while (1) {
long v = va_arg(ap, long);
if (v == -1) break;
total += v;
}
va_end(ap);
return total;
}
/* Non-variadic helper for comparison. */
long add_two(long a, long b) {
return a + b;
}

View File

@@ -0,0 +1,5 @@
30
hello
42 99
60

View File

@@ -0,0 +1,4 @@
{
"description": "Test variadic and non-variadic extern declarations with companion C file",
"libs": ["libc.so.6"]
}

34
tests/variadic_extern.sl Normal file
View File

@@ -0,0 +1,34 @@
import stdlib.sl
# Test variadic extern declarations.
# For variadic externs, the TOS literal before the call is the number of
# extra variadic arguments. The compiler consumes it (not passed to C).
# String literals push (ptr, len) — use drop to discard the length for C.
# printf: 1 fixed param (fmt), variadic args via TOS count
extern int printf(const char *fmt, ...)
extern int fflush(long stream)
# Custom C variadic: sums args until sentinel -1 is seen
extern long va_sum_sentinel(long first, ...)
# Non-variadic extern for comparison
extern long add_two(long a, long b)
word main
# Test 1: non-variadic add_two
10 20 add_two puti cr
# Test 2: printf with 0 variadic args (just format string)
"hello\n" drop 0 printf drop
0 fflush drop
# Test 3: printf with 2 variadic args
"%d %d\n" drop 42 99 2 printf drop
0 fflush drop
# Test 4: va_sum_sentinel(10, 20, 30, -1) = 60
10 20 30 -1 3 va_sum_sentinel puti cr
0
end