small refactor and cleanup

This commit is contained in:
IgorCielniak
2026-01-08 13:15:27 +01:00
parent 963e024108
commit d4dc6ceef5
52 changed files with 418 additions and 372 deletions

2
tests/alloc.expected Normal file
View File

@@ -0,0 +1,2 @@
111
222

23
tests/alloc.sl Normal file
View File

@@ -0,0 +1,23 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
import ../stdlib/mem.sl
: test-mem-alloc
4096 alloc dup 1337 swap ! # allocate 4096 bytes, store 1337 at start
dup @ puti cr # print value at start
4096 free # free the memory
;
struct: Point
field x 8
field y 8
;struct
: main
32 alloc # allocate 32 bytes (enough for a Point struct)
dup 111 swap Point.x!
dup 222 swap Point.y!
dup Point.x@ puti cr
Point.y@ puti cr
32 free # free the memory
;

1
tests/alloc.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/alloc.sl -o /tmp/alloc > /dev/null && /tmp/alloc

View File

@@ -0,0 +1,2 @@
42
3

View File

@@ -0,0 +1,16 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
import ../fn.sl
: main
2 40 +
puti cr
extend-syntax
foo(1, 2)
puti cr
0
;
fn foo(int a, int b){
return a + b;
}

View File

@@ -0,0 +1 @@
python main.py tests/call_syntax_parens.sl -o /tmp/call_syntax_parens > /dev/null && /tmp/call_syntax_parens

27
tests/fib.expected Normal file
View File

@@ -0,0 +1,27 @@
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
-------
25 numbers printed from the fibonaci sequence

26
tests/fib.sl Normal file
View File

@@ -0,0 +1,26 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
import ../stdlib/debug.sl
: main
1 1 2dup 2dup puti cr puti cr
+
dup puti cr
rot
22 dup >r for
2dup + dup puti cr
rot
end
"-------" puts
r> 3 + puti
" numbers printed from the fibonaci sequence" puts
0
;
: main2
1 2 while over 100 < do
over puti cr
swap over +
end
;

1
tests/fib.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/fib.sl -o /tmp/fib > /dev/null && /tmp/fib

View File

@@ -0,0 +1,33 @@
12
7
42
12
1
10
22
3
123
1337
81
99
13
111
60
5
123
1
0
1
0
1
0
1
0
1
0
1
0
111
222
16
70

191
tests/integration_core.sl Normal file
View File

@@ -0,0 +1,191 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
import ../fn.sl
:asm mem-slot {
lea rax, [rel print_buf]
sub r12, 8
mov [r12], rax
}
;
macro: square
dup *
;macro
macro: defconst 2
: $1
$2
;
;macro
macro: defadder 3
: $1
$2 $3 +
;
;macro
defconst MAGIC 99
defadder add13 5 8
struct: Point
field x 8
field y 8
;struct
extend-syntax
fn fancy_add(int a, int b){
return (a + b) * b;
}
: test-add
5 7 + puti cr
;
: test-sub
10 3 - puti cr
;
: test-mul
6 7 * puti cr
;
: test-div
84 7 / puti cr
;
: test-mod
85 7 % puti cr
;
: test-drop
10 20 drop puti cr
;
: test-dup
11 dup + puti cr
;
: test-swap
2 5 swap - puti cr
;
: test-store
mem-slot dup
123 swap !
@ puti cr
;
: test-mmap
0 # addr hint (NULL)
4096 # length (page)
3 # prot (PROT_READ | PROT_WRITE)
34 # flags (MAP_PRIVATE | MAP_ANON)
-1 # fd (ignored for MAP_ANON)
0 # offset
mmap
dup
1337 swap !
dup
@ puti cr
4096 munmap drop
;
: test-macro
9 square puti cr
MAGIC puti cr
add13 puti cr
;
: test-if
5 5 == if
111 puti cr
else
222 puti cr
end
;
: test-else-if
2
dup 1 == if
50 puti cr
else
dup 2 == if
60 puti cr
else
70 puti cr
end
end
drop
;
: test-for
0
5 for
1 +
end
puti cr
;
: test-for-zero
123
0 for
drop
end
puti cr
;
: test-struct
mem-slot
dup 111 swap Point.x!
dup 222 swap Point.y!
dup Point.x@ puti cr
Point.y@ puti cr
Point.size puti cr
;
: test-cmp
5 5 == puti cr
5 4 == puti cr
5 4 != puti cr
4 4 != puti cr
3 5 < puti cr
5 3 < puti cr
5 3 > puti cr
3 5 > puti cr
5 5 <= puti cr
6 5 <= puti cr
5 5 >= puti cr
4 5 >= puti cr
;
: test-c-fn
3
7
fancy_add()
puti cr
;
: main
test-add
test-sub
test-mul
test-div
test-mod
test-drop
test-dup
test-swap
test-store
test-mmap
test-macro
test-if
test-else-if
test-for
test-for-zero
test-cmp
test-struct
test-c-fn
0
;

View File

@@ -0,0 +1 @@
python main.py tests/integration_core.sl -o /tmp/integration_core > /dev/null && /tmp/integration_core

View File

@@ -0,0 +1 @@
read_file works

36
tests/io_read_file.sl Normal file
View File

@@ -0,0 +1,36 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: main
"/tmp/l2_read_file_test.txt"
"read_file works\n"
write_file drop
"/tmp/l2_read_file_test.txt" # (addr len)
read_file # (file_addr file_len)
dup 0 > if # if file_len > 0, success
write_buf # print file contents (file_len file_addr)
0
exit
end
dup -2 == if # open() failed
drop
"open() failed: errno=" puts
swap puti cr
exit
end
dup -1 == if # fstat() failed
drop
"fstat() failed: errno=" puts
swap puti cr
exit
end
dup -3 == if # mmap() failed
drop
"mmap() failed" puts
exit
end
"unknown read_file failure" puts
dup # file_len file_len file_addr
exit # Exit with returned file_len as the program exit code (debug)
;

1
tests/io_read_file.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/io_read_file.sl -o /tmp/io_read_file > /dev/null && /tmp/io_read_file

View File

@@ -0,0 +1 @@
stdin via test

13
tests/io_read_stdin.sl Normal file
View File

@@ -0,0 +1,13 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: main
1024
read_stdin # returns (addr len)
dup 0 > if
write_buf
0 exit
end
"read_stdin failed" puts
exit
;

1
tests/io_read_stdin.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/io_read_stdin.sl -o /tmp/io_read_stdin > /dev/null && printf 'stdin via test\n' | /tmp/io_read_stdin

View File

@@ -0,0 +1 @@
hello from write_buf test

8
tests/io_write_buf.sl Normal file
View File

@@ -0,0 +1,8 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: main
"hello from write_buf test\n"
write_buf
0
;

1
tests/io_write_buf.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/io_write_buf.sl -o /tmp/io_write_buf > /dev/null && /tmp/io_write_buf

View File

@@ -0,0 +1,2 @@
wrote bytes:
27

17
tests/io_write_file.sl Normal file
View File

@@ -0,0 +1,17 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: main
"/tmp/l2_write_file_test.txt" # path
"hello from write_file test\n" # buffer
write_file
dup 0 > if
"wrote bytes: " puts
puti cr
0
exit
end
"write failed errno=" puts
puti cr
exit
;

1
tests/io_write_file.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/io_write_file.sl -o /tmp/io_write_file > /dev/null && /tmp/io_write_file

10
tests/loop_while.expected Normal file
View File

@@ -0,0 +1,10 @@
10
9
8
7
6
5
4
3
2
1

13
tests/loop_while.sl Normal file
View File

@@ -0,0 +1,13 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: main
10
while
dup 0 >
do
dup puti cr
1 -
end
drop
;

1
tests/loop_while.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/loop_while.sl -o /tmp/loop_while > /dev/null && /tmp/loop_while

View File

@@ -0,0 +1,3 @@
5
1
0

13
tests/loops_and_cmp.sl Normal file
View File

@@ -0,0 +1,13 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: main
0
5 for
1 +
end
puti cr
5 5 == puti cr
5 4 == puti cr
0
;

1
tests/loops_and_cmp.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/loops_and_cmp.sl -o /tmp/loops_and_cmp > /dev/null && /tmp/loops_and_cmp

2
tests/mem.expected Normal file
View File

@@ -0,0 +1,2 @@
5
6

9
tests/mem.sl Normal file
View File

@@ -0,0 +1,9 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: main
mem 5 swap !
mem 8 + 6 swap !
mem @ puti cr
mem 8 + @ puti cr
;

1
tests/mem.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/mem.sl -o /tmp/mem > /dev/null && /tmp/mem

View File

@@ -0,0 +1 @@
6

View File

@@ -0,0 +1,28 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: dup
6
;
compile-only
: emit-overridden
"dup" use-l2-ct
42
dup
int>string
nil
token-from-lexeme
list-new
swap
list-append
inject-tokens
;
immediate
compile-only
: main
emit-overridden
puti cr
0
;

View File

@@ -0,0 +1 @@
python main.py tests/override_dup_compile_time.sl -o /tmp/override_dup_compile_time > /dev/null && /tmp/override_dup_compile_time

View File

@@ -1,171 +0,0 @@
#!/usr/bin/env python3
"""Simple end-to-end test runner for L2.
Each test case provides an L2 program source and an expected stdout. The runner
invokes the bootstrap compiler on the fly and executes the produced binary.
"""
from __future__ import annotations
import subprocess
import sys
import tempfile
from dataclasses import dataclass
from pathlib import Path
from typing import List
ROOT = Path(__file__).resolve().parents[1]
COMPILER = ROOT / "main.py"
PYTHON = Path(sys.executable)
@dataclass
class TestCase:
name: str
source: str
expected_stdout: str
CASES: List[TestCase] = [
TestCase(
name="call_syntax_parens",
source=f"""
import {ROOT / 'stdlib/stdlib.sl'}
import {ROOT / 'stdlib/io.sl'}
import {ROOT / 'fn.sl'}
: main
2 40 +
puti cr
extend-syntax
foo(1, 2)
puti cr
0
;
fn foo(int a, int b){{
return a + b;
}}
""",
expected_stdout="42\n3\n",
),
TestCase(
name="loops_and_cmp",
source=f"""
import {ROOT / 'stdlib/stdlib.sl'}
import {ROOT / 'stdlib/io.sl'}
: main
0
5 for
1 +
end
puti cr
5 5 == puti cr
5 4 == puti cr
0
;
""",
expected_stdout="5\n1\n0\n",
),
TestCase(
name="override_dup_compile_time",
source=f"""
import {ROOT / 'stdlib/stdlib.sl'}
import {ROOT / 'stdlib/io.sl'}
: dup
6
;
compile-only
: emit-overridden
"dup" use-l2-ct
42
dup
int>string
nil
token-from-lexeme
list-new
swap
list-append
inject-tokens
;
immediate
compile-only
: main
emit-overridden
puti cr
0
;
""",
expected_stdout="6\n",
),
TestCase(
name="string_puts",
source=f"""
import {ROOT / 'stdlib/stdlib.sl'}
import {ROOT / 'stdlib/io.sl'}
: main
\"hello world\" puts
\"line1\\nline2\" puts
\"\" puts
0
;
""",
expected_stdout="hello world\nline1\nline2\n\n",
),
]
def run_case(case: TestCase) -> None:
print(f"[run] {case.name}")
with tempfile.TemporaryDirectory() as tmp:
src_path = Path(tmp) / f"{case.name}.sl"
exe_path = Path(tmp) / f"{case.name}.out"
src_path.write_text(case.source.strip() + "\n", encoding="utf-8")
compile_cmd = [str(PYTHON), str(COMPILER), str(src_path), "-o", str(exe_path)]
compile_result = subprocess.run(
compile_cmd,
capture_output=True,
text=True,
cwd=ROOT,
)
if compile_result.returncode != 0:
sys.stderr.write("[fail] compile error\n")
sys.stderr.write(compile_result.stdout)
sys.stderr.write(compile_result.stderr)
raise SystemExit(compile_result.returncode)
run_result = subprocess.run(
[str(exe_path)],
capture_output=True,
text=True,
cwd=ROOT,
)
if run_result.returncode != 0:
sys.stderr.write("[fail] execution error\n")
sys.stderr.write(run_result.stdout)
sys.stderr.write(run_result.stderr)
raise SystemExit(run_result.returncode)
if run_result.stdout != case.expected_stdout:
sys.stderr.write(f"[fail] output mismatch for {case.name}\n")
sys.stderr.write("expected:\n" + case.expected_stdout)
sys.stderr.write("got:\n" + run_result.stdout)
raise SystemExit(1)
print(f"[ok] {case.name}")
def main() -> None:
for case in CASES:
run_case(case)
print("[all tests passed]")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,4 @@
hello world
line1
line2

9
tests/string_puts.sl Normal file
View File

@@ -0,0 +1,9 @@
import ../stdlib/stdlib.sl
import ../stdlib/io.sl
: main
"hello world" puts
"line1\nline2" puts
"" puts
0
;

1
tests/string_puts.test Normal file
View File

@@ -0,0 +1 @@
python main.py tests/string_puts.sl -o /tmp/string_puts > /dev/null && /tmp/string_puts

66
tests/test.py Normal file
View File

@@ -0,0 +1,66 @@
#!/usr/bin/python
import sys
import os
import subprocess
COLORS = {
"red": "\033[91m",
"green": "\033[92m",
"yellow": "\033[93m",
"blue": "\033[94m",
"reset": "\033[0m"
}
def print_colored(text, color):
print(COLORS.get(color, "") + text + COLORS["reset"], end="")
def run_tests():
test_dir = "tests"
any_failed = False
if not os.path.isdir(test_dir):
print("No 'tests' directory found.")
return 1
for file in sorted(os.listdir(test_dir)):
if file.endswith(".test"):
test_path = os.path.join(test_dir, file)
expected_path = test_path.replace(".test", ".expected")
if not os.path.isfile(expected_path):
print(f"Missing expected output file for {file}")
any_failed = True
continue
with open(test_path, "r") as test_file:
command = test_file.read().strip()
with open(expected_path, "r") as expected_file:
expected_output = expected_file.read().strip()
try:
result = subprocess.run(command, shell=True, text=True, capture_output=True)
actual_output = result.stdout.strip()
stderr_output = result.stderr.strip()
if result.returncode == 0 and actual_output == expected_output:
print_colored("[OK] ", "green")
print(f"{file} passed")
else:
print_colored("[ERR] ", "red")
print(f"{file} failed (exit {result.returncode})")
print(f"Expected:\n{expected_output}")
print(f"Got:\n{actual_output}")
if stderr_output:
print(f"Stderr:\n{stderr_output}")
any_failed = True
except Exception as e:
print_colored(f"Error running {file}: {e}", "red")
any_failed = True
return 1 if any_failed else 0
if __name__ == "__main__":
sys.exit(run_tests())