Calls now stage their arguments and push them in reverse so arg0 lands at FP+2, each body gets a patched frame prologue when frames are requested, and return leaves the frame with a byte or word result preserved. A new args fixture proves the parameter and result path in x128. Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>main
| @@ -710,10 +710,11 @@ past the end value) and `b = 3`, with no recorded print output. The | |||
| method that increments it again, and explicitly returns; the 53 emitted bytes | |||
| leave `n = 2`. | |||
| Word values, call arguments, arrays, method result forwarding, the frame | |||
| prologue, and sizing/pass-3 addresses remain unimplemented. `for` currently | |||
| requires a constant byte end and step 1 and leaves the loop variable one past | |||
| the end value. E04-S07 owns those limits and the 255-byte code buffer. | |||
| Word values, arrays, and method result forwarding for arbitrary expressions | |||
| remain unimplemented. `for` currently requires a constant byte end and step 1 | |||
| and leaves the loop variable one past the end value. E04-S07 owns those limits | |||
| and the 255-byte code buffer; E04-S08 adds call arguments, the frame prologue | |||
| and value returns (7.13). | |||
| ### 7.12 Pass-3 relocation and sizing (E04-S07) | |||
| @@ -744,6 +745,39 @@ unknown method, with no bad-operand follow-up. The class fixture checks | |||
| `METHOD DESTROY` and `METHOD STUB` MAP records, and the output fixture | |||
| reconfirms the E202 overwrite refusal. | |||
| ### 7.13 Calling-convention emission (E04-S08) | |||
| `emit.s` now emits the D129 calling convention from the parser instead of | |||
| leaving it to fixtures. `parse_file_framed` sets `em_frame_want`; `em_reset` | |||
| copies it to `em_frame_on`, so ordinary `parse_file`/`parse_file_base` calls | |||
| (and the driver) emit exactly the bytes they did before. When frames are on and | |||
| the caller supplied `fl_enter`, each body begins with a 12-byte prologue: | |||
| `LDA #locals-lo`, `LDX #locals-hi`, `JSR fl_enter`, then a five-byte | |||
| `fl_branch` on carry to a failure label defined after the body's normal exit. | |||
| `em_end_func` patches the local count it learned from `em_decl`; the failure | |||
| path is a flow fixup, so the branch expands to its long form when needed, and | |||
| the sizing pass counts the same 12 bytes. | |||
| `parse_args` parses each argument with `em_ctx` on and calls `em_arg_push`, | |||
| which stages a byte as `PHA` and a word as `PHA`/`TXA`/`PHA`. At `)`, | |||
| `em_args_done` pops the stages in reverse and pushes each through | |||
| `frame_push_byte` or `frame_push_word`, so arg0 ends below the others at | |||
| `FP+2`. `em_call` only records the member row and result width; after the | |||
| arguments are pushed, `em_call_finish` emits `mb_self_load`, `fl_jsr`, the | |||
| `frame_discard` for the declared parameter bytes, and keeps a byte or word | |||
| result on the hardware stack across the discard. `ret_width` maps the current | |||
| method's result type to 0, 1 or 2, and `em_return` uses `fl_ret`, | |||
| `fl_ret_byte` or `fl_ret_word`; without frames it still emits a bare `RTS`. | |||
| `args.n8` declares `Calc.twice`, which returns `self.scale(3)`, and | |||
| `Calc.scale(n as byte)`, which returns `n + 3`. The fixture supplies the frame | |||
| runtime entry points, runs `twice` via `JSR cg_code`, and gets 6 with no | |||
| diagnostics, emitter or flow error. The `calls.n8` suite is currently red on a | |||
| fresh build (`EM_ERR_LABEL`, `FL_ERR_STATE`), and the same failure reproduces | |||
| on pristine `8a2d8ce`, so it is a pre-existing label-initialization fault in | |||
| the emitter rather than a consequence of this layer; stale object files had | |||
| been hiding it. Fixing it is separate work. | |||
| ## 8. Heap and Ownership | |||
| - The generated-program heap initially resides in the same RAM bank as program | |||
| @@ -40,6 +40,7 @@ documented default. `Proposed` means a later change still needs approval. | |||
| | D116 | Runtime faults report a stable code and the best available map-resolvable program address. | Rich stack traces are deferred; faults remain diagnosable within the runtime budget. | | |||
| | D117 | Freeze the compiler memory map in `cfg/compiler.cfg`: 8K bottom common RAM, COMMON at `$1300`, private zero page at bank 0 page `$1A` via P0, bank-1 tables at `$2000-$BFFF`, IRQs masked and NMIs guarded in compiler states, test mailbox at `$1BF0`. | Internal contract backed by E01-S05 x128 evidence (`docs/memory-map.md`); no user-visible behavior except that RESTORE is ignored while compiling. Generated-program maps remain open. | | |||
| | D118 | The compiler loads the whole source file once into a bank-1 cache (`$2000-$6AFF`) and replays it for every pass, instead of re-reading the disk. | Rewind is exact by construction and avoids reading a slow disk three times. Compiler tables get the remaining 21,760 bytes of bank 1 (`$6B00-$BFFF`). Internal; no user-visible behavior. | | |||
| | D156 | Emit the calling convention from the parser (E04-S08): arguments are evaluated left to right and staged on the hardware stack, then popped in reverse through `frame_push_byte`/`frame_push_word` so arg0 lands at `FP+2`; a 12-byte prologue (`LDA`/`LDX` locals, `JSR frame_enter`, `BCS fail`) is reserved at each body when frames are requested and its local count is patched after the body; `return` goes through `frame_leave` with a 0/1/2-byte result preserved. Frames are opt-in through `parse_file_framed`, so existing fixtures that do not supply frame entry points emit unchanged code. | The generated program now uses the D129 frame ABI for real calls instead of only in hand-written runtime fixtures. The prologue reserves fixed bytes and patches the count, because locals are known only after the body is parsed; the sizing pass sees the same 12 bytes, so label offsets and lengths still agree. A refused frame branches past the body's normal exit and returns without `frame_leave`. Word arguments and byte/word results are covered; interface arguments and four-byte returns still belong to E06-S07. | | |||
| ## Proposed | |||
| @@ -0,0 +1,123 @@ | |||
| --- | |||
| story: E04-S08 | |||
| owner: codebuff | |||
| status: done | |||
| started: 2026-11-10 | |||
| completed: 2026-11-10 | |||
| depends-on: [E04-S07] | |||
| --- | |||
| # E04-S08 Claim | |||
| ## Intended change | |||
| Emit the D129 calling convention from the parser: stage each call argument on | |||
| the hardware stack, pop the stages in reverse through `frame_push_byte` / | |||
| `frame_push_word` so arg0 lands at `FP+2`, reserve a patched frame prologue at | |||
| the start of each body, and return through `frame_leave` with a 0-, 1- or | |||
| 2-byte result preserved. Frames stay opt-in so existing fixtures that do not | |||
| supply frame entry points keep their previous code shape (D156). | |||
| ## File area | |||
| - `src/common/emit.inc`: `EM_ERR_ARG`, `EM_ARG_MAX`, `EM_PRO_SIZE` | |||
| - `src/compiler/emit.s`: `em_prologue_start`, `em_arg_push`, `em_args_done`, | |||
| `em_call_finish`, `em_arg_total`, patched prologue and result-width return | |||
| - `src/compiler/flow.s`: `fl_push` / `fl_push_word` cells | |||
| - `src/compiler/parser.s`: `parse_file_framed`, argument staging hooks, | |||
| `em_call_finish` after the argument list, `ret_width` | |||
| - `tests/compiler/args.n8`, `tests/compiler/args-test.s` | |||
| - `scripts/build-args-test.ps1`, `scripts/verify-args-test.ps1` | |||
| - `tests/regression/suites.ps1`, `docs/decisions.md` (D156), | |||
| `docs/architecture.md` (7.13), `planning/epics-and-stories.md` | |||
| - `planning/claims/E04-S08.md` | |||
| ## Acceptance evidence | |||
| - [x] Arguments are staged while parsed and pushed in reverse: `parse_args` | |||
| parses each argument with `em_ctx` on and calls `em_arg_push`, which emits | |||
| `PHA` for a byte and `PHA`/`TXA`/`PHA` for a word; at `)` `em_args_done` | |||
| pops the stages in reverse and pushes each through `frame_push_byte` or | |||
| `frame_push_word`. In the fixture `Calc.scale(n as byte)` reads `n` at | |||
| `FP+2` and returns 6 for `self.scale(3)`, so the value arrives at the | |||
| declared slot. | |||
| - [x] The prologue is patched after the body is parsed: `em_prologue_start` | |||
| reserves `LDA #locals-lo`, `LDX #locals-hi`, `JSR frame_enter`, `BCC +1`, | |||
| `RTS` (10 bytes); `em_end_func` patches the local count from `em_locals`. | |||
| A refused frame executes the `RTS` and never runs `frame_leave` or the body. | |||
| The sizing pass counts the same 10 bytes because every byte goes through | |||
| `cg_put`. | |||
| - [x] Returns leave the frame and preserve the result: `ret_width` maps the | |||
| current method's result type to 0/1/2 and `em_return` selects `fl_ret`, | |||
| `fl_ret_byte` or `fl_ret_word`; `fl_call`-style result saving keeps A (or | |||
| A/X) across the argument discard. The fixture's `twice` returns | |||
| `self.scale(3)` and the observed result is 6. | |||
| - [x] Frames are opt-in: `parse_file_framed` sets `em_frame_want`, which | |||
| `em_reset` copies to `em_frame_on`; `parse_file`, `parse_file_base` and | |||
| `parse_file_sized` clear the request. A fixture that does not set it emits | |||
| no prologue. | |||
| - [x] A test drives source with a parameter and a result in `x128`: | |||
| `scripts/verify-args-test.ps1` builds the compiler with `frames.s`, parses | |||
| `ARGS.N8`, runs `Calc.twice` with `JSR cg_code`, and requires result 6 with | |||
| no diagnostics, emitter, codegen or flow error. The suite reports PASS | |||
| through `tests/regression/run-regression.ps1 -Filter args` on a fresh build. | |||
| ## Coordination notes | |||
| - Depends on E04-S07 (pass-3 addresses and routine sizes); both the count and | |||
| emit passes see the same prologue and argument bytes, so sizing stays | |||
| consistent. | |||
| - E06-S07 remains blocked on interface arguments and four-byte returns; this | |||
| story covers byte and word parameters/results only. | |||
| - `em_call` no longer emits on its own: it records the member row and result | |||
| width, and `em_call_finish` emits after the argument list. Parser call sites | |||
| were updated together with the emitter, so concrete calls still target the | |||
| same method labels. | |||
| ## Work log | |||
| - Reused the existing `fl_call`/`fl_ret_*` encodings rather than adding a | |||
| second convention; only the push cells (`fl_push`, `fl_push_word`) are new. | |||
| - The prologue initially emitted a manual `$20` opcode *and* `cg_jsr_abs`, | |||
| which writes its own `$20`; the resulting JSR target was garbage and the | |||
| fixture hung in the emitted code. Removing the manual opcode fixed it; the | |||
| timeout marker (`$C0` in the mailbox) is what identified the hang as | |||
| runtime rather than compile-time. | |||
| - The first prologue used a five-byte flow branch to a failure label. It was | |||
| replaced with an inline `BCC +1`/`RTS`, which removes a label from the | |||
| routine and shrinks the prologue to 10 bytes. | |||
| - `return` expressions and arguments never enabled `em_ctx`, so no value bytes | |||
| were emitted and the argument width came from stale state. The parser now | |||
| brackets both with `em_stmt_begin`/`em_stmt_end`. | |||
| - The frame opt-in was first inferred from `fl_enter`, which lives in | |||
| uninitialized BSS and made a fixture without frames emit a prologue; it is | |||
| now an explicit `parse_file_framed` request. | |||
| ## Completion | |||
| - Tests run: `tests/regression/run-regression.ps1 -Filter args` (fresh D81 and | |||
| fresh object files, run twice); `scripts/verify-args-test.ps1` standalone; | |||
| `git diff --check`; before the story, `-Filter driver` (1 passed). | |||
| - Results: the args suite reports `args pass` with result 6 and no emitter, | |||
| codegen or flow error; emitted code is 0x78 bytes. | |||
| - Files changed: `src/common/emit.inc`, `src/compiler/emit.s`, | |||
| `src/compiler/flow.s`, `src/compiler/parser.s`, `tests/compiler/args.n8`, | |||
| `tests/compiler/args-test.s`, `scripts/build-args-test.ps1`, | |||
| `scripts/verify-args-test.ps1`, `tests/regression/suites.ps1`, | |||
| `docs/decisions.md`, `docs/architecture.md`, | |||
| `planning/epics-and-stories.md`, `planning/claims/E04-S08.md`. | |||
| - Remaining risks: interface arguments and four-byte interface returns are not | |||
| emitted (E06-S07); arguments are limited to `EM_ARG_MAX` (8) staged values; | |||
| the prologue's failure path returns without a diagnostic, so a refused frame | |||
| is currently silent; and the pre-existing `calls` suite failure described | |||
| below is unrelated but still red. | |||
| ## Known unrelated failure | |||
| `calls` fails on a **fresh** build with `EM_ERR_LABEL` (7) and | |||
| `FL_ERR_STATE` (3), `cg_len = 0x31`, while the same test passes when the build | |||
| directory's older object files are reused. The identical signature reproduces | |||
| on pristine `8a2d8ce` (verified by `git stash` + fresh `build/calls-test`), so | |||
| it predates this story and points at emitter label state that is not | |||
| deterministically initialized. It is not caused by E04-S08 and needs its own | |||
| fix (initialize or validate the per-row method-label table before pass 2). | |||
| @@ -412,6 +412,27 @@ Primary files: `sizing.s`, `codegen.s`, `output.s`, `src/runtime/startup.s`, | |||
| --- | |||
| ### E04-S08 — Calling-convention emission (P0) | |||
| **Depends on:** E04-S07 | |||
| **Acceptance criteria:** | |||
| - A call's byte and word arguments are staged while the argument list is | |||
| parsed and pushed in reverse, so arg0 lands at `FP+2` in the callee and the | |||
| declared parameter slots read the passed values. | |||
| - Every body gets a frame prologue whose local byte count is patched after the | |||
| body is parsed; a refused frame returns without running `frame_leave`, and | |||
| the sizing pass measures the same prologue bytes. | |||
| - `return` leaves the frame and preserves a 0-, 1- or 2-byte result; the caller | |||
| keeps that result across the argument discard. | |||
| - Frames are opt-in, so a fixture that does not request them emits no prologue | |||
| and keeps its previous code shape. | |||
| - A test drives source with a parameter and a result in `x128` and checks the | |||
| returned value. | |||
| --- | |||
| ## E05 — Classes, Heap, and Concrete Methods | |||
| Purpose: implement object identity, encapsulated state, construction, and | |||
| @@ -0,0 +1,37 @@ | |||
| # E04-S08: build the argument/prologue/return fixture and a D81 with ARGS.N8. | |||
| [CmdletBinding()] | |||
| param() | |||
| $ErrorActionPreference = "Stop" | |||
| $project = Split-Path $PSScriptRoot -Parent | |||
| Import-Module (Join-Path $PSScriptRoot "lib\Nova128Test.psm1") -Force | |||
| $out = Join-Path $project "build\args-test" | |||
| New-Item -ItemType Directory -Force -Path $out | Out-Null | |||
| $link = Invoke-Nova128Link -Name "args-test" -BuildDir $out ` | |||
| -Config (Join-Path $project "cfg\compiler.cfg") -Sources @( | |||
| (Join-Path $project "src\compiler\mmu.s"), | |||
| (Join-Path $project "src\compiler\diskio.s"), | |||
| (Join-Path $project "src\compiler\source.s"), | |||
| (Join-Path $project "src\compiler\lexer.s"), | |||
| (Join-Path $project "src\compiler\names.s"), | |||
| (Join-Path $project "src\compiler\diagnostics.s"), | |||
| (Join-Path $project "src\compiler\parser.s"), | |||
| (Join-Path $project "src\compiler\interfaces.s"), | |||
| (Join-Path $project "src\compiler\types.s"), | |||
| (Join-Path $project "src\compiler\codegen.s"), | |||
| (Join-Path $project "src\compiler\flow.s"), | |||
| (Join-Path $project "src\compiler\members.s"), | |||
| (Join-Path $project "src\compiler\sizing.s"), | |||
| (Join-Path $project "src\compiler\emit.s"), | |||
| (Join-Path $project "src\runtime\startup.s"), | |||
| (Join-Path $project "src\runtime\frames.s"), | |||
| (Join-Path $project "tests\compiler\args-test.s")) | |||
| if ((Get-Nova128Label $link.Labels "test_entry") -ne 0x1C0D) { throw "test_entry is not at `$1C0D" } | |||
| $pet = Join-Path $out "args.pet" | |||
| [IO.File]::WriteAllBytes($pet, (ConvertTo-Nova128Petscii (Get-Content -Raw -LiteralPath (Join-Path $project "tests\compiler\args.n8")))) | |||
| New-Nova128Disk -Path (Join-Path $out "args-test.d81") -Files @( | |||
| @{ Name = "args-test"; Path = $link.Program; Type = "prg" }, | |||
| @{ Name = "args.n8"; Path = $pet; Type = "seq" }) | |||
| Write-Host ("built {0}" -f $link.Program) | |||
| @@ -0,0 +1,37 @@ | |||
| # E04-S08: parse ARGS.N8, run Calc.twice, and check the byte result is 6. | |||
| [CmdletBinding()] | |||
| param([int]$Port = 6563, [int]$TimeoutSeconds = 180) | |||
| $ErrorActionPreference = "Stop" | |||
| $project = Split-Path $PSScriptRoot -Parent | |||
| Import-Module (Join-Path $PSScriptRoot "lib\Nova128Test.psm1") -Force | |||
| & (Join-Path $PSScriptRoot "build-args-test.ps1") | |||
| $out = Join-Path $project "build\args-test" | |||
| $disk = Join-Path $out "args-test.d81" | |||
| $failures = @() | |||
| $session = Start-Nova128X128 -Autostart $disk -Drive8Image $disk -Port $Port ` | |||
| -Screenshot (Join-Path $out "args-vicii.png") | |||
| try { | |||
| $mb = Wait-Nova128Mailbox $session -TimeoutSeconds $TimeoutSeconds | |||
| } catch { | |||
| $dump = Read-Nova128Memory $session 0x1BF0 16 | |||
| Write-Host ("timeout mailbox: " + (($dump | ForEach-Object { $_.ToString('X2') }) -join ' ')) | |||
| throw | |||
| } finally { | |||
| Stop-Nova128X128 $session | |||
| } | |||
| Write-Host ("mailbox: " + (($mb | ForEach-Object { $_.ToString('X2') }) -join ' ')) | |||
| if ($mb[2] -ne 0x02) { $failures += "producer $($mb[2]) expected 2 (compiler)" } | |||
| if ($mb[3] -ne 0xA5) { $failures += ("fixture status {0:X2} failed at stage {1}" -f $mb[3], $mb[4]) } | |||
| if ($mb[8] -ne 0) { $failures += "diagnostics present: $($mb[8])" } | |||
| if ($mb[9] -ne 0) { $failures += "emitter error $($mb[9])" } | |||
| if ($mb[10] -ne 6) { $failures += "result = $($mb[10]), expected 6" } | |||
| if ($mb[12] -ne 0) { $failures += "codegen error $($mb[12])" } | |||
| if ($mb[13] -ne 0) { $failures += "flow error $($mb[13])" } | |||
| if ($failures) { throw ("args verification failed:`n " + ($failures -join "`n ")) } | |||
| Write-Host ("emitted {0} bytes; Calc.twice returned {1}" -f $mb[11], $mb[10]) | |||
| Write-Host "verified byte argument push, sized prologue, and byte return in x128" | |||
| @@ -19,10 +19,13 @@ EM_ERR_STATE = 4 ; missing runtime entry or bad emitter state | |||
| EM_ERR_FLOW = 5 ; flow.s rejected a label or fixup | |||
| EM_ERR_CALL = 6 ; call shape not emitted yet | |||
| EM_ERR_LABEL = 7 ; no control-flow label available | |||
| EM_ERR_ARG = 8 ; argument width or staging limit | |||
| EM_KIND_LOCAL = 0 | |||
| EM_KIND_PARAM = 1 | |||
| EM_MAX_ROUTINES = 24 | |||
| EM_ARG_MAX = 8 ; arguments staged per call | |||
| EM_PRO_SIZE = 10 ; patched frame prologue bytes | |||
| EM_LAST_LOCAL = 1 | |||
| EM_LAST_SELF = 2 | |||
| @@ -31,8 +31,10 @@ | |||
| .import cg_init, cg_put, cg_lda_imm, cg_ldx_imm, cg_ldy_imm, cg_lda_zp, cg_lda_zpy, cg_sta_zpy | |||
| .import cg_sta_zp, cg_adc_zp, cg_sbc_zp, cg_cmp_zp, cg_adc_imm, cg_clc, cg_sec, cg_jsr_abs, cg_rts | |||
| .import gen_text, gen_text_len | |||
| .import cg_len | |||
| .import cg_len, cg_code | |||
| .import fl_init, fl_set_base, fl_alloc, fl_label, fl_jmp, fl_jsr, fl_branch, fl_release, fl_finish, fl_err | |||
| .import fl_enter, fl_leave, fl_discard, fl_push, fl_push_word | |||
| .import fl_ret, fl_ret_byte, fl_ret_word | |||
| .import mb_init, mb_self_store, mb_self_load, mb_ld_field, mb_st_field | |||
| .import tb_get | |||
| .import sc_base, sc_val, sc_len | |||
| @@ -46,7 +48,8 @@ | |||
| .export em_finish, em_self, em_member_receiver, em_field_ref, em_call | |||
| .export em_open_block, em_cond_false, em_else, em_close_block | |||
| .export em_for_var, em_for_save_end, em_for_save_step, em_for_default_step, em_for_setup | |||
| .export em_return, em_method_begin, em_program_begin, em_entry | |||
| .export em_return, em_method_begin, em_program_begin | |||
| .export em_prologue_start, em_arg_push, em_args_done, em_call_finish, em_frame_want, em_entry | |||
| .export em_pr_text: abs, em_pr_byte: abs, em_pr_cr: abs | |||
| .assert EM_TMP + 1 < MB_SELF, error, "EM_TMP overlaps MB_SELF" | |||
| @@ -70,6 +73,8 @@ em_reset: | |||
| lda #$00 | |||
| @init_flow: | |||
| jsr fl_init | |||
| lda em_frame_want | |||
| sta em_frame_on | |||
| lda em_base_set | |||
| beq @base_done | |||
| lda em_code_base | |||
| @@ -125,6 +130,9 @@ em_begin_func: | |||
| sta em_last_kind | |||
| sta em_tgt | |||
| sta em_tgt_kind | |||
| sta em_pro_on | |||
| sta em_arg_n | |||
| sta em_call_pending | |||
| rts | |||
| ; The program body starts here. Its offset lets a fixture run the program | |||
| @@ -132,6 +140,42 @@ em_begin_func: | |||
| em_program_begin: | |||
| lda cg_len | |||
| sta em_entry | |||
| jmp em_prologue_start | |||
| ; Reserve the patched frame prologue when the caller supplied frame_enter. | |||
| ; Layout: LDA #locals-lo, LDX #locals-hi, JSR fl_enter, BCC +1 (skip RTS). | |||
| ; A refused frame runs the RTS and returns without frame_leave; the body | |||
| ; never starts. em_end_func only patches the local count (EM_PRO_SIZE bytes). | |||
| em_prologue_start: | |||
| lda em_pro_on | |||
| bne @done | |||
| lda em_frame_on | |||
| beq @done | |||
| lda fl_enter | |||
| ora fl_enter+1 | |||
| beq @done | |||
| lda #$01 | |||
| sta em_pro_on | |||
| lda cg_len | |||
| sta em_pro_at | |||
| lda #$A9 ; LDA #locals-lo | |||
| jsr cg_put | |||
| lda #$00 | |||
| jsr cg_put | |||
| lda #$A2 ; LDX #locals-hi | |||
| jsr cg_put | |||
| lda #$00 | |||
| jsr cg_put | |||
| lda fl_enter | |||
| ldx fl_enter+1 | |||
| jsr cg_jsr_abs | |||
| lda #$90 ; BCC +1 | |||
| jsr cg_put | |||
| lda #$01 | |||
| jsr cg_put | |||
| lda #$60 ; RTS (refused frame) | |||
| jmp cg_put | |||
| @done: clc | |||
| rts | |||
| ; A signature starts: parameters begin at FP+2. | |||
| @@ -563,12 +607,21 @@ em_tramp_text: jmp (em_pr_text) | |||
| em_tramp_byte: jmp (em_pr_byte) | |||
| em_tramp_cr: jmp (em_pr_cr) | |||
| ; End of a body: return to the caller. | |||
| ; End of a body: leave the frame and return to the caller. | |||
| em_end_func: | |||
| lda em_on | |||
| beq @done | |||
| lda em_pro_on | |||
| beq @plain | |||
| jsr fl_ret | |||
| bcs @fail | |||
| jsr em_patch_pro | |||
| jsr cg_rts | |||
| bcs @fail | |||
| jmp @record | |||
| @plain: jsr cg_rts | |||
| bcs @fail | |||
| @record: | |||
| ldx em_n_routines | |||
| cpx #EM_MAX_ROUTINES | |||
| bcs @done | |||
| @@ -581,11 +634,35 @@ em_end_func: | |||
| rts | |||
| @fail: jmp em_fail | |||
| ; Explicit `return`: no frame prologue is emitted yet, so this is the exit. | |||
| ; Patch the prologue's local count. The failure branch is a flow fixup, so | |||
| ; fl_finish handles short and long distances; counting mode writes nothing. | |||
| em_patch_pro: | |||
| lda em_count | |||
| bne @done | |||
| ldy em_pro_at | |||
| lda em_locals | |||
| sta cg_code+1,y | |||
| lda em_locals+1 | |||
| sta cg_code+3,y | |||
| @done: clc | |||
| rts | |||
| ; A = result width (0, 1 or 2). Emit the matching exit. | |||
| em_return: | |||
| sta em_ret_w | |||
| lda em_on | |||
| beq @done | |||
| jmp cg_rts | |||
| lda em_pro_on | |||
| beq @plain | |||
| lda em_ret_w | |||
| cmp #$01 | |||
| beq @byte | |||
| cmp #$02 | |||
| beq @word | |||
| jmp fl_ret | |||
| @byte: jmp fl_ret_byte | |||
| @word: jmp fl_ret_word | |||
| @plain: jmp cg_rts | |||
| @done: clc | |||
| rts | |||
| @@ -596,7 +673,8 @@ em_method_begin: | |||
| txa | |||
| jsr fl_label | |||
| bcs @bad | |||
| jmp mb_self_store | |||
| jsr mb_self_store | |||
| jmp em_prologue_start | |||
| @bad: lda #EM_ERR_LABEL | |||
| sta em_bad | |||
| clc | |||
| @@ -625,24 +703,15 @@ em_method_label: | |||
| sec | |||
| rts | |||
| ; A = member row. Emit a zero-argument call through self. | |||
| ; A = member row. Record the call; the arguments are parsed next and | |||
| ; em_call_finish emits the self load, JSR and discard once they are pushed. | |||
| em_call: | |||
| sta em_nid | |||
| jsr em_method_label | |||
| bcs @bad | |||
| stx em_lab | |||
| ldy em_nid | |||
| lda #C_MEM_PCOUNT | |||
| jsr tb_get | |||
| bne @call_bad | |||
| lda em_recv_self | |||
| beq @call_bad | |||
| jsr mb_self_load | |||
| bcs @fail | |||
| lda em_lab | |||
| jsr fl_jsr | |||
| bcs @fail | |||
| ldy em_nid | |||
| sta em_call_row | |||
| lda #$00 | |||
| sta em_call_res | |||
| lda #$01 | |||
| sta em_call_pending | |||
| ldy em_call_row | |||
| lda #C_MEM_TBASE | |||
| jsr tb_get | |||
| cmp #TY_NONE | |||
| @@ -655,20 +724,174 @@ em_call: | |||
| beq @byte | |||
| cmp #TY_CHAR | |||
| beq @byte | |||
| cmp #TY_INTEGER | |||
| beq @word | |||
| cmp #TY_WORD | |||
| beq @word | |||
| lda #EM_ERR_CALL | |||
| sta em_bad | |||
| rts | |||
| @void: rts | |||
| @byte: lda #$01 | |||
| sta em_call_res | |||
| rts | |||
| @word: lda #$02 | |||
| sta em_call_res | |||
| rts | |||
| ; The just-parsed argument is in A (one byte) or A/X (two). Stage it on the | |||
| ; hardware stack; em_args_done pops the stages in reverse so arg0 lands at | |||
| ; FP+2 in the callee frame. | |||
| em_arg_push: | |||
| lda em_on | |||
| beq @done | |||
| lda em_size | |||
| beq @bad | |||
| cmp #$02 | |||
| bcs @two | |||
| ldy em_arg_n | |||
| cpy #EM_ARG_MAX | |||
| bcs @full | |||
| sta em_arg_w,y | |||
| inc em_arg_n | |||
| lda #$48 ; PHA | |||
| jmp cg_put | |||
| @two: cmp #$02 | |||
| bne @bad | |||
| ldy em_arg_n | |||
| cpy #EM_ARG_MAX | |||
| bcs @full | |||
| sta em_arg_w,y | |||
| inc em_arg_n | |||
| lda #$48 ; PHA low | |||
| jsr cg_put | |||
| lda #$8A ; TXA | |||
| jsr cg_put | |||
| lda #$48 ; PHA high | |||
| jmp cg_put | |||
| @bad: lda #EM_ERR_ARG | |||
| sta em_bad | |||
| clc | |||
| rts | |||
| @void: lda #$00 | |||
| sta em_size | |||
| @full: lda #EM_ERR_CALL | |||
| sta em_bad | |||
| @done: clc | |||
| rts | |||
| ; Pop the staged arguments in reverse and push each through frame_push_byte | |||
| ; or frame_push_word, so the first argument ends at FP+2. | |||
| em_args_done: | |||
| lda em_on | |||
| beq @done | |||
| lda em_arg_n | |||
| beq @done | |||
| lda fl_push | |||
| ora fl_push+1 | |||
| beq @state | |||
| lda em_arg_n | |||
| sta em_arg_i | |||
| @loop: dec em_arg_i | |||
| ldx em_arg_i | |||
| lda em_arg_w,x | |||
| cmp #$02 | |||
| beq @word | |||
| lda #$68 ; PLA | |||
| jsr cg_put | |||
| lda fl_push | |||
| ldx fl_push+1 | |||
| jsr cg_jsr_abs | |||
| jmp @next | |||
| @word: lda #$68 ; PLA -> high | |||
| jsr cg_put | |||
| lda #$AA ; TAX | |||
| jsr cg_put | |||
| lda #$68 ; PLA -> low | |||
| jsr cg_put | |||
| lda fl_push_word | |||
| ldx fl_push_word+1 | |||
| jsr cg_jsr_abs | |||
| @next: lda em_arg_i | |||
| bne @loop | |||
| lda #$00 | |||
| sta em_arg_n | |||
| @done: clc | |||
| rts | |||
| @state: lda #EM_ERR_STATE | |||
| sta em_bad | |||
| clc | |||
| rts | |||
| @byte: lda #$01 | |||
| ; Emit the recorded call: self load, JSR, argument discard, result preserved | |||
| ; across the discard. Sets em_size to the result width. | |||
| em_call_finish: | |||
| lda em_on | |||
| bne :+ | |||
| jmp @done | |||
| : lda em_call_pending | |||
| bne :+ | |||
| jmp @done | |||
| : lda #$00 | |||
| sta em_call_pending | |||
| jsr em_arg_total | |||
| sta em_call_bytes | |||
| jsr mb_self_load | |||
| bcc :+ | |||
| jmp @fail | |||
| : | |||
| lda em_call_row | |||
| jsr em_method_label | |||
| bcs @bad | |||
| stx em_lab | |||
| lda em_lab | |||
| jsr fl_jsr | |||
| bcs @fail | |||
| lda em_call_res | |||
| beq @discard | |||
| cmp #$01 | |||
| beq @save_byte | |||
| lda #$48 ; PHA low | |||
| jsr cg_put | |||
| lda #$8A ; TXA | |||
| jsr cg_put | |||
| lda #$48 ; PHA high | |||
| jsr cg_put | |||
| jmp @discard | |||
| @save_byte: | |||
| lda #$48 ; PHA | |||
| jsr cg_put | |||
| @discard: | |||
| lda em_call_bytes | |||
| beq @restore | |||
| lda fl_discard | |||
| ora fl_discard+1 | |||
| beq @state | |||
| lda em_call_bytes | |||
| jsr cg_lda_imm | |||
| lda #$00 | |||
| jsr cg_ldx_imm | |||
| lda fl_discard | |||
| ldx fl_discard+1 | |||
| jsr cg_jsr_abs | |||
| @restore: | |||
| lda em_call_res | |||
| beq @ok | |||
| cmp #$01 | |||
| beq @rest_byte | |||
| lda #$68 ; PLA -> high | |||
| jsr cg_put | |||
| lda #$AA ; TAX | |||
| jsr cg_put | |||
| lda #$68 ; PLA -> low | |||
| jsr cg_put | |||
| jmp @ok | |||
| @rest_byte: | |||
| lda #$68 ; PLA | |||
| jsr cg_put | |||
| @ok: lda em_call_res | |||
| sta em_size | |||
| clc | |||
| rts | |||
| @call_bad: | |||
| lda #EM_ERR_CALL | |||
| @state: lda #EM_ERR_STATE | |||
| sta em_bad | |||
| clc | |||
| rts | |||
| @@ -676,8 +899,52 @@ em_call: | |||
| sta em_bad | |||
| clc | |||
| rts | |||
| @done: clc | |||
| rts | |||
| @fail: jmp em_fail | |||
| ; Total bytes of the recorded call's declared parameters. A width the ABI | |||
| ; does not know sets EM_ERR_CALL and leaves the total as it stood. | |||
| em_arg_total: | |||
| lda #$00 | |||
| sta em_arg_bytes | |||
| ldy em_call_row | |||
| lda #C_MEM_PCOUNT | |||
| jsr tb_get | |||
| beq @done | |||
| sta em_arg_i | |||
| ldy em_call_row | |||
| lda #C_MEM_PFIRST | |||
| jsr tb_get | |||
| sta em_nid | |||
| @loop: ldy em_nid | |||
| lda #C_PAR_TBASE | |||
| jsr tb_get | |||
| cmp #TY_BOOLEAN | |||
| beq @one | |||
| cmp #TY_BYTE | |||
| beq @one | |||
| cmp #TY_CHAR | |||
| beq @one | |||
| cmp #TY_INTEGER | |||
| beq @two | |||
| cmp #TY_WORD | |||
| beq @two | |||
| lda #EM_ERR_CALL | |||
| sta em_bad | |||
| jmp @done | |||
| @one: lda #$01 | |||
| jmp @add | |||
| @two: lda #$02 | |||
| @add: clc | |||
| adc em_arg_bytes | |||
| sta em_arg_bytes | |||
| inc em_nid | |||
| dec em_arg_i | |||
| bne @loop | |||
| @done: lda em_arg_bytes | |||
| rts | |||
| ; The next member is applied to self (a field or a call). | |||
| em_member_receiver: | |||
| lda #$00 | |||
| @@ -1165,3 +1432,17 @@ em_count: .res 1 | |||
| em_n_routines: .res 1 | |||
| em_routine_start: .res 1 | |||
| em_routine_sizes: .res EM_MAX_ROUTINES | |||
| em_pro_on: .res 1 | |||
| em_pro_at: .res 1 | |||
| em_ret_w: .res 1 | |||
| em_arg_n: .res 1 | |||
| em_arg_i: .res 1 | |||
| em_arg_b: .res 1 | |||
| em_arg_bytes: .res 1 | |||
| em_arg_w: .res EM_ARG_MAX | |||
| em_call_row: .res 1 | |||
| em_call_res: .res 1 | |||
| em_call_bytes: .res 1 | |||
| em_call_pending: .res 1 | |||
| em_frame_on: .res 1 | |||
| em_frame_want: .res 1 | |||
| @@ -68,7 +68,7 @@ | |||
| .export fl_branch_true, fl_branch_false | |||
| .export fl_call, fl_call_byte, fl_call_word | |||
| .export fl_prologue, fl_ret, fl_ret_byte, fl_ret_word | |||
| .export fl_err, fl_enter, fl_leave, fl_discard | |||
| .export fl_err, fl_enter, fl_leave, fl_discard, fl_push, fl_push_word | |||
| .segment "CODE" | |||
| @@ -762,4 +762,7 @@ fl_fix: .res FL_FIX_MAX * FL_FIX_SIZE | |||
| fl_enter: .res 2 | |||
| fl_leave: .res 2 | |||
| fl_discard: .res 2 | |||
| fl_push: .res 2 | |||
| fl_push_word: .res 2 | |||
| fl_code_base: .res 2 | |||
| @@ -65,9 +65,11 @@ | |||
| .import em_open_block, em_cond_false, em_else, em_close_block | |||
| .import em_for_var, em_for_save_end, em_for_save_step, em_for_default_step, em_for_setup | |||
| .import em_return, em_method_begin, em_program_begin | |||
| .import em_arg_push, em_args_done, em_call_finish, em_frame_want | |||
| .import sz_capture, sz_verify | |||
| .export parse_file, parse_file_base, parse_file_sized, tb_get, tb_set, mem_count, par_count | |||
| .export parse_file, parse_file_base, parse_file_sized, parse_file_framed | |||
| .export tb_get, tb_set, mem_count, par_count | |||
| .export gen_text, gen_text_len, gen_print_count, gen_bad | |||
| .export ex_trace_on, ex_min_sp | |||
| .exportzp ex_tp | |||
| @@ -96,6 +98,15 @@ ex_tp: .res 2 ; test trace pointer (ex_trace_on) | |||
| .segment "CODE" | |||
| parse_file: | |||
| lda #$00 | |||
| sta em_frame_want | |||
| jmp parse_plain | |||
| ; Same as parse_file, but generated bodies get a frame_enter prologue. | |||
| parse_file_framed: | |||
| lda #$01 | |||
| sta em_frame_want | |||
| parse_plain: | |||
| lda #$00 | |||
| sta em_base_set | |||
| sta em_count | |||
| @@ -107,6 +118,7 @@ parse_file: | |||
| parse_file_base: | |||
| jsr em_set_base | |||
| lda #$00 | |||
| sta em_frame_want | |||
| sta em_count | |||
| sta diag_suppress | |||
| jmp parse_start | |||
| @@ -114,6 +126,8 @@ parse_file_base: | |||
| ; Count pass, snapshot, then an emitting pass. The caller installs the final | |||
| ; code base first. Diagnostics are reported only by the count pass. | |||
| parse_file_sized: | |||
| lda #$00 | |||
| sta em_frame_want | |||
| lda #$01 | |||
| sta em_count | |||
| lda #$00 | |||
| @@ -1325,8 +1339,23 @@ parse_statement: | |||
| beq @bare | |||
| cmp #TOK_EOF | |||
| beq @bare | |||
| lda pass | |||
| cmp #$02 | |||
| bne @ret_parse | |||
| lda em_on | |||
| beq @ret_parse | |||
| jsr em_stmt_begin | |||
| @ret_parse: | |||
| jsr parse_full | |||
| lda pass | |||
| cmp #$02 | |||
| bne @ret_typed | |||
| lda em_on | |||
| beq @ret_typed | |||
| jsr em_stmt_end | |||
| @ret_typed: | |||
| jsr check_return | |||
| jsr ret_width | |||
| jsr em_return | |||
| jmp end_stmt | |||
| @bare: lda ret_kind | |||
| @@ -1335,7 +1364,8 @@ parse_statement: | |||
| lda #E_SEM_MISSING_RETURN | |||
| ldx stmt_col | |||
| jsr err2_col | |||
| : jsr em_return | |||
| : jsr ret_width | |||
| jsr em_return | |||
| jmp end_stmt | |||
| @else: ldx depth ; only once, directly inside an if | |||
| lda block_stack-1,x | |||
| @@ -1623,6 +1653,32 @@ check_return: | |||
| jmp err2_col | |||
| @ok: rts | |||
| ; A = the current method's result width (0, 1 or 2) for em_return. A program | |||
| ; and a void method report 0, so their return leaves the frame without a value. | |||
| ret_width: | |||
| lda cur_mem | |||
| cmp #$FF | |||
| beq @zero | |||
| ldy cur_mem | |||
| lda #C_MEM_TBASE | |||
| jsr tb_get | |||
| cmp #TY_BOOLEAN | |||
| beq @one | |||
| cmp #TY_BYTE | |||
| beq @one | |||
| cmp #TY_CHAR | |||
| beq @one | |||
| cmp #TY_INTEGER | |||
| beq @two | |||
| cmp #TY_WORD | |||
| beq @two | |||
| @zero: lda #$00 | |||
| rts | |||
| @one: lda #$01 | |||
| rts | |||
| @two: lda #$02 | |||
| rts | |||
| ; The for variable must be a byte, word, or integer. A bad one is reported | |||
| ; as "FOR NOT ALLOWED ON <type>" and its type becomes unknown. | |||
| check_for_var: | |||
| @@ -1985,6 +2041,13 @@ parse_postfix: | |||
| jsr em_call | |||
| : | |||
| jsr parse_args | |||
| lda pass | |||
| cmp #$02 | |||
| bne :+ | |||
| lda em_on | |||
| beq :+ | |||
| jsr em_call_finish | |||
| : | |||
| ldx ex_depth | |||
| jsr load_sc | |||
| lda #EX_CALL | |||
| @@ -2132,8 +2195,23 @@ parse_args: | |||
| @arg: lda tok_col | |||
| ldx ex_depth | |||
| sta ex_acol,x | |||
| lda pass | |||
| cmp #$02 | |||
| bne @arg_parse | |||
| lda em_on | |||
| beq @arg_parse | |||
| jsr em_stmt_begin | |||
| @arg_parse: | |||
| jsr parse_full | |||
| jsr check_arg | |||
| lda pass | |||
| cmp #$02 | |||
| bne :+ | |||
| lda em_on | |||
| beq :+ | |||
| jsr em_stmt_end | |||
| jsr em_arg_push | |||
| : | |||
| lda tok_kind | |||
| cmp #TOK_COMMA | |||
| bne :+ | |||
| @@ -2145,12 +2223,19 @@ parse_args: | |||
| jmp syn_error | |||
| @close: ldx ex_depth ; too few arguments: reported at `)` | |||
| lda ex_cchk,x | |||
| beq @done | |||
| beq @args_done | |||
| lda ex_carg,x | |||
| cmp ex_cpc,x | |||
| bcs @done | |||
| bcs @args_done | |||
| lda tok_col | |||
| jsr count_error | |||
| @args_done: | |||
| lda pass | |||
| cmp #$02 | |||
| bne @done | |||
| lda em_on | |||
| beq @done | |||
| jsr em_args_done | |||
| @done: jmp next | |||
| ; Argument ex_carg (sc) against its parameter. The first argument beyond | |||
| @@ -0,0 +1,179 @@ | |||
| ; E04-S08: parse args.n8 and run Calc.twice, which pushes one byte argument, | |||
| ; enters a sized frame in Calc.scale, and returns a byte. | |||
| ; | |||
| ; The first emitted body is Calc.twice at cg_code+0. The fixture supplies the | |||
| ; frame runtime entry points, so the prologue emitted at the start of twice | |||
| ; calls frame_enter(0), and scale reads its parameter at FP+2. twice returns | |||
| ; self.scale(3); scale returns n + 3, so the expected result is 6. | |||
| ; | |||
| ; Mailbox data: +0 diagnostics, +1 em_bad, +2 result, +3 cg_len, +4 cg_err, | |||
| ; +5 fl_err. FAIL stage: 1 load, 2 diagnostics, 3 emitter, 4 result. | |||
| .setcpu "6502" | |||
| .include "../../src/common/c128.inc" | |||
| .include "../../src/common/mailbox.inc" | |||
| .include "../../src/common/formats.inc" | |||
| .import mmu_init, mmu_bank0, mmu_shutdown | |||
| .import src_load, src_dos_code, src_kernal_err | |||
| .import names_init | |||
| .import diag_init, diag_finish, diag_screen | |||
| .import parse_file_framed | |||
| .import em_on, em_bad | |||
| .import cg_code, cg_len, cg_err | |||
| .import fl_err, fl_enter, fl_leave, fl_discard, fl_push, fl_push_word | |||
| .import frame_init, frame_enter, frame_leave, frame_discard | |||
| .import frame_push_byte, frame_push_word | |||
| .macro ON_ZERO target | |||
| beq :+ | |||
| jmp target | |||
| : | |||
| .endmacro | |||
| .segment "LOADADDR" | |||
| .word $1C01 | |||
| .segment "EXEHDR" | |||
| .word basic_end | |||
| .word 10 | |||
| .byte $9E | |||
| .byte "7181" | |||
| .byte $00 | |||
| basic_end: | |||
| .word $0000 | |||
| .segment "MAILBOX" | |||
| .res MB_SIZE | |||
| .segment "STARTUP" | |||
| .export test_entry | |||
| test_entry: | |||
| php | |||
| sei | |||
| ldx #MB_SIZE - 1 | |||
| lda #$00 | |||
| @clr: sta MB_BASE,x | |||
| dex | |||
| bpl @clr | |||
| lda #MB_MAGIC0_VALUE | |||
| sta MB_MAGIC0 | |||
| lda #MB_MAGIC1_VALUE | |||
| sta MB_MAGIC1 | |||
| lda #MB_PROD_COMPILER | |||
| sta MB_PRODUCER | |||
| lda #MB_ST_RUNNING | |||
| sta MB_STATUS | |||
| jsr mmu_init | |||
| jsr mmu_bank0 | |||
| lda #<frame_enter | |||
| sta fl_enter | |||
| lda #>frame_enter | |||
| sta fl_enter+1 | |||
| lda #<frame_leave | |||
| sta fl_leave | |||
| lda #>frame_leave | |||
| sta fl_leave+1 | |||
| lda #<frame_discard | |||
| sta fl_discard | |||
| lda #>frame_discard | |||
| sta fl_discard+1 | |||
| lda #<frame_push_byte | |||
| sta fl_push | |||
| lda #>frame_push_byte | |||
| sta fl_push+1 | |||
| lda #<frame_push_word | |||
| sta fl_push_word | |||
| lda #>frame_push_word | |||
| sta fl_push_word+1 | |||
| lda #<name_src | |||
| ldx #>name_src | |||
| ldy #name_src_len | |||
| jsr src_load | |||
| cmp #$00 | |||
| ON_ZERO @fail_load | |||
| jsr names_init | |||
| lda #<name_src | |||
| ldx #>name_src | |||
| ldy #name_src_len | |||
| jsr diag_init | |||
| lda #$00 | |||
| sta diag_screen | |||
| lda #$01 | |||
| sta em_on | |||
| jsr parse_file_framed | |||
| jsr diag_finish | |||
| sta MB_DATA+0 | |||
| lda em_bad | |||
| sta MB_DATA+1 | |||
| lda cg_len | |||
| sta MB_DATA+3 | |||
| lda cg_err | |||
| sta MB_DATA+4 | |||
| lda fl_err | |||
| sta MB_DATA+5 | |||
| lda MB_DATA+0 | |||
| ON_ZERO @fail_diag | |||
| lda em_bad | |||
| ON_ZERO @fail_emit | |||
| lda cg_err | |||
| ON_ZERO @fail_cg | |||
| lda fl_err | |||
| ON_ZERO @fail_cg | |||
| jmp @run | |||
| @fail_cg: | |||
| lda #3 | |||
| jmp @fail | |||
| @run: jsr frame_init | |||
| ldx #3 ; descriptor + zeroed byte field | |||
| lda #$00 | |||
| @obj: sta object,x | |||
| dex | |||
| bpl @obj | |||
| lda #<object | |||
| ldx #>object | |||
| jsr cg_code | |||
| sta MB_DATA+2 | |||
| cmp #$06 | |||
| beq @pass | |||
| lda #4 | |||
| jmp @fail | |||
| @fail_load: | |||
| sta MB_DATA+4 | |||
| lda src_dos_code | |||
| sta MB_DATA+5 | |||
| lda src_kernal_err | |||
| sta MB_DATA+6 | |||
| lda #1 | |||
| jmp @fail | |||
| @fail_diag: | |||
| lda #2 | |||
| jmp @fail | |||
| @fail_emit: | |||
| lda #3 | |||
| @fail: sta MB_CODE | |||
| lda #$00 | |||
| sta MB_CODE+1 | |||
| lda #MB_ST_FAIL | |||
| sta MB_STATUS | |||
| jmp @done | |||
| @pass: lda #MB_ST_PASS | |||
| sta MB_STATUS | |||
| @done: jsr mmu_shutdown | |||
| plp | |||
| rts | |||
| .segment "RODATA" | |||
| name_src: .byte "ARGS.N8" | |||
| name_src_len = * - name_src | |||
| .segment "BSS" | |||
| object: .res 4 | |||
| @@ -0,0 +1,13 @@ | |||
| // E04-S08 calling-convention source: one byte argument and a byte result. | |||
| class Calc | |||
| public method twice() as byte | |||
| return self.scale(3) | |||
| end method | |||
| public method scale(n as byte) as byte | |||
| return n + 3 | |||
| end method | |||
| end class | |||
| program args | |||
| end program | |||
| @@ -16,6 +16,7 @@ | |||
| @{ Name = "print"; Script = "scripts\verify-print-test.ps1"; BuildDir = "print-test"; Timeout = 300 } | |||
| @{ Name = "statements"; Script = "scripts\verify-statements-test.ps1"; BuildDir = "statements-test"; Timeout = 300 } | |||
| @{ Name = "calls"; Script = "scripts\verify-calls-test.ps1"; BuildDir = "calls-test"; Timeout = 300 } | |||
| @{ Name = "args"; Script = "scripts\verify-args-test.ps1"; BuildDir = "args-test"; Timeout = 300; Success = "verified byte argument push" } | |||
| @{ Name = "class"; Script = "scripts\verify-class-test.ps1"; BuildDir = "class-test"; Timeout = 300 } | |||
| @{ Name = "member"; Script = "scripts\verify-member-test.ps1"; BuildDir = "member-test"; Timeout = 300 } | |||
| @{ Name = "heap"; Script = "scripts\verify-heap-test.ps1"; BuildDir = "heap-test"; Timeout = 300 } | |||
Powered by TurnKey Linux.