feat(lang): functions are values (L2), and render3d takes its scene as callbacks
fn(int, float) -> bool is a type, fn name is any top-level function's value, and a call through a local, a global, a record field, a slice element, a parameter or a result of a function type is an indirect call; two function types mix only when equal, a call checks its argument count, and a value may be null (examples/functions/values.ludic). Job.parallel_for keeps its worker check. render3d's scene is registered rather than required by name: r3d_on_draw, r3d_on_casters and r3d_on_stream_fill (hooks.ludic). The two rendering examples register theirs - and had defined scene_draw_casters with no parameter while the renderer passed one, which nothing checked. render3d declares numbers float itself; smooth.ludic is converted to floats and returns when r3d_init fails instead of running on into a segfault. Noise.* check their argument count (a call one short crashed the compiler). selfhost-build says why it failed. The migration tool reads a declared float as evidence. Seed regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
dc75a5a5ab
commit
0c73287e35
23 changed files with 71430 additions and 68575 deletions
|
|
@ -35,23 +35,28 @@ function emit_noise_ns(meth: pointer, e: Node) -> Val {
|
|||
}
|
||||
g_uses_noisert = true
|
||||
if (meth == "value2") {
|
||||
noise_arity(e, "value2", 3)
|
||||
let x = emit_expr(e.kids[0]); let y = emit_expr(e.kids[1]); let s = emit_expr(e.kids[2])
|
||||
return val(emit_bind(`call i32 @lp_noise_value2(i32 {x.code}, i32 {y.code}, i32 {s.code})`), "fixed")
|
||||
}
|
||||
if (meth == "perlin2") {
|
||||
noise_arity(e, "perlin2", 3)
|
||||
let x = emit_expr(e.kids[0]); let y = emit_expr(e.kids[1]); let s = emit_expr(e.kids[2])
|
||||
return val(emit_bind(`call i32 @lp_noise_perlin2(i32 {x.code}, i32 {y.code}, i32 {s.code})`), "fixed")
|
||||
}
|
||||
if (meth == "simplex2") {
|
||||
noise_arity(e, "simplex2", 3)
|
||||
let x = emit_expr(e.kids[0]); let y = emit_expr(e.kids[1]); let s = emit_expr(e.kids[2])
|
||||
return val(emit_bind(`call i32 @lp_noise_simplex2(i32 {x.code}, i32 {y.code}, i32 {s.code})`), "fixed")
|
||||
}
|
||||
if (meth == "fbm2") {
|
||||
noise_arity(e, "fbm2", 4)
|
||||
g_uses_mathrt = true # simplex path is standalone; fbm needs fx_div only (local)
|
||||
let x = emit_expr(e.kids[0]); let y = emit_expr(e.kids[1]); let s = emit_expr(e.kids[2]); let o = emit_expr(e.kids[3])
|
||||
return val(emit_bind(`call i32 @lp_noise_fbm2(i32 {x.code}, i32 {y.code}, i32 {s.code}, i32 {o.code})`), "fixed")
|
||||
}
|
||||
if (meth == "cellular2") {
|
||||
noise_arity(e, "cellular2", 3)
|
||||
g_uses_mathrt = true # F1 distance needs @lp_fx_sqrt
|
||||
let x = emit_expr(e.kids[0]); let y = emit_expr(e.kids[1]); let s = emit_expr(e.kids[2])
|
||||
return val(emit_bind(`call i32 @lp_noise_cellular2(i32 {x.code}, i32 {y.code}, i32 {s.code})`), "fixed")
|
||||
|
|
@ -215,3 +220,13 @@ function emit_noise_cellular() -> void {
|
|||
emith(" %d2 = alloca i32\n %id = alloca i32\n call void @lp_noise_cell_scan(i32 %x, i32 %y, i32 %seed, ptr %d2, ptr %id)\n")
|
||||
emith(" %r = load i32, ptr %id\n ret i32 %r\n}\n")
|
||||
}
|
||||
# Noise.* take their arguments by position, and fbm2's fourth is the octave count: a call one short
|
||||
# used to read past its arguments and crash the compiler - or, where the call happened to fit,
|
||||
# put the octaves in the seed and give a flat 0.5 everywhere
|
||||
function noise_arity(e: Node, meth: pointer, n: int) -> void {
|
||||
if len(e.kids) != n { perr(`Noise.{meth} takes {itoa(n)} arguments (x, y, seed{noise_arity_more(n)}), and this call gives {itoa(len(e.kids))}`) }
|
||||
}
|
||||
function noise_arity_more(n: int) -> pointer {
|
||||
if n == 4 { return ", octaves" }
|
||||
return ""
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue