ludic/tools/ludic-cli/schema.ludic
Orkuncakilkaya 42deb76c28 schema: ludicc --emit-schema / ludic schema, --check --diagnostics=json, and editor attributes
--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>
2026-09-29 18:06:54 +03:00

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
}