Scriptable properties (ECS-safe subset): @Computed and @OnSpawn
Adds two annotations that give properties/models a scriptable feel WITHOUT reattaching behavior to data — both reduce to code the data-oriented model already emits: - @Computed field on a property: a derived value that is NOT stored; x.field expands inline to its expression (bare names read as fields of x) at each use. Zero storage, zero runtime dispatch. Reuses qualify_fields (now non-destructive, base-node based); a g_computed registry keeps derived fields out of the layout. - @OnSpawn(Model) on a handler: a constructor that runs at each spawn of Model with the model's properties bound by name. Spawn statically knows the model, so no runtime dispatch; emit_spawn binds the properties and inlines the hook body. examples/annotations.ludic now exercises @Handles/@Queries/@Computed/@OnSpawn (output 3 25 0 0); test.sh 15/15, fixpoint holds, goldens byte-identical. Deferred (need more machinery, by design): @OnDespawn (despawn doesn't statically know the entity's model) and @OnChange (needs change-tracking). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
ecead0564e
commit
1951af99e9
9 changed files with 4177 additions and 3503 deletions
|
|
@ -39,6 +39,22 @@ fn emit_init_component(e: ptr, comp: ptr, rec: Node) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
# bind each of a model's properties to entity `e`'s component storage, so an
|
||||
# @OnSpawn hook body can address them by name (like a query binding for one entity).
|
||||
fn emit_bind_props(model: Node, e: ptr) -> void {
|
||||
let me = itoa(MAX_ENT)
|
||||
let c = 0
|
||||
while c < len(model.kids) {
|
||||
let pname = model.kids[c].s
|
||||
let slot = nreg()
|
||||
emit(" "); emit(slot); emit(" = getelementptr inbounds ["); emit(me); emit(" x %Cmp_"); emit(pname); emit("], ptr @S_"); emit(pname); emit(", i32 0, i32 "); emit(e); emit("\n")
|
||||
let vslot = emit_alloca("ptr")
|
||||
emit(" store ptr "); emit(slot); emit(", ptr "); emit(vslot); emit("\n")
|
||||
loc_push(pname, vslot, pname)
|
||||
c = c + 1
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_spawn(st: Node) -> void {
|
||||
let e = emit_bind("call i32 @L_alloc()")
|
||||
let ak = find_arch_id(st.s)
|
||||
|
|
@ -56,6 +72,13 @@ fn emit_spawn(st: Node) -> void {
|
|||
emit_init_component(e, cn, rec)
|
||||
c = c + 1
|
||||
}
|
||||
let ob = onspawn_body(st.s) # @OnSpawn(Model) hook runs after init
|
||||
if not ptr_is_null(ob) {
|
||||
let save = nloc
|
||||
emit_bind_props(arch, e)
|
||||
emit_block(ob)
|
||||
nloc = save
|
||||
}
|
||||
} else {
|
||||
let i = 0
|
||||
while i < len(st.kids) { emit_init_component(e, st.kids[i].s, st.kids[i].a); i = i + 1 }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue