|
|
|
@@ -0,0 +1,118 @@ |
|
|
|
--- |
|
|
|
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. |