feat(lang): L4 type checker between parse and emit
selfhost/check/ walks every function, the entry, tests, globals' initializers and @On listeners with real scopes, and refuses mixed number kinds, text and numbers, two record types, mismatched slices and fn types, wrong argument counts, wrong returns and wrong push elements - every mix-up at once, each at its line. LUDIC_CHECK_REPORT=1 lists them by category. pointer stays untyped (L7's). What it found is fixed: render3d's HDR scan calling the float-bits extern f_lt with floats; ludic.shooter's right-stick aim overflowing past half a push; prof.ludic storing longs in []int; extern arguments now coerced to their parameters. Text-returning runtime functions say string; Assets.ready says bool. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0677aee93f
commit
57b66bdf47
52 changed files with 27005 additions and 11844 deletions
|
|
@ -398,7 +398,7 @@ function assets_font(name: pointer) -> int {
|
|||
|
||||
function assets_total() -> int { atlas_init(); return at_q_n }
|
||||
function assets_loaded() -> int { atlas_init(); return at_q_pos }
|
||||
function assets_ready() -> int { atlas_init(); if at_q_pos >= at_q_n { return 1 }; return 0 }
|
||||
function assets_ready() -> bool { atlas_init(); return at_q_pos >= at_q_n }
|
||||
|
||||
# loading progress as a whole-number percent (0..100); an empty queue is 100.
|
||||
function assets_progress() -> int {
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ function base64_decode(src: pointer) -> pointer {
|
|||
}
|
||||
|
||||
# encode the bytes of NUL-terminated `src` as standard base64 (with '=' padding).
|
||||
function base64_encode(src: pointer) -> pointer {
|
||||
function base64_encode(src: pointer) -> string {
|
||||
let tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
let n = len(src)
|
||||
var out = ""
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@ function bigint_to_int(a: BigNum) -> int {
|
|||
}
|
||||
|
||||
# a limb (< 1e9) as exactly nine digits, left-padded with zeros
|
||||
function bn_pad9(x: int) -> pointer {
|
||||
function bn_pad9(x: int) -> string {
|
||||
var s = string(x)
|
||||
var pad = 9 - len(s)
|
||||
var out = ""
|
||||
|
|
@ -287,7 +287,7 @@ function bn_pad9(x: int) -> pointer {
|
|||
return out + s
|
||||
}
|
||||
|
||||
function bigint_str(a: BigNum) -> pointer {
|
||||
function bigint_str(a: BigNum) -> string {
|
||||
if a.sign == 0 { return "0" }
|
||||
var out = ""
|
||||
if a.sign < 0 { out = "-" }
|
||||
|
|
@ -364,7 +364,7 @@ function decimal_rescale(d: Dec, places: int) -> Dec {
|
|||
return dec_make(m, places)
|
||||
}
|
||||
|
||||
function decimal_str(d: Dec) -> pointer {
|
||||
function decimal_str(d: Dec) -> string {
|
||||
var neg = ""
|
||||
var m = d.m
|
||||
if m.sign < 0 { neg = "-"; m = bigint_neg(m) }
|
||||
|
|
|
|||
|
|
@ -946,7 +946,7 @@ extern function gl_get_doublev(pname: int, params: pointer) = "lgl_GetDoublev"
|
|||
extern function gl_get_error() -> int = "lgl_GetError"
|
||||
extern function gl_get_floatv(pname: int, params: pointer) = "lgl_GetFloatv"
|
||||
extern function gl_get_integerv(pname: int, params: pointer) = "lgl_GetIntegerv"
|
||||
extern function gl_get_string(name: int) -> pointer = "lgl_GetString"
|
||||
extern function gl_get_string(name: int) -> string = "lgl_GetString"
|
||||
extern function gl_get_tex_image(target: int, level: int, format: int, type: int, pixels: pointer) = "lgl_GetTexImage"
|
||||
extern function gl_get_tex_parameterfv(target: int, pname: int, params: pointer) = "lgl_GetTexParameterfv"
|
||||
extern function gl_get_tex_parameteriv(target: int, pname: int, params: pointer) = "lgl_GetTexParameteriv"
|
||||
|
|
@ -1165,7 +1165,7 @@ extern function gl_clear_bufferiv(buffer: int, drawbuffer: int, value: pointer)
|
|||
extern function gl_clear_bufferuiv(buffer: int, drawbuffer: int, value: pointer) = "lgl_ClearBufferuiv"
|
||||
extern function gl_clear_bufferfv(buffer: int, drawbuffer: int, value: pointer) = "lgl_ClearBufferfv"
|
||||
extern function gl_clear_bufferfi(buffer: int, drawbuffer: int, depth: fixed, stencil: int) = "lgl_ClearBufferfi"
|
||||
extern function gl_get_stringi(name: int, index: int) -> pointer = "lgl_GetStringi"
|
||||
extern function gl_get_stringi(name: int, index: int) -> string = "lgl_GetStringi"
|
||||
extern function gl_draw_arrays_instanced(mode: int, first: int, count: int, instancecount: int) = "lgl_DrawArraysInstanced"
|
||||
extern function gl_draw_elements_instanced(mode: int, count: int, type: int, indices: pointer, instancecount: int) = "lgl_DrawElementsInstanced"
|
||||
extern function gl_tex_buffer(target: int, internalformat: int, buffer: int) = "lgl_TexBuffer"
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ function http_ok(h: int) -> bool {
|
|||
return (st >= 200) and (st < 300)
|
||||
}
|
||||
|
||||
function http_text(h: int) -> pointer {
|
||||
function http_text(h: int) -> string {
|
||||
if not http_valid(h) { return null }
|
||||
return h_body[h - 1]
|
||||
}
|
||||
|
|
@ -245,7 +245,7 @@ function http_body_len(h: int) -> int {
|
|||
return h_blen[h - 1]
|
||||
}
|
||||
|
||||
function http_header_of(h: int, name: pointer) -> pointer {
|
||||
function http_header_of(h: int, name: pointer) -> string {
|
||||
if not http_valid(h) { return null }
|
||||
let s = h - 1
|
||||
if h_native[s] == 1 { return hs_header(s, name) }
|
||||
|
|
@ -332,7 +332,7 @@ function http_parse(resp: pointer, len: int) -> int {
|
|||
|
||||
# Look up a header value in a raw header block (case-insensitive), returning a
|
||||
# fresh NUL-terminated copy, or null if absent. Lines are "Name: value\r\n".
|
||||
function http_find_header(hdr: pointer, name: pointer) -> pointer {
|
||||
function http_find_header(hdr: pointer, name: pointer) -> string {
|
||||
if hdr == null { return null }
|
||||
let nlen = http_cstr_len(name)
|
||||
let hlen = http_cstr_len(hdr)
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ function regex_end(m: Match, n: int) -> int {
|
|||
if m == null or n < 0 or n > m.ng { return -1 }
|
||||
return m.caps[2 * n + 1]
|
||||
}
|
||||
function regex_group(m: Match, n: int) -> pointer {
|
||||
function regex_group(m: Match, n: int) -> string {
|
||||
if m == null or n < 0 or n > m.ng { return "" }
|
||||
let a = m.caps[2 * n]
|
||||
let b = m.caps[2 * n + 1]
|
||||
|
|
@ -169,7 +169,7 @@ function rx_append(out: IVec, s: pointer, a: int, b: int) -> void {
|
|||
var i = a
|
||||
while i < b { iv_push(out, s[i] & 255); i += 1 }
|
||||
}
|
||||
function regex_replace(str: pointer, pattern: pointer, repl: pointer) -> pointer {
|
||||
function regex_replace(str: pointer, pattern: pointer, repl: pointer) -> string {
|
||||
let p = regex_compile(pattern)
|
||||
if p == null { return str }
|
||||
let n = rx_slen(str)
|
||||
|
|
|
|||
|
|
@ -647,7 +647,7 @@ function tmap_resolve(m: Tmap, gid: int) -> GidInfo {
|
|||
function tmap_width(m: Tmap) -> int { return m.w }
|
||||
function tmap_height(m: Tmap) -> int { return m.h }
|
||||
function tmap_layer_count(m: Tmap) -> int { return len(m.layers) }
|
||||
function tmap_layer_name(m: Tmap, i: int) -> pointer {
|
||||
function tmap_layer_name(m: Tmap, i: int) -> string {
|
||||
if i < 0 or i >= len(m.layers) { return "" }
|
||||
if m.layers[i].name == null { return "" }
|
||||
return m.layers[i].name
|
||||
|
|
@ -855,7 +855,7 @@ function tmap_tileset_from_value(tv: Val) -> TmTileset {
|
|||
return ts
|
||||
}
|
||||
|
||||
function tiled_join(a: pointer, b: pointer) -> pointer { return Path.normalize(Path.join(a, b)) }
|
||||
function tiled_join(a: pointer, b: pointer) -> string { return Path.normalize(Path.join(a, b)) }
|
||||
|
||||
# build the runtime map from an intermediate tree, resolving external tilesets
|
||||
# and loading tileset images relative to `basedir`.
|
||||
|
|
@ -1105,7 +1105,7 @@ function tmap_object(m: Tmap, layer: int, i: int) -> Val {
|
|||
|
||||
# the shape of an object: "tile" (a gid object), "point", "ellipse", "polygon",
|
||||
# "polyline", "text", or "rectangle" (the default).
|
||||
function tiled_object_shape(obj: Val) -> pointer {
|
||||
function tiled_object_shape(obj: Val) -> string {
|
||||
if value_has(obj, "gid") == 1 { return "tile" }
|
||||
if value_has(obj, "point") == 1 { return "point" }
|
||||
if value_has(obj, "ellipse") == 1 { return "ellipse" }
|
||||
|
|
@ -1132,7 +1132,7 @@ function tiled_prop_node(container: Val, name: pointer) -> Val {
|
|||
|
||||
# a property's raw string value, with a fallback to the object's custom-type
|
||||
# default (objecttypes.xml, via the type table). "" when absent everywhere.
|
||||
function tiled_prop_str(container: Val, name: pointer) -> pointer {
|
||||
function tiled_prop_str(container: Val, name: pointer) -> string {
|
||||
let p = tiled_prop_node(container, name)
|
||||
if value_kind(p) == 6 { return value_as_str(value_get(p, "value")) }
|
||||
# fall back to the container's class default
|
||||
|
|
@ -1153,7 +1153,7 @@ function tiled_prop_int(container: Val, name: pointer) -> int {
|
|||
return xml_atoi(s)
|
||||
}
|
||||
|
||||
function tiled_prop_type(container: Val, name: pointer) -> pointer {
|
||||
function tiled_prop_type(container: Val, name: pointer) -> string {
|
||||
let p = tiled_prop_node(container, name)
|
||||
if value_kind(p) == 6 { return value_as_str(value_get(p, "type")) }
|
||||
let cls = value_as_str(value_get(container, "type"))
|
||||
|
|
@ -1353,13 +1353,13 @@ function tmap_layer_kind(m: Tmap, layer: int) -> int {
|
|||
if layer < 0 or layer >= len(m.layers) { return -1 }
|
||||
return m.layers[layer].kind
|
||||
}
|
||||
function tmap_layer_opacity(m: Tmap, layer: int) -> pointer {
|
||||
function tmap_layer_opacity(m: Tmap, layer: int) -> string {
|
||||
if layer < 0 or layer >= len(m.layers) { return "" }
|
||||
let op = value_get(m.layers[layer].data, "opacity")
|
||||
if value_kind(op) == 0 { return "1" }
|
||||
return value_as_str(op)
|
||||
}
|
||||
function tmap_layer_tint(m: Tmap, layer: int) -> pointer {
|
||||
function tmap_layer_tint(m: Tmap, layer: int) -> string {
|
||||
if layer < 0 or layer >= len(m.layers) { return "" }
|
||||
return value_as_str(value_get(m.layers[layer].data, "tintcolor"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ function value_put(obj: Val, key: pointer, item: Val) -> Val {
|
|||
function value_kind(v: Val) -> int { return v.tag }
|
||||
function value_count(v: Val) -> int { return len(v.kids) }
|
||||
function value_as_int(v: Val) -> int { return v.num }
|
||||
function value_as_str(v: Val) -> pointer { if v.txt == null { return "" }; return v.txt }
|
||||
function value_as_str(v: Val) -> string { if v.txt == null { return "" }; return v.txt }
|
||||
function value_at(list: Val, i: int) -> Val {
|
||||
if i < 0 or i >= len(list.kids) { return value_null() }
|
||||
return list.kids[i]
|
||||
}
|
||||
function value_key_at(obj: Val, i: int) -> pointer {
|
||||
function value_key_at(obj: Val, i: int) -> string {
|
||||
if i < 0 or i >= len(obj.keys) { return "" }
|
||||
return obj.keys[i]
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ function value_has(obj: Val, key: pointer) -> int {
|
|||
|
||||
# --- JSON encode ------------------------------------------------------------
|
||||
# escape a string's `"` `\` and newline, wrapping it in quotes.
|
||||
function json_quote(s: pointer) -> pointer {
|
||||
function json_quote(s: pointer) -> string {
|
||||
var out = "\""
|
||||
var i = 0
|
||||
let n = len(s)
|
||||
|
|
@ -96,7 +96,7 @@ function json_quote(s: pointer) -> pointer {
|
|||
# remainder hits zero. This is the exact inverse of jp_number's fixed decode, so
|
||||
# a value_fixed round-trips through JSON bit-for-bit; short values (0.5, 2.0) stay
|
||||
# short. Each step keeps frac < 655360, well within i32.
|
||||
function json_fixed_str(raw: int) -> pointer {
|
||||
function json_fixed_str(raw: int) -> string {
|
||||
var a = raw
|
||||
var sign = ""
|
||||
if a < 0 { sign = "-"; a = -a }
|
||||
|
|
@ -112,7 +112,7 @@ function json_fixed_str(raw: int) -> pointer {
|
|||
return sign + string(ip) + "." + fs
|
||||
}
|
||||
|
||||
function json_encode(v: Val) -> pointer {
|
||||
function json_encode(v: Val) -> string {
|
||||
if v.tag == 0 { return "null" }
|
||||
if v.tag == 1 { return string(v.num) }
|
||||
if v.tag == 2 { return json_fixed_str(v.num) }
|
||||
|
|
@ -172,7 +172,7 @@ function jp_value(p: JP) -> Val {
|
|||
}
|
||||
|
||||
# read a quoted string (cursor on the opening quote) -> the unescaped contents.
|
||||
function jp_string(p: JP) -> pointer {
|
||||
function jp_string(p: JP) -> string {
|
||||
p.i += 1 # skip opening quote
|
||||
var out = ""
|
||||
while p.i < p.n {
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ function xml_new(tag: pointer) -> Xml {
|
|||
}
|
||||
|
||||
# --- accessors --------------------------------------------------------------
|
||||
function xml_tag(n: Xml) -> pointer { if n.tag == null { return "" }; return n.tag }
|
||||
function xml_text(n: Xml) -> pointer { if n.text == null { return "" }; return n.text }
|
||||
function xml_tag(n: Xml) -> string { if n.tag == null { return "" }; return n.tag }
|
||||
function xml_text(n: Xml) -> string { if n.text == null { return "" }; return n.text }
|
||||
function xml_child_count(n: Xml) -> int { return len(n.kids) }
|
||||
function xml_child(n: Xml, i: int) -> Xml {
|
||||
if i < 0 or i >= len(n.kids) { return xml_new("") }
|
||||
|
|
@ -47,7 +47,7 @@ function xml_has(n: Xml, key: pointer) -> int {
|
|||
while i < len(n.akeys) { if n.akeys[i] == key { return 1 }; i += 1 }
|
||||
return 0
|
||||
}
|
||||
function xml_attr(n: Xml, key: pointer) -> pointer {
|
||||
function xml_attr(n: Xml, key: pointer) -> string {
|
||||
var i = 0
|
||||
while i < len(n.akeys) { if n.akeys[i] == key { return n.avals[i] }; i += 1 }
|
||||
return ""
|
||||
|
|
@ -92,7 +92,7 @@ function xml_atoi(s: pointer) -> int {
|
|||
# raw run. Only bytes 0..255 of a character reference are emitted (Ludic strings
|
||||
# are byte strings); a code point above that is written as its low byte, which is
|
||||
# ample for the ASCII/Latin-1 text Tiled attributes carry.
|
||||
function xml_unescape(s: pointer) -> pointer {
|
||||
function xml_unescape(s: pointer) -> string {
|
||||
# fast path: no '&' means nothing to expand
|
||||
var k = 0
|
||||
let m = len(s)
|
||||
|
|
@ -153,7 +153,7 @@ function xml_hexval(c: int) -> int {
|
|||
# a one-byte string holding byte value `b` (1..255); "" for 0 (a NUL can't sit in
|
||||
# a Ludic string). Built by slicing a 256-byte table of every byte value.
|
||||
var xml_bytetab: pointer = null
|
||||
function xml_byte(b: int) -> pointer {
|
||||
function xml_byte(b: int) -> string {
|
||||
if b <= 0 { return "" }
|
||||
if xml_bytetab == null {
|
||||
let t = bytes(257)
|
||||
|
|
@ -202,7 +202,7 @@ function xp_skip_misc(p: XP) -> bool {
|
|||
}
|
||||
|
||||
# read a name (element or attribute): letters, digits, '_', '-', ':', '.'
|
||||
function xp_name(p: XP) -> pointer {
|
||||
function xp_name(p: XP) -> string {
|
||||
let start = p.i
|
||||
while p.i < p.n {
|
||||
let c = p.s[p.i]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue