feat: restructure repo, borrow checker, expanded stdlib
- Reorganize repository to Rust-style layout: compiler/bootstrap/ compiler/selfhost/ compiler/tests/ library/std/ library/runtime/ tests/ tools/ - Add buxs/ Windows-compatible project root - Add borrow checker tests and implement: - Alias analysis (double mutable borrow detection) - Use-after-move detection for own T - Expand standard library: - Std::Os: Args, Env, Cwd, Chdir - Std::Time: NowMs, NowUs, SleepMs - Std::Process: Run, Output - Std::Io: PrintInt64 (fixes 32-bit truncation bug) - Add examples: os_time.bux, process.bux - Fix PrintInt to use int64_t in C runtime
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import std/[unittest, strutils]
|
||||
import ../bootstrap/[lexer, parser, sema, types]
|
||||
|
||||
proc checkSource(source: string): SemaResult =
|
||||
let lexRes = tokenize(source, "<test>")
|
||||
check not lexRes.hasErrors
|
||||
let parseRes = parse(lexRes.tokens, "<test>")
|
||||
check parseRes.diagnostics.len == 0
|
||||
result = analyze(parseRes.module)
|
||||
|
||||
suite "Borrow Checker":
|
||||
|
||||
test "@[Checked] function with &mut allows mutation":
|
||||
let res = checkSource("""
|
||||
func Mutate(val: &mut int) {
|
||||
*val = 42;
|
||||
}
|
||||
func Main() -> int {
|
||||
var x: int = 10;
|
||||
Mutate(&x);
|
||||
return 0;
|
||||
}
|
||||
""")
|
||||
check(not res.hasErrors)
|
||||
|
||||
test "@[Checked] function rejects write through &T":
|
||||
let res = checkSource("""
|
||||
@[Checked]
|
||||
func BadWrite(val: &int) {
|
||||
*val = 42;
|
||||
}
|
||||
func Main() -> int {
|
||||
var x: int = 10;
|
||||
BadWrite(&x);
|
||||
return 0;
|
||||
}
|
||||
""")
|
||||
check(res.hasErrors)
|
||||
check(res.diagnostics[0].message.contains("cannot assign through shared reference"))
|
||||
|
||||
test "unchecked function allows write through raw pointer":
|
||||
let res = checkSource("""
|
||||
func RawWrite(val: *int) {
|
||||
*val = 42;
|
||||
}
|
||||
func Main() -> int {
|
||||
var x: int = 10;
|
||||
RawWrite(&x);
|
||||
return 0;
|
||||
}
|
||||
""")
|
||||
check(not res.hasErrors)
|
||||
|
||||
test "&T allows reading":
|
||||
let res = checkSource("""
|
||||
@[Checked]
|
||||
func Read(val: &int) -> int {
|
||||
return *val;
|
||||
}
|
||||
func Main() -> int {
|
||||
var x: int = 10;
|
||||
return Read(&x);
|
||||
}
|
||||
""")
|
||||
check(not res.hasErrors)
|
||||
|
||||
test "own T type parses and resolves":
|
||||
let res = checkSource("""
|
||||
struct Box {
|
||||
value: int;
|
||||
}
|
||||
func TakeOwn(b: own Box) -> int {
|
||||
return b.value;
|
||||
}
|
||||
func Main() -> int {
|
||||
var b: Box = Box { value: 42 };
|
||||
return TakeOwn(b);
|
||||
}
|
||||
""")
|
||||
check(not res.hasErrors)
|
||||
|
||||
test "@[Checked] rejects double mutable borrow in call":
|
||||
let res = checkSource("""
|
||||
@[Checked]
|
||||
func Swap(a: &mut int, b: &mut int) {
|
||||
let tmp = *a;
|
||||
*a = *b;
|
||||
*b = tmp;
|
||||
}
|
||||
@[Checked]
|
||||
func Main() -> int {
|
||||
var x: int = 10;
|
||||
Swap(&x, &x);
|
||||
return 0;
|
||||
}
|
||||
""")
|
||||
check(res.hasErrors)
|
||||
check(res.diagnostics[0].message.contains("mutable borrow"))
|
||||
|
||||
test "@[Checked] rejects use after move":
|
||||
let res = checkSource("""
|
||||
struct Box {
|
||||
value: int;
|
||||
}
|
||||
@[Checked]
|
||||
func Consume(b: own Box) -> int {
|
||||
return b.value;
|
||||
}
|
||||
@[Checked]
|
||||
func Main() -> int {
|
||||
var b: Box = Box { value: 42 };
|
||||
let x: int = Consume(b);
|
||||
return b.value;
|
||||
}
|
||||
""")
|
||||
check(res.hasErrors)
|
||||
check(res.diagnostics[0].message.contains("moved"))
|
||||
Reference in New Issue
Block a user