compiler: text keys (phase 26.2) - k"pause.resume" / kn"catch.count" of the builtin type Key (not a string, and no string one; == compares), its run-time value the key after a marker byte (1, or 2 for a plural); package.ludic's lang "assets/lang" en and a gettext .po reader; every key literal checked against en.po (a kn"" one wants a msgid_plural), trf / trn and a template's t('key', ...) against the English's holes, a component's template words and a @Text row's English as "English left" (warnings, english_left in ludic deps), a @Text Key field a compiled row leaves out filled with its derived key <registry>.<row>.<field> (or @TextKey's prefix; maps.<map>.<table>.<row>.<field> for a @PerMap row, checked), one English under several undescribed keys warned at en.po's line; the schema's "lang" (keys and their sites, unused, undescribed, split, and every other language's missing / fuzzy / extra); k"" in .lres data, @PerMap rows included (lres_key); ludic-fmt keeps a key literal whole; reseeded, bootstrap-cfree fixpoint holds

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-29 23:33:52 +03:00
parent 82c652ca31
commit cc1ea0f4ae
28 changed files with 139268 additions and 109746 deletions

View file

@ -74,5 +74,13 @@ function ck_give(to: pointer, from: pointer, e: Node, what: pointer) -> void {
ck_err(cat, e, `{what} wants {ck_a(to)} and this is a pointer: a slice is made with words(n), floats(n) or new, not from an address`)
return
}
if (cat == "key") and ck_is_key(to) {
ck_err(cat, e, `{what} wants a Key and this is {ck_a(from)}: a key is written k"module.purpose" (kn"..." for a plural)`)
return
}
if (cat == "key") {
ck_err(cat, e, `{what} wants {ck_a(to)} and this is a Key: text is made from a key (tr(key)), never the key itself`)
return
}
ck_err(cat, e, `{what} wants {ck_a(to)} and this is {ck_a(from)}`)
}

View file

@ -40,7 +40,10 @@ function ck_expr(e: Node) -> pointer {
if is_float_file(e.file) { return "float" }
return "fixed"
}
if k == E_STR { return "string" }
if k == E_STR {
if e.ival == KEY_LIT or e.ival == KEY_PLURAL { return "Key" } # k"..." / kn"..." (i18n.ludic)
return "string"
}
if k == E_SLICE { ck_walk(e); return "string" }
if k == E_BOOL { return "bool" }
if k == E_NULL { return "null" }

View file

@ -34,6 +34,7 @@ function ck_compare(e: Node, op: pointer, l: pointer, r: pointer, a: Node, b: No
let cr = ck_class(r)
# a pointer holding text is compared with a string all through the runtime and the compiler
if ((l == "pointer") and (cr == "string")) or ((r == "pointer") and (cl == "string")) { return }
if ((l == "pointer") and (cr == "key")) or ((r == "pointer") and (cl == "key")) { return }
if cl != cr {
ck_err("compare", e, `{op} between {ck_a(l)} and {ck_a(r)}`)
return
@ -46,6 +47,10 @@ function ck_compare(e: Node, op: pointer, l: pointer, r: pointer, a: Node, b: No
# `string` and the untyped `pointer` are both text to an operator (the emitter's is_textish)
function ck_is_text(t: pointer) -> bool { return (t == "string") or (t == "pointer") }
function ck_arith(e: Node, op: pointer, l: pointer, r: pointer, a: Node, b: Node) -> pointer {
if ck_is_key(l) or ck_is_key(r) {
ck_err("key", e, `{op} on a Key: a key names a text, it is not one - make the text with tr(key)`)
return "?"
}
if ck_is_text(l) or ck_is_text(r) {
if ck_unknown(l) or ck_unknown(r) { return "string" }
if ck_is_text(l) and ck_is_text(r) and (op == "+") { return "string" }

View file

@ -60,6 +60,7 @@ function ck_ty_args(s: pointer, tps: pointer) -> pointer {
function ck_ty_known(name: pointer, tps: pointer) -> bool {
if ck_tab_get(ck_ty_k, ck_ty_v, name) != null { return true }
if (name == "Vector") or (name == "IVec2") or (name == "Rect") { return true } # the packed value types
if (name == "Key") { return true } # k"..." (i18n.ludic)
if is_state_ty(name) or ck_record(name) != null or ck_enum(name) != null { return true }
if gen_template(g_gen_recs, name) != null { return true }
if tps != null {

View file

@ -5,6 +5,11 @@
# functions are kept apart, and a pointer is trusted to be whatever it is given as.
var ck_extern_arg: bool = false # an extern's arguments are being given: a slice goes as its data
function ck_unknown(t: pointer) -> bool { return t == null or (t == "?") }
# the builtin Key, the type of k"..." - unless the program declares a type of that name itself
function ck_is_key(t: pointer) -> bool {
if t == null or not (t == "Key") { return false }
return ck_record(t) == null and ck_enum(t) == null
}
function ck_is_int(t: pointer) -> bool {
if (t == "int") or (t == "long") or (t == "byte") or (t == "i64") or (t == "u8") { return true }
let en = ck_enum(t)
@ -38,6 +43,7 @@ function ck_is_lit(e: Node) -> bool {
function ck_class(t: pointer) -> pointer {
if ck_is_num(t) { return "number" }
if (t == "string") { return "string" }
if ck_is_key(t) { return "key" }
if (t == "bool") { return "bool" }
return "reference"
}
@ -85,6 +91,8 @@ function ck_mismatch(to: pointer, from: pointer, e: Node) -> pointer {
}
if (from == "pointer") and is_slice_ty(to) { return "pointer-slice" }
if (to == "pointer") or (from == "pointer") { return null }
# a Key (k"...") is not text and text is not a Key, either way round (i18n.ludic)
if ck_is_key(to) or ck_is_key(from) { return "key" }
if (to == "string") { return "kind" }
if ck_is_rec(to) and ck_is_rec(from) { return "record" }
if ck_is_rec(to) and ((from == "string") or is_slice_ty(from)) { return "kind" }