Просмотр исходного кода

Add interface conformance and stable slot assignment (E03-S06).

Number interface methods in source order and check each class against every
implemented interface, reporting missing, private, mismatched, conflicting,
and non-interface implementations at the class declaration.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
main
Daniel Covington 5 дней назад
Родитель
Сommit
b790ef2683
17 измененных файлов: 800 добавлений и 14 удалений
  1. +12
    -0
      newLang/docs/architecture.md
  2. +2
    -0
      newLang/docs/diagnostics.md
  3. +1
    -1
      newLang/docs/memory-map.md
  4. +122
    -0
      newLang/planning/claims/E03-S06.md
  5. +3
    -0
      newLang/scripts/build-parser-test.ps1
  6. +1
    -0
      newLang/scripts/demo-write-check.ps1
  7. +24
    -5
      newLang/scripts/verify-parser-test.ps1
  8. +2
    -0
      newLang/src/common/diagcat.inc
  9. +3
    -2
      newLang/src/common/parser.inc
  10. +452
    -0
      newLang/src/compiler/interfaces.s
  11. +10
    -4
      newLang/src/compiler/parser.s
  12. +54
    -1
      newLang/tests/parser/parser-test.s
  13. +3
    -1
      newLang/tests/parser/unknown.expect
  14. +10
    -0
      newLang/tests/semantic/iface_bad.expect
  15. +58
    -0
      newLang/tests/semantic/iface_bad.n8
  16. +9
    -0
      newLang/tests/semantic/interfaces.expect
  17. +34
    -0
      newLang/tests/semantic/interfaces.n8

+ 12
- 0
newLang/docs/architecture.md Просмотреть файл

@@ -211,6 +211,18 @@ 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.

E03-S06 adds `interfaces.s`. After the declaration pass it numbers every
interface method in source order (`C_MEM_SLOT`), giving later dispatch tables
a stable slot order, and checks each class against every interface in its
implements list. A satisfying method is public and has the same parameter
count, parameter types, and return type; one method may satisfy identical
requirements from several interfaces. Failures report at the class declaration
line, column 1: E130 for a missing or private method, E131 for a signature
mismatch, E132 when a same-named requirement of another implemented interface
conflicts with the class method's signature, and E133 when an implements entry
names a class or program rather than an interface. An implements entry that
names no declared type is left to pass 2's unknown-name diagnostic.

### Pass 1 — declarations and layout

- tokenize the complete source;


+ 2
- 0
newLang/docs/diagnostics.md Просмотреть файл

@@ -99,6 +99,8 @@ After 20 errors the next one is replaced by E221 and compilation stops.
|---|---|---|
| E130 | `IFC_METHOD_MISSING` | % IS NOT IMPLEMENTED |
| E131 | `IFC_SIGNATURE_MISMATCH` | % DIFFERS FROM INTERFACE |
| E132 | `IFC_SIGNATURE_CONFLICT` | % HAS CONFLICTING SIGNATURES |
| E133 | `IFC_NOT_INTERFACE` | % IS NOT AN INTERFACE |

## Methods and returns (E150-E169)



+ 1
- 1
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` | 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) |
| `parser.s` | 6,912 | 27 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, interface slot; E03-S02, E03-S05, E03-S06) and 255 parameter-type rows |

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


+ 122
- 0
newLang/planning/claims/E03-S06.md Просмотреть файл

@@ -0,0 +1,122 @@
---
story: E03-S06
owner: e03_iface
status: done
started: 2026-11-09
depends-on: [E03-S02, E03-S04]
---

# E03-S06 Claim

## Intended change

Add `src/compiler/interfaces.s`, which runs once after the declaration pass.
It numbers each interface method in source order in a new `C_MEM_SLOT` member
column, then checks every class against every interface in its implements
list. A satisfying method is public and has the same parameter count,
parameter types, and return type; one method may satisfy identical
requirements from several interfaces. Missing and private methods report
E130, signature mismatches E131, a class method that matches a same-named
requirement of another implemented interface E132, and an implements entry
that names a class or program E133. All are reported at the class declaration
line, column 1. The parser harness emits an `$F9` slot record so a fixture can
verify source order.

## File area

- `src/compiler/interfaces.s` (new), `src/compiler/parser.s`
- `src/common/parser.inc`, `src/common/diagcat.inc`, `docs/diagnostics.md`
- `tests/parser/parser-test.s`, `scripts/build-parser-test.ps1`,
`scripts/verify-parser-test.ps1`, `scripts/demo-write-check.ps1`
- `tests/semantic/interfaces.n8`, `interfaces.expect`, `iface_bad.n8`,
`iface_bad.expect`, `tests/parser/unknown.expect`
- `docs/architecture.md`, `docs/memory-map.md`
- `planning/claims/E03-S06.md`
- generated files under `build/`

## Acceptance evidence

- [x] Interface method slots follow interface source order:
`interfaces.n8` declares Shape (`area`, `scale`, `name`), Named (`label`,
`show`), and Display (`show`, declared after the class); the harness's
`$F9` record and `interfaces.expect` list them as shape 0/1/2, named 0/1,
display 0. `assign_slots` writes that order into `C_MEM_SLOT`.
- [x] A public exact-signature method satisfies a requirement: Box's five
public methods match all five interface signatures exactly, and
`interfaces.n8` is accepted with no ERR file in the parser run.
- [x] One method may satisfy identical requirements from multiple interfaces:
Box's single public `show()` satisfies both `Named.show()` and
`Display.show()`; no duplicate or conflict diagnostic is produced.
- [x] Same-name incompatible requirements are rejected: `iface_bad.n8` has
Left (`show()`) and Right (`show(x as byte)`) implemented by one class whose
`show()` matches Left; Right reports E132 at 49:1,
`SHOW HAS CONFLICTING SIGNATURES`.
- [x] Missing, private, parameter-mismatched, and return-mismatched methods
each have fixture coverage: `iface_bad.n8` expects E130 at 28:1 (`AREA`),
E130 at 31:1 (`LABEL`, private), E131 at 37:1 (`SCALE`, word vs byte), and
E131 at 43:1 (`OK`, word vs boolean). E133 at 54:1 covers a class used as an
interface. All six exact diagnostics match their messages.

## Coordination notes

- No other claim is active. E03-S05 is complete (`42a26c9`).
- Conformance legitimately adds E130 to `tests/parser/unknown.n8` (Worker
implements Printable without `print`); its exact expectation gained that
first pass-1 line and still passes with six diagnostics.
- E132 and E133 extend the approved E130-E149 interface category; they do not
change source syntax or the interface ABI. Slot order is spec 5.2's source
order, and C_MEM_SLOT is parser metadata for later dispatch/MAP work.

## Work log

- `interfaces.s`: `assign_slots` numbers interface methods by declaration;
`check_interfaces` walks classes and implements lists in source order and
reports at the class line. `find_method` ignores fields; a private method is
treated as not implemented. `same_sig` compares result type, parameter count,
and all parameter types. `conflicting` decides E132 by looking for a
same-named requirement in another implemented interface whose signature the
class method does satisfy. `iface_err` spells the argument from `name_out`
and reports through `diag_report`, returning carry when the error limit
stops compilation.
- `parser.s` exports `tb_set`, calls `assign_slots` then `check_interfaces`
after `layout_classes`, and returns at once if the diagnostic limit is hit.
- `parser.inc`: `C_MEM_SLOT = 26`, `TABLE_COLUMNS = 27`; the parser tables are
now 6,912 bytes in `docs/memory-map.md`.
- `parser-test.s`: `dump_ifaces` emits `$F9`, each interface name, member
count, and each slot/name pair. Fixtures 40-41 added; `FIXTURE_COUNT = 41`.
- `verify-parser-test.ps1`: decodes `$F9` before `$FA`, stops the type and
member loops at it, treats the new `iface` group like an accepted fixture
for diagnostics/member checks, and compares slot lines to
`interfaces.expect`.
- `diagcat.inc`: E132 `% HAS CONFLICTING SIGNATURES`, E133
`% IS NOT AN INTERFACE`; catalog is 70 entries and docs are regenerated.
- First build failed on seven long `bcs @stop`/`beq @inext` branches in the
6502 code; each became a short branch plus `jmp` trampoline.

## Completion

- Tests run: `scripts/build-parser-test.ps1`,
`scripts/verify-parser-test.ps1 -Port 6530`,
`scripts/build-diag-test.ps1 -UpdateDocs`,
`scripts/verify-diag-test.ps1 -Port 6530`,
`scripts/verify-lexer-test.ps1 -Port 6530`,
`scripts/demo-write-check.ps1` (good.n8 and bad.n8),
`scripts/demo-write-check.ps1 -Programs bad.n8`.
- Results: all 41 parser fixtures pass (lowest expression SP `$A7`);
`interfaces.n8` reports 6 interface slots and 11 members that match the
source oracle, and `ifacebad.n8` matches all six exact diagnostics. The
diagnostics catalog has 70 entries and its screen/ERR expectations and docs
are in sync. The lexer still matches 10 fixtures / 6,733 bytes. The demo
rebuilt and linked `interfaces.s`; good.n8 completed its Vim save and C128
check in the full run, and the bad.n8 rerun saved 258 PETSCII bytes
identically and reported E151, E152, E120, and E061.
- Files changed: as listed under File area.
- Remaining risks: conformance positions are class-level (line, column 1)
because member rows do not store a source column; the message names the
method. E132 is anchored on a class method that matches another requirement;
a class with no method at all still rejects each interface with E130. An
implements entry naming no declared type is left to pass 2's unknown-name
diagnostic, so E133 only covers declared classes/programs. The VICE verifier
defaults on this machine (6532/6534/6535) can produce an empty monitor reply;
all runs used `-Port 6530`. Interface dispatch tables and their MAP output
remain E04/E05 work; C_MEM_SLOT is the stable input for them.

+ 3
- 0
newLang/scripts/build-parser-test.ps1 Просмотреть файл

@@ -53,6 +53,8 @@ $script:ParserFixtures = [ordered]@{
"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")
"interfaces.n8" = @("$t\interfaces.n8", "iface", "$t\interfaces.expect")
"ifacebad.n8" = @("$t\iface_bad.n8", "exact", "$t\iface_bad.expect")
}

$link = Invoke-Nova128Link -Name "parser-test" -BuildDir $out `
@@ -64,6 +66,7 @@ $link = Invoke-Nova128Link -Name "parser-test" -BuildDir $out `
(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 "tests\parser\parser-test.s"))
if ((Get-Nova128Label $link.Labels "test_entry") -ne 0x1C0D) { throw "test_entry is not at `$1C0D" }


+ 1
- 0
newLang/scripts/demo-write-check.ps1 Просмотреть файл

@@ -39,6 +39,7 @@ $link = Invoke-Nova128Link -Name "n8check" -BuildDir $out `
(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 "demo\n8check.s"))



+ 24
- 5
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 = @(); Layout = @(); Trace = $null }
MinSp = $dump[$p + 4]; Types = @(); Members = @(); Ifaces = @(); Layout = @(); Trace = $null }
$p += 5
while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFC -and $dump[$p] -ne 0xFB -and $dump[$p] -ne 0xFA) {
while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFC -and $dump[$p] -ne 0xFB -and $dump[$p] -ne 0xFA -and $dump[$p] -ne 0xF9) {
$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 -and $dump[$p] -ne 0xFA) {
while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFB -and $dump[$p] -ne 0xFA -and $dump[$p] -ne 0xF9) {
$owner = Read-DumpName
$name = Read-DumpName
$flags = $dump[$p]; $p++
@@ -74,6 +74,18 @@ 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 0xF9) {
$p++
while ($dump[$p] -ne 0xFA -and $dump[$p] -ne 0xFB -and $dump[$p] -ne 0xFD) {
$owner = Read-DumpName
$count = $dump[$p]; $p++
for ($k = 0; $k -lt $count; $k++) {
$slot = $dump[$p]; $p++
$name = Read-DumpName
$r.Ifaces += ("{0} slot {1} {2}" -f $owner, $slot, $name)
}
}
}
if ($dump[$p] -eq 0xFA) {
$p++
while ($dump[$p] -ne 0xFD -and $dump[$p] -ne 0xFB) {
@@ -195,7 +207,7 @@ foreach ($name in $ParserFixtures.Keys) {
$problems = @()
if ($r.Load -ne 0) { $problems += "src_load returned $($r.Load)" }
switch ($group) {
{ $_ -eq "accepted" -or $_ -eq "layout" } {
{ $_ -eq "accepted" -or $_ -eq "layout" -or $_ -eq "iface" } {
if ($r.Count -ne 0) { $problems += "$($r.Count) diagnostic(s): $($errLines -join ' | ')" }
if ($null -ne $errLines) { $problems += "an ERR file exists" }
$want = @()
@@ -245,7 +257,7 @@ foreach ($name in $ParserFixtures.Keys) {
$detail = "{0} diagnostics" -f $got.Count
}
}
if ($group -in @("accepted", "layout") -or $memberChecked -contains $name) {
if ($group -in @("accepted", "layout", "iface") -or $memberChecked -contains $name) {
$wantMembers = Get-SourceMembers $src
if (($r.Members -join ';') -ne ($wantMembers -join ';')) {
$problems += "members [$($r.Members -join '; ')] expected [$($wantMembers -join '; ')]"
@@ -270,6 +282,13 @@ foreach ($name in $ParserFixtures.Keys) {
}
$detail += ", {0} layout lines" -f $r.Layout.Count
}
if ($group -eq "iface") {
$want = @(Get-Content -LiteralPath $expect | Where-Object { $_ -and -not $_.StartsWith("//") })
if (($r.Ifaces -join ';') -ne ($want -join ';')) {
$problems += "slots [$($r.Ifaces -join '; ')] expected [$($want -join '; ')]"
}
$detail += ", {0} interface slots" -f $r.Ifaces.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)


+ 2
- 0
newLang/src/common/diagcat.inc Просмотреть файл

@@ -82,6 +82,8 @@
; ------------------------------------------------------------- interfaces
DIAGNOSTIC IFC_METHOD_MISSING, 130, "% IS NOT IMPLEMENTED"
DIAGNOSTIC IFC_SIGNATURE_MISMATCH, 131, "% DIFFERS FROM INTERFACE"
DIAGNOSTIC IFC_SIGNATURE_CONFLICT, 132, "% HAS CONFLICTING SIGNATURES"
DIAGNOSTIC IFC_NOT_INTERFACE, 133, "% IS NOT AN INTERFACE"

; ---------------------------------------------------- methods and returns
DIAGNOSTIC SEM_MISSING_RETURN, 150, "MISSING RETURN VALUE"


+ 3
- 2
newLang/src/common/parser.inc Просмотреть файл

@@ -1,4 +1,4 @@
; parser.inc - parser tables and limits (E03-S01..E03-S04).
; parser.inc - parser tables and limits (E03-S01..E03-S06).

.ifndef PARSER_INC
PARSER_INC = 1
@@ -79,7 +79,8 @@ 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_MEM_SLOT = 26 ; interface method slot (source order)
TABLE_COLUMNS = 27
C_TYPE_LAST = C_TYPE_INIT ; type columns 0..this are cleared per run

.endif

+ 452
- 0
newLang/src/compiler/interfaces.s Просмотреть файл

@@ -0,0 +1,452 @@
; interfaces.s - interface slot order and class conformance (E03-S06).
;
; Runs once after pass 1, when every interface, class, member, parameter, and
; implements row is recorded:
; assign_slots numbers each interface method in declaration order and
; stores it in C_MEM_SLOT, so later method tables and the MAP
; writer can use a stable slot without re-reading the source;
; check_interfaces
; verifies each class against every interface it implements.
; A satisfying method is public and has the same parameter
; count, parameter types, and return type. One method may
; satisfy identical requirements from several interfaces.
;
; Diagnostics are reported at the class declaration line, column 1:
; E130 no public method with a required name (missing, field, or private)
; E131 a public method with that name differs in its signature
; E132 the differing method matches the same-named requirement of another
; implemented interface, so the interfaces conflict
; E133 an implements entry names a class or program, not an interface
; An implements entry that names no declared type is left to pass 2, which
; already reports the unknown name at the source position.
;
; Everything is read through tb_get/tb_set, so this module runs in the normal
; bank-0 compiler state.

.setcpu "6502"
.include "../common/errors.inc"
.include "../common/parser.inc"

.import tb_get, tb_set, names_count
.import diag_report, diag_line, diag_col, diag_arg1, diag_arg1_len
.import name_get, name_out, name_out_len

.export assign_slots, check_interfaces

.segment "CODE"

; ------------------------------------------------------------- slot order
; Every interface method gets its declaration index: 0, 1, ... in source
; order. Interfaces cannot declare fields, so member rows are signatures.
assign_slots:
lda #$01
sta as_id
@next: lda as_id
cmp names_count
bcc :+
rts
: ldy as_id
lda #C_TYPE_KIND
jsr tb_get
cmp #TYPE_INTERFACE
beq :+
jmp @skip
: ldy as_id
lda #C_TYPE_MFIRST
jsr tb_get
sta as_row
ldy as_id
lda #C_TYPE_MCOUNT
jsr tb_get
sta as_n
lda #$00
sta as_slot
@slot: lda as_n
beq @skip
ldy as_row
ldx as_slot
lda #C_MEM_SLOT
jsr tb_set
inc as_row
inc as_slot
dec as_n
bne @slot
@skip: inc as_id
bne @next
rts

; ----------------------------------------------------------- conformance
; For each class in declaration order, walk its implements list in source
; order and each interface's signatures in slot order.
check_interfaces:
lda #$01
sta cf_class
@class: lda cf_class
cmp names_count
bcc :+
jmp @done
: ldy cf_class
lda #C_TYPE_KIND
jsr tb_get
cmp #TYPE_CLASS
beq :+
jmp @cnext
: ldy cf_class
lda #C_TYPE_ICOUNT
jsr tb_get
bne :+
jmp @cnext ; no implements list
: sta cf_count
ldy cf_class
lda #C_TYPE_IFIRST
jsr tb_get
sta cf_row
lda #$00
sta cf_i
@impl: lda cf_i
cmp cf_count
bcc :+
jmp @cnext
: ldy cf_row
lda #C_IMPL_IFACE
jsr tb_get
sta cf_iface
ldy cf_iface
lda #C_TYPE_KIND
jsr tb_get
cmp #TYPE_INTERFACE
beq @conform
cmp #$00
bne :+ ; unknown: pass 2 reports it
jmp @inext
:
ldx cf_iface
lda #E_IFC_NOT_INTERFACE
jsr iface_err
bcc :+
jmp @stop
:
jmp @inext
@conform:
ldy cf_iface
lda #C_TYPE_MFIRST
jsr tb_get
sta cf_req
ldy cf_iface
lda #C_TYPE_MCOUNT
jsr tb_get
sta cf_n
@req: lda cf_n
bne :+
jmp @inext
: ldy cf_req
lda #C_MEM_NAME
jsr tb_get
sta cf_name
lda cf_class
ldx cf_name
jsr find_method
bcc @missing
sty cf_method
lda #C_MEM_FLAGS
jsr tb_get
and #MF_PRIVATE
beq @sig
jmp @missing ; private methods do not implement
@sig: lda cf_req
ldx cf_method
jsr same_sig
bcs @satisfied
lda cf_method
ldx cf_name
jsr conflicting
bcs @conflict
ldx cf_name
lda #E_IFC_SIGNATURE_MISMATCH
jsr iface_err
bcc :+
jmp @stop
:
jmp @satisfied
@conflict:
ldx cf_name
lda #E_IFC_SIGNATURE_CONFLICT
jsr iface_err
bcc :+
jmp @stop
:
jmp @satisfied
@missing:
ldx cf_name
lda #E_IFC_METHOD_MISSING
jsr iface_err
bcc :+
jmp @stop
:
@satisfied:
inc cf_req
dec cf_n
jmp @req
@inext: inc cf_row
inc cf_i
jmp @impl
@cnext: inc cf_class
beq @done
jmp @class
@stop: sec
rts
@done: clc
rts

; A = class ID, X = method name ID. C=1 and Y=row when the class declares a
; method with that name; C=0 otherwise. A field with the name does not count.
find_method:
sta fmc_class
stx fmc_name
ldy fmc_class
lda #C_TYPE_MFIRST
jsr tb_get
sta fmc_row
ldy fmc_class
lda #C_TYPE_MCOUNT
jsr tb_get
sta fmc_n
@row: lda fmc_n
beq @no
ldy fmc_row
lda #C_MEM_FLAGS
jsr tb_get
and #MF_METHOD
beq @next
ldy fmc_row
lda #C_MEM_NAME
jsr tb_get
cmp fmc_name
beq @yes
@next: inc fmc_row
dec fmc_n
bne @row
@no: clc
rts
@yes: ldy fmc_row
sec
rts

; C=1 when the class method A matches a same-named requirement (X) of an
; implemented interface other than the one being checked. That means the
; interfaces themselves disagree, not that the class method is wrong.
conflicting:
sta cn_method
stx cn_name
ldy cf_class
lda #C_TYPE_IFIRST
jsr tb_get
sta cn_row
ldy cf_class
lda #C_TYPE_ICOUNT
jsr tb_get
sta cn_n
@iface: lda cn_n
beq @no
ldy cn_row
lda #C_IMPL_IFACE
jsr tb_get
sta cn_iface
cmp cf_iface
beq @next_iface
ldy cn_iface
lda #C_TYPE_KIND
jsr tb_get
cmp #TYPE_INTERFACE
bne @next_iface
ldy cn_iface
lda #C_TYPE_MFIRST
jsr tb_get
sta cn_req
ldy cn_iface
lda #C_TYPE_MCOUNT
jsr tb_get
sta cn_req_n
@req: lda cn_req_n
beq @next_iface
ldy cn_req
lda #C_MEM_NAME
jsr tb_get
cmp cn_name
bne @next_req
lda cn_method
ldx cn_req
jsr same_sig
bcs @yes
@next_req:
inc cn_req
dec cn_req_n
bne @req
@next_iface:
inc cn_row
dec cn_n
bne @iface
@no: clc
rts
@yes: sec
rts

; C=1 when member rows A and X have equal signatures: result type, parameter
; count, and each parameter type.
same_sig:
sta sg_a
stx sg_b
ldy sg_a
lda #C_MEM_PCOUNT
jsr tb_get
sta sg_n
ldy sg_b
lda #C_MEM_PCOUNT
jsr tb_get
cmp sg_n
bne @no
lda sg_a
ldx sg_b
jsr same_result
bcc @no
ldy sg_a
lda #C_MEM_PFIRST
jsr tb_get
sta sg_pa
ldy sg_b
lda #C_MEM_PFIRST
jsr tb_get
sta sg_pb
lda #$00
sta sg_i
@param: lda sg_i
cmp sg_n
beq @yes
lda sg_pa
clc
adc sg_i
sta sg_ra
lda sg_pb
clc
adc sg_i
sta sg_rb
lda sg_ra
ldx sg_rb
jsr same_param
bcc @no
inc sg_i
bne @param
@yes: sec
rts
@no: clc
rts

same_result:
ldy #C_MEM_TBASE
jmp same_cells

same_param:
ldy #C_PAR_TBASE
jmp same_cells

; C=1 when four consecutive type columns starting at Y are equal for rows A
; and X (base, name, length lo, length hi).
same_cells:
sta sg_a
stx sg_b
sty sg_col
lda #$00
sta sg_ci
@col: ldy sg_a
lda sg_col
clc
adc sg_ci
jsr tb_get
sta sg_v
ldy sg_b
lda sg_col
clc
adc sg_ci
jsr tb_get
cmp sg_v
bne @no
inc sg_ci
lda sg_ci
cmp #$04
bne @col
sec
rts
@no: clc
rts

; Report A at class cf_class's declaration line, column 1, with name X as
; argument 1. C=1 when the diagnostic limit stopped compilation.
iface_err:
sta ie_code
stx ie_name
ldy cf_class
lda #C_TYPE_LINE_LO
jsr tb_get
sta diag_line
ldy cf_class
lda #C_TYPE_LINE_HI
jsr tb_get
sta diag_line+1
lda #$01
sta diag_col
lda ie_name
jsr name_get
lda #<name_out
sta diag_arg1
lda #>name_out
sta diag_arg1+1
lda name_out_len
sta diag_arg1_len
lda ie_code
jsr diag_report
bcc @ok
sec
rts
@ok: clc
rts

.segment "BSS"
; slot assignment
as_id: .res 1
as_row: .res 1
as_n: .res 1
as_slot: .res 1
; conformance
cf_class: .res 1
cf_iface: .res 1
cf_count: .res 1
cf_row: .res 1
cf_i: .res 1
cf_req: .res 1
cf_n: .res 1
cf_name: .res 1
cf_method: .res 1
fmc_class: .res 1
fmc_name: .res 1
fmc_row: .res 1
fmc_n: .res 1
cn_method: .res 1
cn_name: .res 1
cn_row: .res 1
cn_n: .res 1
cn_iface: .res 1
cn_req: .res 1
cn_req_n: .res 1
sg_a: .res 1
sg_b: .res 1
sg_n: .res 1
sg_i: .res 1
sg_pa: .res 1
sg_pb: .res 1
sg_col: .res 1
sg_ci: .res 1
sg_v: .res 1
sg_ra: .res 1
sg_rb: .res 1
ie_code: .res 1
ie_name: .res 1

+ 10
- 4
newLang/src/compiler/parser.s Просмотреть файл

@@ -1,5 +1,5 @@
; parser.s - declarations, members, scopes, statements, expressions, and
; type checking (E03-S01..E03-S05).
; type checking (E03-S01..E03-S06).
;
; parse_file runs two passes over the loaded source (call after src_load,
; diag_init, and names_init):
@@ -9,7 +9,8 @@
; member and parameter tables; parses every statement; reports
; syntax, ordering, duplicate, init/destroy shape, and
; local-placement errors; records each class's implements list,
; init row, instance size, and field offsets (E03-S05).
; init row, instance size, and field offsets (E03-S05); assigns
; interface slots and checks class conformance (E03-S06).
; 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
@@ -54,8 +55,9 @@
.import tt_base, tt_name, tt_len
.import ty_assign, ty_binary, ty_unary
.import ty_arg_sc1, ty_arg_sc2, ty_arg_name1, ty_arg_num2
.import assign_slots, check_interfaces

.export parse_file, tb_get, mem_count, par_count
.export parse_file, tb_get, tb_set, mem_count, par_count
.export ex_trace_on, ex_min_sp
.exportzp ex_tp
.export type_kind, type_line_lo, type_line_hi
@@ -99,7 +101,11 @@ parse_file:
sta pass
jsr parse_pass
jsr layout_classes
lda #$02
jsr assign_slots
jsr check_interfaces
bcc :+
rts
: lda #$02
sta pass
jsr parse_pass
rts


+ 54
- 1
newLang/tests/parser/parser-test.s Просмотреть файл

@@ -11,6 +11,10 @@
; per member row: owner name, member name, flags, type, parameter count,
; then each parameter's type. A name is a length and its spelling (length
; 0 = none); a type is base, name, length lo, length hi.
; $F9
; per interface: name, slot count (member count), then each slot's number
; and method name in source order (E03-S06)
; $FA, per class: name, instance size, field count, fields and offsets
; for the TRACE_INDEX fixture only: $FB, length lo/hi, the expression
; trace (parser.inc TR_*)
; $FD
@@ -141,6 +145,7 @@ test_entry:
lda #$FC
jsr emit
jsr dump_members
jsr dump_ifaces
jsr dump_layout
lda fx_index
cmp #TRACE_INDEX
@@ -289,6 +294,52 @@ dump_members:
jmp @next
@done: rts

; Emit $F9, then each interface: name, member count, and each member's slot
; number and method name in declaration order.
dump_ifaces:
lda #$F9
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_INTERFACE
beq :+
jmp @adv
: lda id
jsr emit_name
ldy id
lda #C_TYPE_MCOUNT
jsr tb_get
sta lk_n
jsr emit
ldy id
lda #C_TYPE_MFIRST
jsr tb_get
sta lk_row
@slot: lda lk_n
beq @adv
ldy lk_row
lda #C_MEM_SLOT
jsr tb_get
jsr emit
ldy lk_row
lda #C_MEM_NAME
jsr tb_get
jsr emit_name
inc lk_row
dec lk_n
jmp @slot
@adv: inc id
beq @done
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:
@@ -519,7 +570,9 @@ fixtures:
FIXTURE "CALLS.N8"
FIXTURE "LAYOUT.N8"
FIXTURE "TOOBIG.N8"
FIXTURE_COUNT = 39
FIXTURE "INTERFACES.N8"
FIXTURE "IFACEBAD.N8"
FIXTURE_COUNT = 41
TRACE_INDEX = 28 ; PREC.N8

messages:


+ 3
- 1
newLang/tests/parser/unknown.expect Просмотреть файл

@@ -1,5 +1,7 @@
// pass 2: Printable and Worker are forward references; the rest are unknown.
// run() declares a result but its body has no return (E150).
// run() declares a result but its body has no return (E150). Worker also does
// not implement Printable.print (E130, pass 1).
IFC_METHOD_MISSING 1 1 PRINT IS NOT IMPLEMENTED
SEM_UNKNOWN_NAME 1 25
SEM_UNKNOWN_NAME 2 11
SEM_UNKNOWN_NAME 3 28


+ 10
- 0
newLang/tests/semantic/iface_bad.expect Просмотреть файл

@@ -0,0 +1,10 @@
// E03-S06: conformance failures are reported at the class declaration line,
// column 1. Missing, private, parameter-mismatched, return-mismatched,
// conflicting same-name requirements, and a class used as an interface.
// SYMBOL line column message (message compared case-insensitively)
IFC_METHOD_MISSING 28 1 AREA IS NOT IMPLEMENTED
IFC_METHOD_MISSING 31 1 LABEL IS NOT IMPLEMENTED
IFC_SIGNATURE_MISMATCH 37 1 SCALE DIFFERS FROM INTERFACE
IFC_SIGNATURE_MISMATCH 43 1 OK DIFFERS FROM INTERFACE
IFC_SIGNATURE_CONFLICT 49 1 SHOW HAS CONFLICTING SIGNATURES
IFC_NOT_INTERFACE 54 1 NOTIFACE IS NOT AN INTERFACE

+ 58
- 0
newLang/tests/semantic/iface_bad.n8 Просмотреть файл

@@ -0,0 +1,58 @@
interface Shape
method area() as word
end interface

interface Named
method label() as char
end interface

interface Scaled
method scale(f as byte) as word
end interface

interface Boolish
method ok() as boolean
end interface

interface Left
method show()
end interface

interface Right
method show(x as byte)
end interface

class NotIface
end class

class Missing implements Shape
end class

class Hider implements Named
private method label() as char
return 'h'
end method
end class

class WrongParam implements Scaled
public method scale(f as word) as word
return f
end method
end class

class WrongReturn implements Boolish
public method ok() as word
return 0
end method
end class

class Conflict implements Left, Right
public method show()
end method
end class

class BadIface implements NotIface
end class

program Main
end program

+ 9
- 0
newLang/tests/semantic/interfaces.expect Просмотреть файл

@@ -0,0 +1,9 @@
// E03-S06: interface slots follow the interface's source declaration order,
// not alphabetical or class order. Box satisfies Named.show and Display.show
// with its single public show() method.
shape slot 0 area
shape slot 1 scale
shape slot 2 name
named slot 0 label
named slot 1 show
display slot 0 show

+ 34
- 0
newLang/tests/semantic/interfaces.n8 Просмотреть файл

@@ -0,0 +1,34 @@
interface Shape
method area() as word
method scale(f as byte) as word
method name() as char
end interface

interface Named
method label() as char
method show()
end interface

class Box implements Shape, Named, Display
public method area() as word
return 1
end method
public method scale(f as byte) as word
return f
end method
public method name() as char
return 'b'
end method
public method label() as char
return 'l'
end method
public method show()
end method
end class

interface Display
method show()
end interface

program Main
end program

Загрузка…
Отмена
Сохранить

Powered by TurnKey Linux.