feat(cli): ludic build --check / ludicc --check - check without building
The parse, the types and the module rules (export, uses, layers, ports, registries) run and nothing is emitted or linked: about three seconds on Maroon Lake. In this mode the checker asks vis_check at each reference it resolves, with a global's initializer and a registry's entries seen from the files the emitter would use. Reseed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
7ef6c7ec75
commit
8892f51096
12 changed files with 15546 additions and 14721 deletions
|
|
@ -42,6 +42,7 @@ program Ludic {
|
|||
print(" run [file] [--headless] build the project and run it")
|
||||
print(" build [file] [--headless] [-o out]")
|
||||
print(" compile to build/<name> (a native binary, nothing to ship beside it)")
|
||||
print(" build [file] --check only check it: types, modules, uses and ports; nothing emitted")
|
||||
print(" test [file|dir...] [-j N] [-v] [--test NAME]")
|
||||
print(" compile and run the project's tests (-v: every test's line)")
|
||||
print(" deps [file] [--graph|--dot|--writes|--uses MOD|--check F|--baseline F]")
|
||||
|
|
|
|||
|
|
@ -276,6 +276,7 @@ function parse_build_args(start: int) -> pointer {
|
|||
else if a == "--windowed" { g_mode = 1 }
|
||||
else if a == "--save-temps" { g_save = true }
|
||||
else if a == "--unsafe" { g_unsafe_build = true }
|
||||
else if a == "--check" { g_check_build = true }
|
||||
else if a == "-o" {
|
||||
ai += 1
|
||||
if ai < arg_count() { g_out = arg(ai) }
|
||||
|
|
@ -283,7 +284,7 @@ function parse_build_args(start: int) -> pointer {
|
|||
}
|
||||
else if a[0] == '-' {
|
||||
err(`ludic: unknown option {a}\n`)
|
||||
err(" build/run take: [file] [--headless|--windowed] [-o out] [--save-temps]\n")
|
||||
err(" build/run take: [file] [--headless|--windowed] [-o out] [--save-temps] [--check]\n")
|
||||
g_argerr = true
|
||||
}
|
||||
else { src = a }
|
||||
|
|
@ -303,10 +304,20 @@ function output_path(entry: pointer) -> pointer {
|
|||
}
|
||||
|
||||
# ludic build [file] [--headless] [-o out] [--save-temps]
|
||||
# --check: parse, types, modules, uses, ports - everything the compiler checks before it emits -
|
||||
# and nothing emitted or linked; a fraction of a build's time, for iterating on uses lines
|
||||
var g_check_build: bool = false
|
||||
function check_app(src: pointer) -> int {
|
||||
ensure_ludicc()
|
||||
if not shq(`{ludicc()} --check{title_flag()}{unsafe_flag()} {src}`) { return 1 }
|
||||
print(`checked {src}`)
|
||||
return 0
|
||||
}
|
||||
function cmd_build() -> int {
|
||||
let entry = parse_build_args(2)
|
||||
if g_argerr { return 1 }
|
||||
if entry == "" { return no_entry() }
|
||||
if g_check_build { return check_app(entry) }
|
||||
let out = output_path(entry)
|
||||
if not compile_app(entry, out, g_mode, g_save) { return 1 }
|
||||
if g_mode == 2 {
|
||||
|
|
|
|||
|
|
@ -490,6 +490,23 @@ function deps_case() -> void {
|
|||
ok(lbl)
|
||||
}
|
||||
|
||||
# --check: the module rules, the ports and the types, with nothing emitted - a broken uses line is
|
||||
# refused as a full build refuses it, and a sound program writes no file
|
||||
function check_build_case() -> void {
|
||||
let lbl = "ludicc --check / ludic build --check: modules, uses, ports and types without emitting"
|
||||
let bad = ["rejected/uses_missing", "rejected/layer_reach", "rejected/private_module", "rejected/port_unbound", "rejected/registry_hidden", "rejected/port_new", "rejected/wrong_arity"]
|
||||
let want = ["fishing uses items.inv_add", "hud uses items.item_count", "add is private to module bank", "port Clock is used here but never bound", "Tools is private to module kit", "Clock is a port", "leaves out h"]
|
||||
for i in 0 .. len(bad) {
|
||||
if shq(`bin/ludicc --check examples/{bad[i]}.ludic > {tmp_dir()}/chk.err 2>&1`) { bad2(lbl, `{bad[i]} passed the check`); return }
|
||||
let said = capture(`cat {tmp_dir()}/chk.err`)
|
||||
if not s_contains(said, want[i]) { bad2(lbl, `{bad[i]}: [{s_trim(said)}]`); return }
|
||||
}
|
||||
shell("rm -f build/checked_out")
|
||||
if not shq(`bin/ludic build examples/modules/layers.ludic --check -o build/checked_out > {tmp_dir()}/chk.out 2>&1`) { bad2(lbl, capture_line(`tail -1 {tmp_dir()}/chk.out`)); return }
|
||||
if file_exists("build/checked_out") { bad2(lbl, "--check wrote a binary"); return }
|
||||
ok(lbl)
|
||||
}
|
||||
|
||||
# every package's own tests, the way a package author runs them: `ludic test packages`
|
||||
function packages_test_case() -> void {
|
||||
let lbl = "ludic test packages: every package's tests pass"
|
||||
|
|
@ -1079,6 +1096,7 @@ function cmd_dev_test() -> int {
|
|||
test_dir_case()
|
||||
packages_test_case()
|
||||
deps_case()
|
||||
check_build_case()
|
||||
lab_plate_case()
|
||||
pack_roundtrip_case()
|
||||
packignore_case()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue