diff --git a/newLang/docs/architecture.md b/newLang/docs/architecture.md index 564e453..7456b50 100644 --- a/newLang/docs/architecture.md +++ b/newLang/docs/architecture.md @@ -204,6 +204,13 @@ result must end in `return` (an `if` only when both branches do), reported at `end` as E150. Numeric literals are typed by context and folded (E084/E086); arrays are never whole values (E088). +E03-S05 computes each class's instance size and field offsets after the +declaration pass, once every forward type reference has a kind. Fields keep +declaration order after the two-byte descriptor pointer with no padding; ABI +sizes are 1 for boolean/byte/char, 2 for integer/word/class reference, 4 for +an interface reference, and element size times length for an array. A class +whose instance would exceed 65535 bytes reports E096 at its declaration line. + ### Pass 1 — declarations and layout - tokenize the complete source; diff --git a/newLang/docs/diagnostics.md b/newLang/docs/diagnostics.md index ab274b4..538ac9b 100644 --- a/newLang/docs/diagnostics.md +++ b/newLang/docs/diagnostics.md @@ -85,6 +85,7 @@ After 20 errors the next one is replaced by E221 and compilation stops. | E093 | `TYP_NOT_CLASS` | % IS NOT A CLASS | | E094 | `TYP_ARRAY_SIGNATURE` | ARRAYS CANNOT BE PARAMETERS OR RESULTS | | E095 | `TYP_ARRAY_LENGTH` | ARRAY LENGTH MUST NOT BE ZERO | +| E096 | `TYP_INSTANCE_TOO_LARGE` | CLASS INSTANCE TOO LARGE | ## Access (E120-E129) diff --git a/newLang/docs/memory-map.md b/newLang/docs/memory-map.md index d079071..a848405 100644 --- a/newLang/docs/memory-map.md +++ b/newLang/docs/memory-map.md @@ -51,7 +51,7 @@ COMMON, DISKBUF, private ZP, SCRATCH, and MAILBOX are visible from bank 1. | Owner | Bytes | Contents | |---|---|---| | `names.s` | 5,164 | 64 hash-chain heads + 255 name records of 20 bytes (D120) | -| `parser.s` | 4,608 | 18 columns of 256 bytes (`src/common/parser.inc`): type table by name ID (kind, declaration line, member range; E03-S01/E03-S02), 255 member rows (owner, name, flags, type, parameter range) and 255 parameter-type rows (E03-S02) | +| `parser.s` | 6,656 | 26 columns of 256 bytes (`src/common/parser.inc`): type table by name ID (kind, declaration line, member and implements ranges, instance size; E03-S01, E03-S05), 255 member rows (owner, name, flags, type, parameter range, field offset) and 255 parameter-type rows (E03-S02, E03-S05) | BSS is not zeroed at load: every table must be cleared by its owner before use (`names_init`, `parser.s` `tt_clear`). The member and parameter rows are diff --git a/newLang/planning/claims/E03-S05.md b/newLang/planning/claims/E03-S05.md new file mode 100644 index 0000000..47d60b9 --- /dev/null +++ b/newLang/planning/claims/E03-S05.md @@ -0,0 +1,107 @@ +--- +story: E03-S05 +owner: e03_layout +status: done +started: 2026-11-09 +depends-on: [E03-S02, E03-S04] +--- + +# E03-S05 Claim + +## Intended change + +Compute every class's instance size and every field's byte offset after pass 1, +when forward type references have a kind at last, and report E096 when an +instance would exceed 65535 bytes. Instances begin with the two-byte class +descriptor pointer and keep fields in declaration order with no padding. +Add the size and offset columns to the bank-1 type and member tables, and make +the parser harness emit a deterministic layout record so a fixture can list +each class's size and its fields' offsets in declaration order. + +## File area + +- `src/common/parser.inc`, `src/compiler/parser.s` +- `src/common/diagcat.inc`, `docs/diagnostics.md` (E096) +- `tests/parser/parser-test.s`, `scripts/build-parser-test.ps1`, + `scripts/verify-parser-test.ps1` +- `tests/semantic/layout.n8`, `layout.expect`, `too_big.n8`, `too_big.expect` +- `docs/architecture.md`, `docs/memory-map.md` +- `planning/claims/E03-S05.md` +- generated files under `build/` + +## Acceptance evidence + +- [x] Field offsets begin after the class-descriptor pointer and are + deterministic: `layout.n8` declares one field of every ABI size and two + arrays; `layout.expect` records `box size 35` with offsets 2, 3, 4, 5, 7, 9, + 15, 17, 21, 23, and 31 in declaration order, and `empty size 2`. The + verifier compares the whole `$FA` layout list; all 39 parser fixtures pass. +- [x] Instance size overflow/capacity is diagnosed: `too_big.n8` + (`word[40000]` = 80,000 bytes) is rejected with E096 at 1:1, matching + `too_big.expect`; the size columns saturate at `$FFFF` rather than wrapping. +- [x] Field default privacy and method default publicity match the + specification: `layout.n8` uses bare fields and one bare `public method`; + the independent source oracle in `verify-parser-test.ps1` derives every + member's access (fields private, methods public) and compares it against the + parser's 13 member rows for the fixture. The same check covers all accepted + fixtures. +- [x] MAP fixture lists sizes and offsets in declaration order: + `layout.n8`/`layout.expect` is that listing. The harness's `$FA` record is + the deterministic layout listing the future `NAME.MAP` writer will consume; + the MAP writer itself belongs to E05-S02 (`output.s`), so no `NAME.MAP` file + exists to compare yet. This is recorded under remaining risks. + +## Coordination notes + +- No other claim is active. No new decision: the sizes are the approved + architecture ABI (1 for boolean/byte/char, 2 for integer/word/class + reference, 4 for interface reference, element size times length for arrays) + and object layout is the approved two-byte descriptor followed by fields. + D124-D127 from E03-S04 remain proposed. +- The layout pass runs between pass 1 and pass 2, so it only uses recorded + table rows and never depends on source order or pass-2 typing. + +## Work log + +- `parser.inc`: added `C_TYPE_SIZE_LO/HI` (22/23) and + `C_MEM_OFFSET_LO/HI` (24/25); `TABLE_COLUMNS` is now 26. `docs/memory-map.md` + records the parser tables as 6,656 bytes. +- `parser.s`: `parse_file` calls `layout_classes` after pass 1. Helpers + `field_size_mem`, `field_size`, and `elem_size` compute a member's size from + its recorded type, and `store_field_offset` writes the current offset into + the member row. A class starts at 2; methods are skipped; overflow sets the + size to `$FFFF`, records the failure, and reports E096 once at the class's + declaration line and column 1. The pass loops over name IDs and member rows, + so classes and fields are laid out in declaration order. +- `parser-test.s`: `dump_layout` emits `$FA`, then per class its name, size + lo/hi, field count, and each field's name and offset lo/hi. `count_fields` + counts non-method member rows owned by the class. `FIXTURE_COUNT` is 39. +- `verify-parser-test.ps1`: decodes `$FA` until `$FD`/`$FB` and compares the + layout lines against `layout.expect`; the member loop now also stops at + `$FA`, because `dump_layout` always emits its marker before `$FD`. +- `diagcat.inc`: appended `TYP_INSTANCE_TOO_LARGE, 96`; the catalog now has 68 + entries and `docs/diagnostics.md` was regenerated. +- First build exposed four 6502 branch-range errors in `layout_classes` and + three in `dump_layout`; they are now short branches to nearby `jmp` + trampolines. The verifier edit had also joined `$p += 5` and `while` on one + line; fixed. + +## Completion + +- Tests run: `scripts/build-parser-test.ps1`, + `scripts/verify-parser-test.ps1 -Port 6530`, + `scripts/build-lexer-test.ps1`, `scripts/verify-lexer-test.ps1`, + `scripts/build-diag-test.ps1 -UpdateDocs`, + `scripts/verify-diag-test.ps1`, `scripts/demo-write-check.ps1`. +- Results: all 39 parser fixtures pass (lowest expression SP `$A7`); + `layout.n8` matches 13 layout lines and `too_big.n8` reports E096 at 1:1. + The lexer matches 10 fixtures / 6,733 dump bytes; the 68-entry diagnostic + catalog and its screen/ERR expectations match with docs in sync; the demo + saves `good.n8` and `bad.n8` byte-for-byte, `good.n8` reports no errors, and + `bad.n8` reports E151, E152, E120, and E061. `vim/work.d81` was not touched. +- Files changed: as listed under File area. +- Remaining risks: the `NAME.MAP` text writer is E05-S02, so the declaration + order and layout listing are verified through the harness record rather than + a real `.map` file. E096 reports the instance's saturated `$FFFF` size in the + table; consumers must treat that as "too large". Any future padding or + alignment rule would change `layout.expect` and the offsets. diff --git a/newLang/scripts/build-parser-test.ps1 b/newLang/scripts/build-parser-test.ps1 index ed8aecf..fa38a27 100644 --- a/newLang/scripts/build-parser-test.ps1 +++ b/newLang/scripts/build-parser-test.ps1 @@ -51,6 +51,8 @@ $script:ParserFixtures = [ordered]@{ "ops.n8" = @("$t\ops.n8", "exact", "$t\ops.expect") "uses.n8" = @("$t\uses.n8", "exact", "$t\uses.expect") "calls.n8" = @("$t\calls.n8", "exact", "$t\calls.expect") + "layout.n8" = @("$t\layout.n8", "layout", "$t\layout.expect") + "toobig.n8" = @("$t\too_big.n8", "rejected", "$t\too_big.expect") } $link = Invoke-Nova128Link -Name "parser-test" -BuildDir $out ` diff --git a/newLang/scripts/verify-parser-test.ps1 b/newLang/scripts/verify-parser-test.ps1 index 79f30cc..da2a43c 100644 --- a/newLang/scripts/verify-parser-test.ps1 +++ b/newLang/scripts/verify-parser-test.ps1 @@ -53,9 +53,9 @@ $records = @(); $script:p = 0 while ($dump[$p] -ne 0xFE) { if ($dump[$p] -ne 0xFF) { throw "dump out of sync at $p" } $r = [pscustomobject]@{ Index = $dump[$p + 1]; Load = $dump[$p + 2]; Count = $dump[$p + 3] - MinSp = $dump[$p + 4]; Types = @(); Members = @(); Trace = $null } + MinSp = $dump[$p + 4]; Types = @(); Members = @(); Layout = @(); Trace = $null } $p += 5 - while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFC) { + while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFC -and $dump[$p] -ne 0xFB -and $dump[$p] -ne 0xFA) { $len = $dump[$p + 3] $spell = ConvertFrom-Spelling $dump[($p + 4)..($p + 3 + $len)] $r.Types += ("{0} {1} {2}" -f @("", "interface", "class", "program")[$dump[$p]], $spell, ($dump[$p + 1] + 256 * $dump[$p + 2])) @@ -63,7 +63,7 @@ while ($dump[$p] -ne 0xFE) { } if ($dump[$p] -eq 0xFC) { $p++ - while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFB) { + while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFB -and $dump[$p] -ne 0xFA) { $owner = Read-DumpName $name = Read-DumpName $flags = $dump[$p]; $p++ @@ -74,6 +74,20 @@ while ($dump[$p] -ne 0xFE) { $(if ($flags -band 1) { "method" } else { "field" }), $(if ($flags -band 2) { "private" } else { "public" }), $type, ($params -join ",")) } + if ($dump[$p] -eq 0xFA) { + $p++ + while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFB) { + $owner = Read-DumpName + $size = $dump[$p] + 256 * $dump[$p + 1]; $p += 2 + $count = $dump[$p]; $p++ + $r.Layout += ("{0} size {1}" -f $owner, $size) + for ($k = 0; $k -lt $count; $k++) { + $fname = Read-DumpName + $off = $dump[$p] + 256 * $dump[$p + 1]; $p += 2 + $r.Layout += ("{0}.{1} offset {2}" -f $owner, $fname, $off) + } + } + } if ($dump[$p] -eq 0xFB) { $n = $dump[$p + 1] + 256 * $dump[$p + 2] $r.Trace = if ($n) { [byte[]]$dump[($p + 3)..($p + 2 + $n)] } else { [byte[]]@() } @@ -181,7 +195,7 @@ foreach ($name in $ParserFixtures.Keys) { $problems = @() if ($r.Load -ne 0) { $problems += "src_load returned $($r.Load)" } switch ($group) { - "accepted" { + { $_ -eq "accepted" -or $_ -eq "layout" } { if ($r.Count -ne 0) { $problems += "$($r.Count) diagnostic(s): $($errLines -join ' | ')" } if ($null -ne $errLines) { $problems += "an ERR file exists" } $want = @() @@ -231,7 +245,7 @@ foreach ($name in $ParserFixtures.Keys) { $detail = "{0} diagnostics" -f $got.Count } } - if ($group -eq "accepted" -or $memberChecked -contains $name) { + if ($group -in @("accepted", "layout") -or $memberChecked -contains $name) { $wantMembers = Get-SourceMembers $src if (($r.Members -join ';') -ne ($wantMembers -join ';')) { $problems += "members [$($r.Members -join '; ')] expected [$($wantMembers -join '; ')]" @@ -249,6 +263,13 @@ foreach ($name in $ParserFixtures.Keys) { $detail += ", {0} traced statements" -f $got.Count } } + if ($group -eq "layout") { + $want = @(Get-Content -LiteralPath $expect | Where-Object { $_ -and -not $_.StartsWith("//") }) + if (($r.Layout -join ';') -ne ($want -join ';')) { + $problems += "layout [$($r.Layout -join '; ')] expected [$($want -join '; ')]" + } + $detail += ", {0} layout lines" -f $r.Layout.Count + } if ($r.MinSp -ne 0xFF -and $r.MinSp -lt $minSp) { $minSp = $r.MinSp } $status = if ($problems) { "FAIL" } else { "ok" } Write-Host (" {0,-13} {1,-9} {2} {3}" -f $name, $group, $status, $detail) diff --git a/newLang/src/common/diagcat.inc b/newLang/src/common/diagcat.inc index 59c1bb3..1bbc50f 100644 --- a/newLang/src/common/diagcat.inc +++ b/newLang/src/common/diagcat.inc @@ -74,6 +74,7 @@ DIAGNOSTIC TYP_NOT_CLASS, 93, "% IS NOT A CLASS" DIAGNOSTIC TYP_ARRAY_SIGNATURE, 94, "ARRAYS CANNOT BE PARAMETERS OR RESULTS" DIAGNOSTIC TYP_ARRAY_LENGTH, 95, "ARRAY LENGTH MUST NOT BE ZERO" + DIAGNOSTIC TYP_INSTANCE_TOO_LARGE, 96, "CLASS INSTANCE TOO LARGE" ; ----------------------------------------------------------------- access DIAGNOSTIC ACC_PRIVATE_MEMBER, 120, "% IS PRIVATE" diff --git a/newLang/src/common/parser.inc b/newLang/src/common/parser.inc index c5fbdce..acf23bf 100644 --- a/newLang/src/common/parser.inc +++ b/newLang/src/common/parser.inc @@ -75,7 +75,11 @@ C_PAR_TNAME = 18 C_PAR_TLEN_LO = 19 C_PAR_TLEN_HI = 20 C_IMPL_IFACE = 21 ; implemented interface name ID -TABLE_COLUMNS = 22 +C_TYPE_SIZE_LO = 22 ; class instance size (descriptor + fields) +C_TYPE_SIZE_HI = 23 +C_MEM_OFFSET_LO = 24 ; field byte offset +C_MEM_OFFSET_HI = 25 +TABLE_COLUMNS = 26 C_TYPE_LAST = C_TYPE_INIT ; type columns 0..this are cleared per run .endif diff --git a/newLang/src/compiler/parser.s b/newLang/src/compiler/parser.s index 59cb0bb..91796d1 100644 --- a/newLang/src/compiler/parser.s +++ b/newLang/src/compiler/parser.s @@ -1,5 +1,5 @@ ; parser.s - declarations, members, scopes, statements, expressions, and -; type checking (E03-S01..E03-S04). +; type checking (E03-S01..E03-S05). ; ; parse_file runs two passes over the loaded source (call after src_load, ; diag_init, and names_init): @@ -8,8 +8,8 @@ ; the bank-1 type table and each field and method signature in the ; member and parameter tables; parses every statement; reports ; syntax, ordering, duplicate, init/destroy shape, and -; local-placement errors; records each class's implements list -; and init row. +; local-placement errors; records each class's implements list, +; init row, instance size, and field offsets (E03-S05). ; pass 2 replays the source, parsing everything again, and reports type ; references that do not name a declared interface or class ; (forward references are therefore legal), name, member, and @@ -45,6 +45,7 @@ .import tok_kind, tok_line, tok_col, tok_len, tok_value, tok_text, tok_text_len, tok_err .import src_line .import name_intern, name_find, name_declare +.import names_count .import diag_report, diag_line, diag_col, diag_arg1, diag_arg1_len .import mmu_peek1, mmu_poke1 .importzp mmu_ptr @@ -97,6 +98,7 @@ parse_file: lda #$01 sta pass jsr parse_pass + jsr layout_classes lda #$02 sta pass jsr parse_pass @@ -544,6 +546,219 @@ no_array_sig: jmp err1_col @ok: rts +; ------------------------------------------------------------- layout +; Pass 1, after all declarations: instance sizes and field offsets. A class +; starts with its two-byte descriptor pointer; fields follow in declaration +; order with no padding. ABI sizes: boolean/byte/char 1, integer/word/class +; reference 2, interface reference 4, array = element size * length. E096 is +; reported at the class line when the total exceeds 65535. +layout_classes: + lda #$01 + sta lk_id +@class: lda lk_id + cmp names_count + bcc :+ + jmp @done +: ldy lk_id + lda #C_TYPE_KIND + jsr tb_get + cmp #TYPE_CLASS + beq :+ + jmp @next +: lda #$02 + sta cls_size + lda #$00 + sta cls_size+1 + sta cls_bad + sta lk_row +@row: lda lk_row + cmp mem_count + bcs @class_done + ldy lk_row + lda #C_MEM_OWNER + jsr tb_get + cmp lk_id + bne @rnext + ldy lk_row + lda #C_MEM_FLAGS + jsr tb_get + and #MF_METHOD + bne @rnext + lda cls_bad + bne @saturated + jsr field_size_mem + bcs @overflow + jsr store_field_offset + clc + lda cls_size + adc fsize + sta cls_size + lda cls_size+1 + adc fsize+1 + sta cls_size+1 + bcc @rnext +@overflow: + jsr store_field_offset + lda #$01 + sta cls_bad + lda #$FF + sta cls_size + sta cls_size+1 + jmp @rnext +@saturated: + jsr store_field_offset +@rnext: inc lk_row + jmp @row +@class_done: + ldy lk_id + ldx cls_size + lda #C_TYPE_SIZE_LO + jsr tb_set + ldx cls_size+1 + lda #C_TYPE_SIZE_HI + jsr tb_set + lda cls_bad + bne :+ + jmp @next +: ldy lk_id + lda #C_TYPE_LINE_LO + jsr tb_get + sta diag_line + ldy lk_id + lda #C_TYPE_LINE_HI + jsr tb_get + sta diag_line+1 + lda #$01 + sta diag_col + lda #E_TYP_INSTANCE_TOO_LARGE + jsr diag_report + bcs :+ + jmp @next +: jmp stop_parse +@next: inc lk_id + beq @done + jmp @class +@done: rts + +; fsize = the type of member row lk_row; C=1 when it exceeds 65535. +field_size_mem: + ldy lk_row + lda #C_MEM_TBASE + jsr tb_get + sta ty_base + ldy lk_row + lda #C_MEM_TNAME + jsr tb_get + sta ty_name + ldy lk_row + lda #C_MEM_TLEN_LO + jsr tb_get + sta ty_len + ldy lk_row + lda #C_MEM_TLEN_HI + jsr tb_get + sta ty_len+1 + jsr field_size + rts + +; member row lk_row's offset = cls_size. +store_field_offset: + ldy lk_row + lda #C_MEM_OFFSET_LO + ldx cls_size + jsr tb_set + lda #C_MEM_OFFSET_HI + ldx cls_size+1 + jsr tb_set + rts + +; fsize = size of the type in ty_*; C=1 when the array is too large. +field_size: + lda ty_len + ora ty_len+1 + beq @scalar + jsr elem_size + beq @zero + cmp #$01 + beq @one + cmp #$02 + beq @two + lda ty_len + sta fsize + lda ty_len+1 + sta fsize+1 + asl fsize + rol fsize+1 + bcs @over + asl fsize + rol fsize+1 + bcs @over + clc + rts +@one: lda ty_len + sta fsize + lda ty_len+1 + sta fsize+1 + clc + rts +@two: lda ty_len + sta fsize + lda ty_len+1 + sta fsize+1 + asl fsize + rol fsize+1 + bcs @over + clc + rts +@zero: lda #$00 + sta fsize + sta fsize+1 + clc + rts +@scalar: + jsr elem_size + sta fsize + lda #$00 + sta fsize+1 + clc + rts +@over: lda #$FF + sta fsize + sta fsize+1 + sec + rts + +; A = bytes in one element of ty_*: 1, 2, 4, or 0 for an unknown type. +elem_size: + lda ty_base + 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 + cmp #TY_REF + bne @none + ldy ty_name + lda #C_TYPE_KIND + jsr tb_get + cmp #TYPE_INTERFACE + beq @four + lda #$02 + rts +@one: lda #$01 + rts +@two: lda #$02 + rts +@four: lda #$04 + rts +@none: lda #$00 + rts + ; Pass 1: a class's init records its member row (+1) for `new` checks. note_init: lda pass @@ -2508,3 +2723,9 @@ ret_kind: .res 1 ; RET_* ret_row: .res 1 ; member row of the method (RET_VALUE) body_nm: .res 1 ; method or program name ID (E151) end_col: .res 1 ; column of `end` (E150) +; class layout (E03-S05) +cls_size: .res 2 ; instance size being accumulated +cls_bad: .res 1 ; E096 reported for this class +fsize: .res 2 ; one field's size +lk_id: .res 1 ; layout: class name ID +lk_row: .res 1 ; layout: member row diff --git a/newLang/tests/parser/parser-test.s b/newLang/tests/parser/parser-test.s index 676d04b..8dce1d7 100644 --- a/newLang/tests/parser/parser-test.s +++ b/newLang/tests/parser/parser-test.s @@ -141,6 +141,7 @@ test_entry: lda #$FC jsr emit jsr dump_members + jsr dump_layout lda fx_index cmp #TRACE_INDEX bne @advance @@ -288,6 +289,97 @@ dump_members: jmp @next @done: rts +; Emit $FA, then each class: name, instance size lo/hi, field count, and +; every field's name and offset lo/hi in declaration order. +dump_layout: + lda #$FA + jsr emit + lda #$01 + sta id +@next: lda id + cmp names_count + bcc :+ + jmp @done +: ldy id + lda #C_TYPE_KIND + jsr tb_get + cmp #TYPE_CLASS + bne @not_class + lda id + jsr emit_name + ldy id + lda #C_TYPE_SIZE_LO + jsr tb_get + jsr emit + ldy id + lda #C_TYPE_SIZE_HI + jsr tb_get + jsr emit + lda id + jsr count_fields + jsr emit + lda #$00 + sta lk_row +@field_loop: + lda lk_row + cmp mem_count + bcs @fields_done + ldy lk_row + lda #C_MEM_OWNER + jsr tb_get + cmp id + bne @fnext + ldy lk_row + lda #C_MEM_FLAGS + jsr tb_get + and #MF_METHOD + bne @fnext + ldy lk_row + lda #C_MEM_NAME + jsr tb_get + jsr emit_name + ldy lk_row + lda #C_MEM_OFFSET_LO + jsr tb_get + jsr emit + ldy lk_row + lda #C_MEM_OFFSET_HI + jsr tb_get + jsr emit +@fnext: inc lk_row + jmp @field_loop +@fields_done: +@not_class: + inc id + beq @done + jmp @next +@done: rts + +; A = class name ID; A = number of field rows it owns. +count_fields: + sta lk_owner + lda #$00 + sta lk_n + sta lk_row +@loop: lda lk_row + cmp mem_count + bcs @done + ldy lk_row + lda #C_MEM_OWNER + jsr tb_get + cmp lk_owner + bne @next + ldy lk_row + lda #C_MEM_FLAGS + jsr tb_get + and #MF_METHOD + bne @next + inc lk_n +@next: inc lk_row + jmp @loop +@done: lda lk_n + rts + ; Emit $FB, the trace length, and the trace bytes. dump_trace: lda #$FB @@ -425,7 +517,9 @@ fixtures: FIXTURE "OPS.N8" FIXTURE "USES.N8" FIXTURE "CALLS.N8" -FIXTURE_COUNT = 37 + FIXTURE "LAYOUT.N8" + FIXTURE "TOOBIG.N8" +FIXTURE_COUNT = 39 TRACE_INDEX = 28 ; PREC.N8 messages: @@ -448,6 +542,9 @@ prow: .res 1 pleft: .res 1 col: .res 1 trow: .res 1 +lk_owner: .res 1 +lk_row: .res 1 +lk_n: .res 1 trace_len: .res 2 trace_buf: .res 1024 dump: .res DUMP_SIZE diff --git a/newLang/tests/semantic/layout.expect b/newLang/tests/semantic/layout.expect new file mode 100644 index 0000000..58aef5c --- /dev/null +++ b/newLang/tests/semantic/layout.expect @@ -0,0 +1,17 @@ +// E03-S05: instance size and field offsets. A class starts with its +// two-byte descriptor pointer; fields follow in declaration order with no +// padding. boolean/byte/char are 1 byte, integer/word/class reference 2, +// interface reference 4, and an array is element size times length. +box size 35 +box.b offset 2 +box.ok offset 3 +box.c offset 4 +box.w offset 5 +box.i offset 7 +box.nums offset 9 +box.flags offset 15 +box.s offset 17 +box.next offset 21 +box.many offset 23 +box.kids offset 31 +empty size 2 diff --git a/newLang/tests/semantic/layout.n8 b/newLang/tests/semantic/layout.n8 new file mode 100644 index 0000000..b0a0640 --- /dev/null +++ b/newLang/tests/semantic/layout.n8 @@ -0,0 +1,27 @@ +interface Shape + method area() as word +end interface + +class Box implements Shape + byte b + boolean ok + char c + word w + integer i + word[3] nums + byte[2] flags + Shape s + Box next + Shape[2] many + Box[2] kids + + public method area() as word + return 0 + end method +end class + +class Empty +end class + +program Main +end program diff --git a/newLang/tests/semantic/too_big.expect b/newLang/tests/semantic/too_big.expect new file mode 100644 index 0000000..bffa84e --- /dev/null +++ b/newLang/tests/semantic/too_big.expect @@ -0,0 +1,4 @@ +diagnostic: TYP_INSTANCE_TOO_LARGE +line: 1 +column: 1 +reason: the field array makes the class instance exceed 65535 bytes diff --git a/newLang/tests/semantic/too_big.n8 b/newLang/tests/semantic/too_big.n8 new file mode 100644 index 0000000..a49c070 --- /dev/null +++ b/newLang/tests/semantic/too_big.n8 @@ -0,0 +1,6 @@ +class Huge + word[40000] data +end class + +program Main +end program