# emit_machine.ludic — `machine { state Name = v { .. } }` dispatches on # an int state store; `become Name` writes the target state's value back. The # store is either a named program-scope `var` (loaded/stored directly) or, for # older code, a register index (reg()/set_reg()). # If `a` names a program-scope `var`, return it; else null (a register index). function machine_var(a: Node) -> Node { if a.kind == E_ID { let g = find_global(a.s) if (g != null) { if g.kind == N_VAR { return g } } } return null } function emit_machine(st: Node) -> void { let gv = machine_var(st.a) var s = "" if (gv != null) { s = emit_bind(`load i32, ptr @g_{st.a.s}`) } else { let regv = emit_expr(st.a) s = emit_bind(`call i32 @fn_rt_reg(i32 {regv.code})`) } if nmach < len(mach_stk) { mach_stk[nmach] = st } else { push(mach_stk, st) } nmach = nmach + 1 let endl = lbl("smend") var i = 0 while i < len(st.kids) { let state = st.kids[i] let v = emit_expr(state.b) let c = emit_bind(`icmp eq i32 {s}, {v.code}`) let body = lbl("sbody"); let nxt = lbl("sarm") emit(" br i1 "); emit(c); emit(", label %"); emit(body); emit(", label %"); emit(nxt); emit("\n") emit(body); emit(":\n"); g_term = false emit_block(state.a) if not g_term { emit(" br label %"); emit(endl); emit("\n") } emit(nxt); emit(":\n"); g_term = false i = i + 1 } if not g_term { emit(" br label %"); emit(endl); emit("\n") } emit(endl); emit(":\n"); g_term = false nmach = nmach - 1 } # `become Name` — a machine state transition when Name is a state of an # enclosing `machine`, otherwise a scene transition. A scene transition runs the # source scene's on-exit, stores the target scene id into @L_scene, and runs the # target's on-enter (two direct calls and a store — no dispatch table). function emit_become(st: Node) -> void { if nmach > 0 { # inside a machine: try a state first let m = mach_stk[nmach - 1] var target: Node = null var i = 0 while i < len(m.kids) { if (m.kids[i].s == st.s) { target = m.kids[i] }; i = i + 1 } if (target != null) { let gv = machine_var(m.a) let sv = emit_expr(target.b) if (gv != null) { emit(" store i32 "); emit(sv.code); emit(", ptr @g_"); emit(m.a.s); emit("\n") } else { let regv = emit_expr(m.a) emit(" call void @fn_rt_set_reg(i32 "); emit(regv.code); emit(", i32 "); emit(sv.code); emit(")\n") } return } } let sc = find_scene(st.s) # else a scene transition if (sc == null) { perr(`become: no state or scene {st.s}`) } if (g_cur_scene != null) { emit(" call void @scene_exit_"); emit(g_cur_scene.s); emit("()\n") } emit(" store i32 "); emit(itoa(sc.ival)); emit(", ptr @L_scene\n") emit(" call void @scene_enter_"); emit(sc.s); emit("()\n") }