You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5.9KB


story: E06-S07 owner: codebuff status: in-progress started: 2026-11-10 depends-on: [E06-S05, E05-S04, E04-S06, E04-S07]

E06-S07 Claim

Intended change

Emit interface values from source rather than only from hand-written fixtures: store and copy all four bytes of an object/table pair in locals, parameters, fields and array elements; convert a class reference or null at a use site; and call an interface method through if_call with the compile-time slot. The emitted code reuses the E06-S02 trampoline, the E06-S04 conversions, and iface_slot, so no new runtime entry point or layout is introduced (D153).

File area

  • src/compiler/emit.s: four-byte value paths for a slot, a field and a call site; interface-aware em_target/em_store_target
  • src/compiler/members.s: four-byte member load/store between a field and if_dst/if_src
  • src/compiler/parser.s: pass-2 hooks for conversion assignment and interface call sites
  • src/compiler/iftables.s: the table lookup the conversion emission needs (it_find, already present)
  • src/common/emit.inc: new emitter error codes for an unsupported interface shape
  • tests/compiler/iface.n8, tests/compiler/iface-test.s
  • scripts/build-iface-test.ps1, scripts/verify-iface-test.ps1
  • tests/semantic/*.n8 for the misuse diagnostics
  • docs/decisions.md (D153), docs/architecture.md, docs/memory-map.md
  • planning/claims/E06-S07.md
  • generated files under build/iface-test/

Acceptance criteria (from the story)

  • Concrete-to-interface assignment in a statement, argument, return or initializer emits the E06-S04 conversion path and stores all four bytes.
  • null in an interface context produces the canonical null value and a call through it takes the fault path.
  • Interface-typed locals, parameters, returns and fields keep all four bytes, including array elements and copies.
  • A source-level interface call emits if_call with the value pointer in A/X and the slot in Y, with arguments and one-/two-byte returns.
  • Two classes dispatch one interface call differently, and one class dispatching two interfaces works, compiled from source.
  • Unrelated class assignment, undeclared interface member and private member through an interface each report their catalogue code and emit no PRG.
  • MAP output names the interface tables and slots the emitted code uses.

Coordination notes

  • The type checker is not the gap: types.s already classifies class and interface references by name and ty_assign accepts a class for an interface it implements (tests/semantic/refs.n8). Interface slots therefore allocate four bytes through the existing size argument; the byte-only emitter is what refuses them (EM_ERR_SIZE from em_expr_name, em_target, em_bin).
  • if_assign takes the destination in A/X and the mode in Y (0 copies if_src, any other value converts if_obj with if_tab); if_call takes the value pointer in A/X and the slot in Y and reports through if_error. Both are already proven by tests/runtime/convert-test.s and tests/runtime/ifcall-test.s.
  • Zero page has no room for another pointer: $F2-$F4 is the only free gap, so D153 keeps one value address (EM_LP) plus the runtime's own module pointers.
  • E04-S07 owns frame sizing, pass-3 addresses and argument push/discard, so interface calls with arguments cannot be emitted before it; that is why this claim lists it as a dependency. The zero-argument call and all storage and conversion shapes do not need it.

Work log

  • Read emit.s, members.s, codegen.s, emit.inc, interfaces.inc, types.s and the runtime interface API. The emitter is byte-only end to end: em_size is compared with 1 in load, push, combine, target and store, and em_target accepts only a one-byte local or a one-byte self field.
  • mb_ld_field/mb_st_field accept MB_BYTE or MB_WORD only, so a four-byte interface field needs its own member transfer; mb_point already loads any object reference into MB_SELF, which a receiver expression can reuse.
  • iface_slot returns the slot from the interface's signature rows and is the only correct source of the call's Y; it_find returns the class's table for a given interface, which is the compile-time half of a conversion.
  • Emitter state has no four-byte temp: em_size is a single byte count and the left-operand path pushes exactly one byte. Conversions and copies must move all four bytes through the runtime routines rather than a new temp.
  • Story dependency corrected: E04-S07 added, because argument push/discard and word results are its work, and the story's argument criterion cannot be met without it.

Completion

  • Tests run: none yet. This claim records analysis and the emission decision; no emitter, parser or fixture change has landed, so there is no behaviour to verify and the claim stays in-progress rather than done.
  • Results: not applicable.
  • Remaining risks: pass 2 emits as it type-checks, so a four-byte target must be known before the operand is emitted, which is a different ordering from the byte path where the target is captured and consumed afterwards; a conversion site must also decide between if_assign mode 0 and 1 from the source type that types.s already computed.

Next steps

  1. Add the four-byte slot load/store and em_target/em_store_target cases with IF_VALUE_SIZE, plus EM_ERR_SIZE only for shapes that are still unsupported.
  2. Add mb_ld_iface/mb_st_iface and use them for interface fields.
  3. Emit conversion assignment at a use site: it_find for if_tab, source pointer or zero into if_obj, destination slot pointer into if_dst, JSR if_assign with mode 0 or 1.
  4. Emit if_call from an interface receiver with iface_slot as Y, then the iface.n8 fixture with two classes and two interfaces, and the misuse diagnostics in the semantic suite.

Powered by TurnKey Linux.