--emit-schema FILE writes the compiler's resolved view once the program type-checks: every
record (fields, types, defaults as written, docs, places, attributes), every registry with its
entries in their final order after the open-registry merge (key, constant, index, file:line:col
of the entry and of each field value, and which file contributed which keys), every const, and
the zero-argument functions a fn value can name. Deterministic, schema_version 1; the runtime is
left out. `ludic schema [file] [-o FILE]` wraps it.
--check --diagnostics=json prints every error as one JSON array on stdout: the checker's and the
module rules' all, a parse or lowering error as the last. Tokens and nodes now carry a column.
Fields take several @attributes; @Ref(Registry), @OneOf(PREFIX_), @Range(lo, hi), @Unit("..."),
@Asset("..."), @Color on a field and @AppendOnly / @ByKey on a registry change nothing but go into
the schema, and @Ref naming no registry is an error (every one reported). Fixtures:
examples/lang/attributes.ludic, examples/rejected/ref_unknown.ludic, cases in ludic-dev test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
48 lines
1.8 KiB
Text
48 lines
1.8 KiB
Text
# ---- ludic schema -------------------------------------------------------------
|
|
# What an editor of a program's data needs, from the compiler's own view: every record with its
|
|
# fields, types, defaults, docs and attributes (@Ref, @Range, ...), every registry with its entries
|
|
# in their final order and where each is written, every const, and the functions a `fn` value can
|
|
# name. The compiler writes it (`ludicc --emit-schema`, selfhost/backend/emit_schema.ludic) once the
|
|
# program has type-checked.
|
|
#
|
|
# ludic schema [file] the JSON on stdout
|
|
# ludic schema [file] -o FILE into FILE
|
|
# ludic schema --unsafe ... a program whose own files write `unsafe`
|
|
function cmd_schema() -> int {
|
|
var src = ""
|
|
var dest = ""
|
|
var ai = 2
|
|
while ai < arg_count() {
|
|
let a = arg(ai)
|
|
if a == "-o" or a == "--out" {
|
|
if ai + 1 >= arg_count() { err(`ludic schema: {a} needs a file\n`); return 2 }
|
|
ai += 1
|
|
dest = arg(ai)
|
|
}
|
|
else if a == "--unsafe" { g_unsafe_build = true }
|
|
else if a[0] == '-' {
|
|
err(`ludic schema: unknown option {a}\n`)
|
|
err(" usage: ludic schema [file] [-o FILE] [--unsafe]\n")
|
|
return 2
|
|
}
|
|
else { src = a }
|
|
ai += 1
|
|
}
|
|
let entry = find_entry(src)
|
|
if entry == "" { return no_entry() }
|
|
ensure_ludicc()
|
|
var target = dest
|
|
if target == "" { target = tmp_path("schema.json") }
|
|
let errs = tmp_path("schema.err")
|
|
if not shq(`{ludicc()} --headless{unsafe_flag()} {sh_single(entry)} --emit-schema {sh_single(target)} 2> {errs}`) {
|
|
err(`ludic schema: {entry} did not compile:\n`)
|
|
err(capture(`grep -i error {errs} | head -20`))
|
|
return 1
|
|
}
|
|
if dest == "" {
|
|
let s = read_file(target)
|
|
if s == null { err("ludic schema: the compiler wrote no schema (is it older than ludic schema?)\n"); return 1 }
|
|
out(s)
|
|
}
|
|
return 0
|
|
}
|