aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/FAILURES.md12
-rw-r--r--tests/README.md4
-rw-r--r--tests/i/class-default-public/notes.md2
-rw-r--r--tests/i/identifier-case/notes.md2
-rw-r--r--tests/i/identifier-domains/case.json3
-rw-r--r--tests/i/identifier-domains/expected.txt7
-rw-r--r--tests/i/identifier-domains/notes.md5
-rw-r--r--tests/i/identifier-domains/program.cps43
-rw-r--r--tests/i/integer-literal-contexts/case.json3
-rw-r--r--tests/i/integer-literal-contexts/expected.txt3
-rw-r--r--tests/i/integer-literal-contexts/notes.md5
-rw-r--r--tests/i/integer-literal-contexts/program.cps10
-rw-r--r--tests/i/loops/notes.md2
-rw-r--r--tests/i/loops/program.cps4
-rw-r--r--tests/i/text-files/notes.md2
-rw-r--r--tests/i/text-files/program.cps4
-rw-r--r--tests/ii/files/notes.md2
-rw-r--r--tests/ii/files/program.cps2
-rw-r--r--tests/iii/class-private-case/case.json8
-rw-r--r--tests/iii/class-private-case/notes.md3
-rw-r--r--tests/iii/class-private-case/program.cps5
-rw-r--r--tests/iii/diagnostic-call-after-arguments/case.json8
-rw-r--r--tests/iii/diagnostic-call-after-arguments/notes.md3
-rw-r--r--tests/iii/diagnostic-call-after-arguments/program.cps5
-rw-r--r--tests/iii/diagnostic-multiline-name/case.json8
-rw-r--r--tests/iii/diagnostic-multiline-name/notes.md3
-rw-r--r--tests/iii/diagnostic-multiline-name/program.cps2
-rw-r--r--tests/iii/diagnostic-nested-call/case.json8
-rw-r--r--tests/iii/diagnostic-nested-call/notes.md3
-rw-r--r--tests/iii/diagnostic-nested-call/program.cps3
-rw-r--r--tests/iii/identifier-array-collision/case.json8
-rw-r--r--tests/iii/identifier-array-collision/notes.md3
-rw-r--r--tests/iii/identifier-array-collision/program.cps2
-rw-r--r--tests/iii/identifier-builtin-collision/case.json8
-rw-r--r--tests/iii/identifier-builtin-collision/notes.md3
-rw-r--r--tests/iii/identifier-builtin-collision/program.cps3
-rw-r--r--tests/iii/identifier-constant-collision/case.json8
-rw-r--r--tests/iii/identifier-constant-collision/notes.md3
-rw-r--r--tests/iii/identifier-constant-collision/program.cps2
-rw-r--r--tests/iii/identifier-enum-collision/case.json8
-rw-r--r--tests/iii/identifier-enum-collision/notes.md3
-rw-r--r--tests/iii/identifier-enum-collision/program.cps1
-rw-r--r--tests/iii/identifier-field-collision/case.json8
-rw-r--r--tests/iii/identifier-field-collision/notes.md3
-rw-r--r--tests/iii/identifier-field-collision/program.cps4
-rw-r--r--tests/iii/identifier-function-collision/case.json8
-rw-r--r--tests/iii/identifier-function-collision/notes.md3
-rw-r--r--tests/iii/identifier-function-collision/program.cps6
-rw-r--r--tests/iii/identifier-parameter-collision/case.json8
-rw-r--r--tests/iii/identifier-parameter-collision/notes.md3
-rw-r--r--tests/iii/identifier-parameter-collision/program.cps2
-rw-r--r--tests/iii/identifier-runtime-collision/case.json8
-rw-r--r--tests/iii/identifier-runtime-collision/notes.md3
-rw-r--r--tests/iii/identifier-runtime-collision/program.cps2
-rw-r--r--tests/iii/identifier-type-collision/case.json8
-rw-r--r--tests/iii/identifier-type-collision/notes.md3
-rw-r--r--tests/iii/identifier-type-collision/program.cps2
-rw-r--r--tests/iii/identifier-variable-collision/case.json8
-rw-r--r--tests/iii/identifier-variable-collision/notes.md3
-rw-r--r--tests/iii/identifier-variable-collision/program.cps2
-rw-r--r--tests/iii/integer-bound-overflow/case.json8
-rw-r--r--tests/iii/integer-bound-overflow/notes.md3
-rw-r--r--tests/iii/integer-bound-overflow/program.cps2
-rw-r--r--tests/iii/integer-constant-overflow/case.json8
-rw-r--r--tests/iii/integer-constant-overflow/notes.md3
-rw-r--r--tests/iii/integer-constant-overflow/program.cps1
-rw-r--r--tests/iii/integer-huge-overflow/case.json8
-rw-r--r--tests/iii/integer-huge-overflow/notes.md3
-rw-r--r--tests/iii/integer-huge-overflow/program.cps1
-rw-r--r--tests/iii/integer-negative-overflow/case.json8
-rw-r--r--tests/iii/integer-negative-overflow/notes.md3
-rw-r--r--tests/iii/integer-negative-overflow/program.cps1
-rw-r--r--tests/iii/integer-positive-overflow/case.json8
-rw-r--r--tests/iii/integer-positive-overflow/notes.md3
-rw-r--r--tests/iii/integer-positive-overflow/program.cps1
-rw-r--r--tests/iii/while-do-rejected/case.json8
-rw-r--r--tests/iii/while-do-rejected/notes.md3
-rw-r--r--tests/iii/while-do-rejected/program.cps3
78 files changed, 368 insertions, 17 deletions
diff --git a/tests/FAILURES.md b/tests/FAILURES.md
index 83744e5..d88b850 100644
--- a/tests/FAILURES.md
+++ b/tests/FAILURES.md
@@ -1,10 +1,12 @@
# Compiler test findings
-Baseline: Linux x86_64, Clang/LLVM 23.1.3, Release EMBEDDED, compiler sources at `e2c6570`. Tests do not modify compiler sources. The full suite has 45 compiler cases plus harness and portable-generator checks. Fixed output expectations are pending human review.
+Baseline: Linux x86_64, Clang/LLVM 23.1.3, Release EMBEDDED, compiler sources at `e2c6570`. Tests do not modify compiler sources. The initial suite had 45 compiler cases plus harness and portable-generator checks. Fixed output expectations are pending human review.
-## Observed failures
+The expanded suite has 67 compiler cases plus harness and portable-generator checks (69 CTest entries). The 13 failures below were reproduced with the Actions seed `e1e789ac0249149a4aa1671f5f9260d488cb617a` and are now fixed on Linux Release EMBEDDED. Regression cases cover case-insensitive name domains and collisions, default/public/private fields, checked i64 literals in expressions/constants/parameter bounds, rejection of WHILE DO, and nested/multiline diagnostic locations. Existing fixed expectations and differential generators remain unchanged; WHILE fixtures now use the standard syntax.
-| Case | Required behavior | Current behavior |
+## Historical failures (fixed on Linux)
+
+| Case | Required behavior | Baseline behavior |
|---|---|---|
| i/class-default-public | Omitted access defaults to public (CIE p. 28). | Rejects the field unless PUBLIC/PRIVATE is explicit. |
| i/identifier-case | Identifier lookup is case insensitive (CIE p. 7). | Reports the differently cased variable as unknown. |
@@ -20,9 +22,9 @@ Baseline: Linux x86_64, Clang/LLVM 23.1.3, Release EMBEDDED, compiler sources at
| iii/nominal-type-mismatch | Incompatible named pointers, line 7. | Correct cause, no line. |
| iii/unknown-name | Undeclared name, line 2. | Correct cause, no line. |
-Both native and `-r` paths expose the four i-group failures. All nine iii-group failures occur with both native/IR output requests, whether the destination was absent or already contained a sentinel. Failed compilation preserves the destination in these cases. The remaining 32 compiler cases passed locally, including seven groups of 10,000 random records plus 36 boundary records (70,036 total inputs, each checked through native and embedded execution).
+At baseline, both native and `-r` paths exposed the four i-group failures. All nine iii-group failures occurred with both native/IR output requests, whether the destination was absent or already contained a sentinel. Failed compilation preserves the destination in these cases. The remaining 32 compiler cases passed locally, including seven groups of 10,000 random records plus 36 boundary records (70,036 total inputs, each checked through native and embedded execution).
-The baseline test seed and exact command results are retained in `build/test-results`; subsequent CI reports use their own explicit push SHA. Platform results from Actions are the authority for Windows/macOS verification; local Linux results do not establish their behavior.
+Current exact command results are retained in `build/test-results`; the replay uses the original Actions SHA as its seed. Subsequent CI reports use their own explicit push SHA. Platform results from Actions are the authority for Windows/macOS verification; local Linux results do not establish their behavior.
## Coverage gaps
diff --git a/tests/README.md b/tests/README.md
index 9024191..dd1407a 100644
--- a/tests/README.md
+++ b/tests/README.md
@@ -9,7 +9,7 @@ ctest --test-dir build --output-on-failure --parallel 2
python3 tests/summarize.py build/test-results
```
-Use `ctest --test-dir build -L '^ii$' --output-on-failure` for one suite, or `-R '^i/arrays$'` for one case. CTest returns failure if any case fails; it continues through the other cases. [Current failures and coverage gaps](FAILURES.md) are intentionally visible, with no expected-failure exemptions.
+Use `ctest --test-dir build -L '^ii$' --output-on-failure` for one suite, or `-R '^i/arrays$'` for one case. CTest returns failure if any case fails; it continues through the other cases. [Historical failures and coverage gaps](FAILURES.md) are intentionally visible, with no expected-failure exemptions.
The suites are **i**: independently traced fixed outputs, **ii**: C++ differential tests with Perl inputs, and **iii**: rejected programs with required causes and source lines. Fixed expectations are **pending human review**; each case's notes explain the trace and distinguish CIE rules from project extensions. REAL calculations are observed through BOOLEAN/INTEGER output; REAL text and REAL-to-string formatting remain outside this suite.
@@ -26,6 +26,6 @@ Use the actual SHA from a failed report in place of `FULL_COMMIT_SHA`. Clear `CP
`build/test-results/<suite>/<case>/` contains `result.json`, numbered command metadata, stdin/stdout/stderr, expected output and isolated work directories. Random mismatches also save the first differing record. Re-running a case replaces only that case's directory; summaries include any other retained results, so remove `build/test-results` before collecting a fresh full-suite report. Commands have finite timeouts (30 seconds normally, 120 for compilation, 180 for file-intensive executions); timeout and launch/crash failures fail the case.
-In Actions, each compiler platform runs all three suites and summarizes results before its existing package smoke checks and upload. Failures retain inputs and logs as an Actions artifact for 14 days. Each platform publishes only after its own tests pass. These new tests expose existing defects, so compiler packages will remain unpublished until those defects are fixed; the independent plugin job can still publish.
+In Actions, each compiler platform runs all three suites and summarizes results before its existing package smoke checks and upload. Failures retain inputs and logs as an Actions artifact for 14 days. Each platform publishes only after its own tests pass. The initial Linux failures have been fixed; any failing compiler test still blocks publication for that platform. The independent plugin job can publish separately.
For adding cases and runner interfaces, see [AGENTS/TESTING.md](../AGENTS/TESTING.md).
diff --git a/tests/i/class-default-public/notes.md b/tests/i/class-default-public/notes.md
index 1f5c869..db762db 100644
--- a/tests/i/class-default-public/notes.md
+++ b/tests/i/class-default-public/notes.md
@@ -2,6 +2,6 @@
Human review: pending. Expected output was independently traced by AI, not captured from cpsc.
-Basis: CIE p. 28: methods and properties are public unless otherwise stated. This conflicts with the current explicit-access requirement.
+Basis: CIE p. 28: methods and properties are public unless otherwise stated. The compiler accepts omitted access as public.
Trace: Value has default public access. Assigning and reading it must yield 7. A compile rejection is a failure, not an accepted alternative.
diff --git a/tests/i/identifier-case/notes.md b/tests/i/identifier-case/notes.md
index ac8c200..ac6e5e8 100644
--- a/tests/i/identifier-case/notes.md
+++ b/tests/i/identifier-case/notes.md
@@ -2,6 +2,6 @@
Human review: pending. Expected output was independently traced by AI, not captured from cpsc.
-Basis: CIE p. 7: identifiers should be considered case insensitive. Current symbol lookup is case sensitive.
+Basis: CIE p. 7: identifiers should be considered case insensitive. Symbol lookup must resolve both spellings to the same declaration.
Trace: Counter and counter denote the same declared variable; the read yields 7.
diff --git a/tests/i/identifier-domains/case.json b/tests/i/identifier-domains/case.json
new file mode 100644
index 0000000..1f18635
--- /dev/null
+++ b/tests/i/identifier-domains/case.json
@@ -0,0 +1,3 @@
+{
+ "exit_code": 0
+}
diff --git a/tests/i/identifier-domains/expected.txt b/tests/i/identifier-domains/expected.txt
new file mode 100644
index 0000000..95fa0cf
--- /dev/null
+++ b/tests/i/identifier-domains/expected.txt
@@ -0,0 +1,7 @@
+4
+6
+7:TRUE
+8:9
+5:3
+5
+3
diff --git a/tests/i/identifier-domains/notes.md b/tests/i/identifier-domains/notes.md
new file mode 100644
index 0000000..1a03605
--- /dev/null
+++ b/tests/i/identifier-domains/notes.md
@@ -0,0 +1,5 @@
+# identifier-domains
+
+Human review: pending. Expected output was independently traced, not captured from cpsc.
+
+CIE pp. 7, 28: names ignore case and omitted class access is public. The array is changed by reference to 4 and 6; the node is changed through its pointer to 7; Summer is the second enumerator. Class fields hold 8 and 9. The string length is 5 and the native int cast is 3. A block shadows Limit with 5, then restores 3. The function and procedure calls precede their definitions.
diff --git a/tests/i/identifier-domains/program.cps b/tests/i/identifier-domains/program.cps
new file mode 100644
index 0000000..d1b684b
--- /dev/null
+++ b/tests/i/identifier-domains/program.cps
@@ -0,0 +1,43 @@
+TYPE Node
+ DECLARE Value : INTEGER
+ENDTYPE
+TYPE Link = ^Node
+TYPE Season = (Spring, Summer)
+TYPE Signed = C_TYPE("int")
+CLASS Box
+ Value : INTEGER
+ PUBLIC Other : INTEGER
+ PRIVATE Hidden : INTEGER
+ENDCLASS
+CONSTANT Limit = 3
+DECLARE Item : nODE
+DECLARE Ptr : lINK
+DECLARE Mode : sEASON
+DECLARE Crate : bOX
+DECLARE Items : ARRAY[1:2] OF INTEGER
+DECLARE Index : INTEGER
+item.value <- limit
+pTR <- ^ITEM
+ptr^.vALUE <- 7
+mode <- sUMMER
+crate.value <- 8
+CRATE.other <- 9
+CALL cHANGE(iTEMS)
+FOR Index <- 1 TO 2
+ OUTPUT items[index]
+NEXT iNDEX
+OUTPUT rEADnODE(ITEM), ":", MODE = summer
+OUTPUT crate.VALUE, ":", crate.OTHER
+OUTPUT length("MiXeD"), ":", (sIGNED)3
+IF TRUE THEN
+ CONSTANT lIMIT = 5
+ OUTPUT LIMIT
+ENDIF
+OUTPUT Limit
+PROCEDURE Change(BYREF Values : ARRAY OF INTEGER)
+ vALUES[1] <- 4
+ VALUES[2] <- 6
+ENDPROCEDURE
+FUNCTION ReadNode(Value : NODE) RETURNS INTEGER
+ RETURN vALUE.Value
+ENDFUNCTION
diff --git a/tests/i/integer-literal-contexts/case.json b/tests/i/integer-literal-contexts/case.json
new file mode 100644
index 0000000..1f18635
--- /dev/null
+++ b/tests/i/integer-literal-contexts/case.json
@@ -0,0 +1,3 @@
+{
+ "exit_code": 0
+}
diff --git a/tests/i/integer-literal-contexts/expected.txt b/tests/i/integer-literal-contexts/expected.txt
new file mode 100644
index 0000000..e23c6cc
--- /dev/null
+++ b/tests/i/integer-literal-contexts/expected.txt
@@ -0,0 +1,3 @@
+9223372036854775807
+-9223372036854775808:9223372036854775807
+0:-1:-3
diff --git a/tests/i/integer-literal-contexts/notes.md b/tests/i/integer-literal-contexts/notes.md
new file mode 100644
index 0000000..6285895
--- /dev/null
+++ b/tests/i/integer-literal-contexts/notes.md
@@ -0,0 +1,5 @@
+# integer-literal-contexts
+
+Human review: pending. Expected output was independently traced, not captured from cpsc.
+
+The i64 endpoints are exact in constants, expressions and signed parameter bounds. The array has one element, containing Maximum. Ordinary unary negation still yields 0, -1 and -3.
diff --git a/tests/i/integer-literal-contexts/program.cps b/tests/i/integer-literal-contexts/program.cps
new file mode 100644
index 0000000..3ebc7fb
--- /dev/null
+++ b/tests/i/integer-literal-contexts/program.cps
@@ -0,0 +1,10 @@
+CONSTANT Minimum = -9223372036854775808
+CONSTANT Maximum = 9223372036854775807
+DECLARE Values : ARRAY[-9223372036854775808:-9223372036854775808] OF INTEGER
+Values[Minimum] <- Maximum
+CALL Show(Values)
+OUTPUT Minimum, ":", Maximum
+OUTPUT -0, ":", -1, ":", -(1 + 2)
+PROCEDURE Show(BYREF Items : ARRAY[-9223372036854775808:-9223372036854775808] OF INTEGER)
+ OUTPUT Items[-9223372036854775808]
+ENDPROCEDURE
diff --git a/tests/i/loops/notes.md b/tests/i/loops/notes.md
index 6979d92..bdd322a 100644
--- a/tests/i/loops/notes.md
+++ b/tests/i/loops/notes.md
@@ -6,4 +6,4 @@ Basis: CIE pp. 20-21.
Trace: FOR contributions are 0, 2, and 3+1-1=3. WHILE contributes 0+1+2=3. REPEAT contributes 10 once, then counts to 3. Total=18.
-The project requires DO after WHILE; this fixture uses that spelling to exercise runtime semantics. The separate standard-while fixture tests the CIE spelling.
+WHILE headers use the standard CIE spelling without DO. The separate standard-while fixture also checks this syntax.
diff --git a/tests/i/loops/program.cps b/tests/i/loops/program.cps
index a858e6c..d30b463 100644
--- a/tests/i/loops/program.cps
+++ b/tests/i/loops/program.cps
@@ -10,11 +10,11 @@ NEXT I
FOR I <- 3 TO -1 STEP -2
Total <- Total + I
NEXT I
-WHILE FALSE DO
+WHILE FALSE
Total <- Total + 1000
ENDWHILE
I <- 0
-WHILE I < 3 DO
+WHILE I < 3
Total <- Total + I
I <- I + 1
ENDWHILE
diff --git a/tests/i/text-files/notes.md b/tests/i/text-files/notes.md
index cc62aea..1b2ecad 100644
--- a/tests/i/text-files/notes.md
+++ b/tests/i/text-files/notes.md
@@ -6,4 +6,4 @@ Basis: CIE p. 25; CRLF input handling follows project text-file semantics.
Trace: Input contains three lines, including an empty line and a last line without terminator. Empty-file EOF is true. WRITE replaces old contents; APPEND adds last after the existing blank line.
-The project requires DO after WHILE; this fixture uses that spelling to exercise runtime semantics. The separate standard-while fixture tests the CIE spelling.
+WHILE headers use the standard CIE spelling without DO. The separate standard-while fixture also checks this syntax.
diff --git a/tests/i/text-files/program.cps b/tests/i/text-files/program.cps
index 1d6d5bb..42632fd 100644
--- a/tests/i/text-files/program.cps
+++ b/tests/i/text-files/program.cps
@@ -2,7 +2,7 @@ DECLARE Line : STRING
DECLARE Count : INTEGER
OPENFILE "input.txt" FOR READ
Count <- 0
-WHILE NOT EOF("input.txt") DO
+WHILE NOT EOF("input.txt")
READFILE "input.txt", Line
OUTPUT "[", Line, "]"
Count <- Count + 1
@@ -19,7 +19,7 @@ OPENFILE "result.txt" FOR APPEND
WRITEFILE "result.txt", "last"
CLOSEFILE "result.txt"
OPENFILE "result.txt" FOR READ
-WHILE NOT EOF("result.txt") DO
+WHILE NOT EOF("result.txt")
READFILE "result.txt", Line
OUTPUT "[", Line, "]"
ENDWHILE
diff --git a/tests/ii/files/notes.md b/tests/ii/files/notes.md
index 02831fa..a13a748 100644
--- a/tests/ii/files/notes.md
+++ b/tests/ii/files/notes.md
@@ -1,5 +1,5 @@
# files
-CIE p. 25. Both programs exercise actual text files, including truncation, append, empty lines and EOF. Separate working directories avoid shared files. Pseudocode uses the project-required WHILE DO spelling; i/standard-while separately checks the standard spelling.
+CIE p. 25. Both programs exercise actual text files, including truncation, append, empty lines and EOF. Separate working directories avoid shared files. Pseudocode uses standard WHILE headers without DO; i/standard-while separately checks this syntax.
Each record produces exactly one output line. Random records are preceded by fixed boundary records; every arithmetic intermediate is bounded.
diff --git a/tests/ii/files/program.cps b/tests/ii/files/program.cps
index 9bc4aad..f825118 100644
--- a/tests/ii/files/program.cps
+++ b/tests/ii/files/program.cps
@@ -19,7 +19,7 @@ FOR Index <- 1 TO Count
OPENFILE "roundtrip.txt" FOR READ
Combined <- ""
Lines <- 0
- WHILE NOT EOF("roundtrip.txt") DO
+ WHILE NOT EOF("roundtrip.txt")
READFILE "roundtrip.txt", Line
Combined <- Combined & "[" & Line & "]"
Lines <- Lines + 1
diff --git a/tests/iii/class-private-case/case.json b/tests/iii/class-private-case/case.json
new file mode 100644
index 0000000..6d425cd
--- /dev/null
+++ b/tests/iii/class-private-case/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Cannot\\ access\\ private\\ field\\ hIDDEN\\ of\\ type\\ Box",
+ "line": 5
+ }
+ ]
+}
diff --git a/tests/iii/class-private-case/notes.md b/tests/iii/class-private-case/notes.md
new file mode 100644
index 0000000..0eff0da
--- /dev/null
+++ b/tests/iii/class-private-case/notes.md
@@ -0,0 +1,3 @@
+# class-private-case
+
+The compiler must reject this program: Cannot access private field hIDDEN of type Box. The diagnostic must identify line 5; compilation must preserve existing output.
diff --git a/tests/iii/class-private-case/program.cps b/tests/iii/class-private-case/program.cps
new file mode 100644
index 0000000..9ba8e02
--- /dev/null
+++ b/tests/iii/class-private-case/program.cps
@@ -0,0 +1,5 @@
+CLASS Box
+ PRIVATE Hidden : INTEGER
+ENDCLASS
+DECLARE Item : Box
+OUTPUT item.hIDDEN
diff --git a/tests/iii/diagnostic-call-after-arguments/case.json b/tests/iii/diagnostic-call-after-arguments/case.json
new file mode 100644
index 0000000..2b00e17
--- /dev/null
+++ b/tests/iii/diagnostic-call-after-arguments/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "BYREF\\ argument\\ to\\ Change\\ must\\ be\\ a\\ variable",
+ "line": 3
+ }
+ ]
+}
diff --git a/tests/iii/diagnostic-call-after-arguments/notes.md b/tests/iii/diagnostic-call-after-arguments/notes.md
new file mode 100644
index 0000000..9011f61
--- /dev/null
+++ b/tests/iii/diagnostic-call-after-arguments/notes.md
@@ -0,0 +1,3 @@
+# diagnostic-call-after-arguments
+
+The compiler must reject this program: BYREF argument to Change must be a variable. The diagnostic must identify line 3; compilation must preserve existing output.
diff --git a/tests/iii/diagnostic-call-after-arguments/program.cps b/tests/iii/diagnostic-call-after-arguments/program.cps
new file mode 100644
index 0000000..743a51c
--- /dev/null
+++ b/tests/iii/diagnostic-call-after-arguments/program.cps
@@ -0,0 +1,5 @@
+PROCEDURE Change(BYVAL Text : STRING, BYREF Value : INTEGER)
+ENDPROCEDURE
+CALL Change(
+ LEFT("text", 2),
+ 1)
diff --git a/tests/iii/diagnostic-multiline-name/case.json b/tests/iii/diagnostic-multiline-name/case.json
new file mode 100644
index 0000000..e90b979
--- /dev/null
+++ b/tests/iii/diagnostic-multiline-name/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Unknown\\ variable\\ name\\ Missing",
+ "line": 2
+ }
+ ]
+}
diff --git a/tests/iii/diagnostic-multiline-name/notes.md b/tests/iii/diagnostic-multiline-name/notes.md
new file mode 100644
index 0000000..28534c3
--- /dev/null
+++ b/tests/iii/diagnostic-multiline-name/notes.md
@@ -0,0 +1,3 @@
+# diagnostic-multiline-name
+
+The compiler must reject this program: Unknown variable name Missing. The diagnostic must identify line 2; compilation must preserve existing output.
diff --git a/tests/iii/diagnostic-multiline-name/program.cps b/tests/iii/diagnostic-multiline-name/program.cps
new file mode 100644
index 0000000..529dd9f
--- /dev/null
+++ b/tests/iii/diagnostic-multiline-name/program.cps
@@ -0,0 +1,2 @@
+OUTPUT 1 +
+ Missing
diff --git a/tests/iii/diagnostic-nested-call/case.json b/tests/iii/diagnostic-nested-call/case.json
new file mode 100644
index 0000000..a00f88b
--- /dev/null
+++ b/tests/iii/diagnostic-nested-call/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "MID\\ expects\\ 3\\ args",
+ "line": 2
+ }
+ ]
+}
diff --git a/tests/iii/diagnostic-nested-call/notes.md b/tests/iii/diagnostic-nested-call/notes.md
new file mode 100644
index 0000000..252dec7
--- /dev/null
+++ b/tests/iii/diagnostic-nested-call/notes.md
@@ -0,0 +1,3 @@
+# diagnostic-nested-call
+
+The compiler must reject this program: MID expects 3 args. The diagnostic must identify line 2; compilation must preserve existing output.
diff --git a/tests/iii/diagnostic-nested-call/program.cps b/tests/iii/diagnostic-nested-call/program.cps
new file mode 100644
index 0000000..0987bed
--- /dev/null
+++ b/tests/iii/diagnostic-nested-call/program.cps
@@ -0,0 +1,3 @@
+OUTPUT LENGTH(
+ MID("text", 1)
+)
diff --git a/tests/iii/identifier-array-collision/case.json b/tests/iii/identifier-array-collision/case.json
new file mode 100644
index 0000000..4bb0e66
--- /dev/null
+++ b/tests/iii/identifier-array-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Declaration\\ of\\ values\\ conflicts\\ with\\ an\\ existing\\ declaration\\ in\\ this\\ scope",
+ "line": 2
+ }
+ ]
+}
diff --git a/tests/iii/identifier-array-collision/notes.md b/tests/iii/identifier-array-collision/notes.md
new file mode 100644
index 0000000..e11a241
--- /dev/null
+++ b/tests/iii/identifier-array-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-array-collision
+
+Names differing only in ASCII case cannot introduce a separate symbol. Require Declaration of values conflicts with an existing declaration in this scope at line 2, a failed compilation, and preservation of any existing output.
diff --git a/tests/iii/identifier-array-collision/program.cps b/tests/iii/identifier-array-collision/program.cps
new file mode 100644
index 0000000..94a8083
--- /dev/null
+++ b/tests/iii/identifier-array-collision/program.cps
@@ -0,0 +1,2 @@
+DECLARE Values : ARRAY[1:2] OF INTEGER
+DECLARE values : INTEGER
diff --git a/tests/iii/identifier-builtin-collision/case.json b/tests/iii/identifier-builtin-collision/case.json
new file mode 100644
index 0000000..df7c2b6
--- /dev/null
+++ b/tests/iii/identifier-builtin-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "'lENGTH'\\ is\\ a\\ built\\-in\\ function\\ and\\ cannot\\ be\\ redefined",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/identifier-builtin-collision/notes.md b/tests/iii/identifier-builtin-collision/notes.md
new file mode 100644
index 0000000..85b97fe
--- /dev/null
+++ b/tests/iii/identifier-builtin-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-builtin-collision
+
+Names differing only in ASCII case cannot introduce a separate symbol. Require 'lENGTH' is a built-in function and cannot be redefined at line 1, a failed compilation, and preservation of any existing output.
diff --git a/tests/iii/identifier-builtin-collision/program.cps b/tests/iii/identifier-builtin-collision/program.cps
new file mode 100644
index 0000000..647aab9
--- /dev/null
+++ b/tests/iii/identifier-builtin-collision/program.cps
@@ -0,0 +1,3 @@
+FUNCTION lENGTH() RETURNS INTEGER
+ RETURN 1
+ENDFUNCTION
diff --git a/tests/iii/identifier-constant-collision/case.json b/tests/iii/identifier-constant-collision/case.json
new file mode 100644
index 0000000..bdb0040
--- /dev/null
+++ b/tests/iii/identifier-constant-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Declaration\\ of\\ lIMIT\\ conflicts\\ with\\ an\\ existing\\ declaration\\ in\\ this\\ scope",
+ "line": 2
+ }
+ ]
+}
diff --git a/tests/iii/identifier-constant-collision/notes.md b/tests/iii/identifier-constant-collision/notes.md
new file mode 100644
index 0000000..d5ea85e
--- /dev/null
+++ b/tests/iii/identifier-constant-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-constant-collision
+
+Names differing only in ASCII case cannot introduce a separate symbol. Require Declaration of lIMIT conflicts with an existing declaration in this scope at line 2, a failed compilation, and preservation of any existing output.
diff --git a/tests/iii/identifier-constant-collision/program.cps b/tests/iii/identifier-constant-collision/program.cps
new file mode 100644
index 0000000..c202f59
--- /dev/null
+++ b/tests/iii/identifier-constant-collision/program.cps
@@ -0,0 +1,2 @@
+CONSTANT Limit = 3
+DECLARE lIMIT : INTEGER
diff --git a/tests/iii/identifier-enum-collision/case.json b/tests/iii/identifier-enum-collision/case.json
new file mode 100644
index 0000000..53f0cdc
--- /dev/null
+++ b/tests/iii/identifier-enum-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Duplicate\\ value\\ 'spring'\\ in\\ enum\\ Season",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/identifier-enum-collision/notes.md b/tests/iii/identifier-enum-collision/notes.md
new file mode 100644
index 0000000..0fdb4de
--- /dev/null
+++ b/tests/iii/identifier-enum-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-enum-collision
+
+The compiler must reject this program: Duplicate value 'spring' in enum Season. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/identifier-enum-collision/program.cps b/tests/iii/identifier-enum-collision/program.cps
new file mode 100644
index 0000000..bd80acc
--- /dev/null
+++ b/tests/iii/identifier-enum-collision/program.cps
@@ -0,0 +1 @@
+TYPE Season = (Spring, spring)
diff --git a/tests/iii/identifier-field-collision/case.json b/tests/iii/identifier-field-collision/case.json
new file mode 100644
index 0000000..cb164c7
--- /dev/null
+++ b/tests/iii/identifier-field-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Duplicate\\ field\\ 'value'\\ in\\ record\\ Box",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/identifier-field-collision/notes.md b/tests/iii/identifier-field-collision/notes.md
new file mode 100644
index 0000000..d88ddfb
--- /dev/null
+++ b/tests/iii/identifier-field-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-field-collision
+
+The compiler must reject this program: Duplicate field 'value' in record Box. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/identifier-field-collision/program.cps b/tests/iii/identifier-field-collision/program.cps
new file mode 100644
index 0000000..56597bf
--- /dev/null
+++ b/tests/iii/identifier-field-collision/program.cps
@@ -0,0 +1,4 @@
+CLASS Box
+ Value : INTEGER
+ value : INTEGER
+ENDCLASS
diff --git a/tests/iii/identifier-function-collision/case.json b/tests/iii/identifier-function-collision/case.json
new file mode 100644
index 0000000..7743273
--- /dev/null
+++ b/tests/iii/identifier-function-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Function\\ value\\ cannot\\ be\\ redefined\\.",
+ "line": 4
+ }
+ ]
+}
diff --git a/tests/iii/identifier-function-collision/notes.md b/tests/iii/identifier-function-collision/notes.md
new file mode 100644
index 0000000..795b86d
--- /dev/null
+++ b/tests/iii/identifier-function-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-function-collision
+
+Names differing only in ASCII case cannot introduce a separate symbol. Require Function value cannot be redefined. at line 4, a failed compilation, and preservation of any existing output.
diff --git a/tests/iii/identifier-function-collision/program.cps b/tests/iii/identifier-function-collision/program.cps
new file mode 100644
index 0000000..cc7f6de
--- /dev/null
+++ b/tests/iii/identifier-function-collision/program.cps
@@ -0,0 +1,6 @@
+FUNCTION Value() RETURNS INTEGER
+ RETURN 1
+ENDFUNCTION
+FUNCTION value() RETURNS INTEGER
+ RETURN 2
+ENDFUNCTION
diff --git a/tests/iii/identifier-parameter-collision/case.json b/tests/iii/identifier-parameter-collision/case.json
new file mode 100644
index 0000000..17daa9a
--- /dev/null
+++ b/tests/iii/identifier-parameter-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Duplicate\\ parameter\\ name\\ 'value'",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/identifier-parameter-collision/notes.md b/tests/iii/identifier-parameter-collision/notes.md
new file mode 100644
index 0000000..c752a2f
--- /dev/null
+++ b/tests/iii/identifier-parameter-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-parameter-collision
+
+The compiler must reject this program: Duplicate parameter name value. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/identifier-parameter-collision/program.cps b/tests/iii/identifier-parameter-collision/program.cps
new file mode 100644
index 0000000..2cb5af6
--- /dev/null
+++ b/tests/iii/identifier-parameter-collision/program.cps
@@ -0,0 +1,2 @@
+PROCEDURE Bad(Value : INTEGER, value : INTEGER)
+ENDPROCEDURE
diff --git a/tests/iii/identifier-runtime-collision/case.json b/tests/iii/identifier-runtime-collision/case.json
new file mode 100644
index 0000000..aa83876
--- /dev/null
+++ b/tests/iii/identifier-runtime-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "'Printf'\\ is\\ a\\ reserved\\ runtime\\ symbol",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/identifier-runtime-collision/notes.md b/tests/iii/identifier-runtime-collision/notes.md
new file mode 100644
index 0000000..ec125eb
--- /dev/null
+++ b/tests/iii/identifier-runtime-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-runtime-collision
+
+Names differing only in ASCII case cannot introduce a separate symbol. Require 'Printf' is a reserved runtime symbol at line 1, a failed compilation, and preservation of any existing output.
diff --git a/tests/iii/identifier-runtime-collision/program.cps b/tests/iii/identifier-runtime-collision/program.cps
new file mode 100644
index 0000000..6e526fd
--- /dev/null
+++ b/tests/iii/identifier-runtime-collision/program.cps
@@ -0,0 +1,2 @@
+PROCEDURE Printf()
+ENDPROCEDURE
diff --git a/tests/iii/identifier-type-collision/case.json b/tests/iii/identifier-type-collision/case.json
new file mode 100644
index 0000000..93f3914
--- /dev/null
+++ b/tests/iii/identifier-type-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Type\\ first\\ is\\ already\\ defined",
+ "line": 2
+ }
+ ]
+}
diff --git a/tests/iii/identifier-type-collision/notes.md b/tests/iii/identifier-type-collision/notes.md
new file mode 100644
index 0000000..3483ceb
--- /dev/null
+++ b/tests/iii/identifier-type-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-type-collision
+
+The compiler must reject this program: Type first is already defined. The diagnostic must identify line 2; compilation must preserve existing output.
diff --git a/tests/iii/identifier-type-collision/program.cps b/tests/iii/identifier-type-collision/program.cps
new file mode 100644
index 0000000..d1f475f
--- /dev/null
+++ b/tests/iii/identifier-type-collision/program.cps
@@ -0,0 +1,2 @@
+TYPE First = ^INTEGER
+TYPE first = ^INTEGER
diff --git a/tests/iii/identifier-variable-collision/case.json b/tests/iii/identifier-variable-collision/case.json
new file mode 100644
index 0000000..b50d602
--- /dev/null
+++ b/tests/iii/identifier-variable-collision/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Declaration\\ of\\ counter\\ conflicts\\ with\\ an\\ existing\\ declaration\\ in\\ this\\ scope",
+ "line": 2
+ }
+ ]
+}
diff --git a/tests/iii/identifier-variable-collision/notes.md b/tests/iii/identifier-variable-collision/notes.md
new file mode 100644
index 0000000..a25de06
--- /dev/null
+++ b/tests/iii/identifier-variable-collision/notes.md
@@ -0,0 +1,3 @@
+# identifier-variable-collision
+
+The compiler must reject this program: Declaration of counter conflicts with an existing declaration in this scope. The diagnostic must identify line 2; compilation must preserve existing output.
diff --git a/tests/iii/identifier-variable-collision/program.cps b/tests/iii/identifier-variable-collision/program.cps
new file mode 100644
index 0000000..fc0d743
--- /dev/null
+++ b/tests/iii/identifier-variable-collision/program.cps
@@ -0,0 +1,2 @@
+DECLARE Counter : INTEGER
+DECLARE counter : INTEGER
diff --git a/tests/iii/integer-bound-overflow/case.json b/tests/iii/integer-bound-overflow/case.json
new file mode 100644
index 0000000..6421b0f
--- /dev/null
+++ b/tests/iii/integer-bound-overflow/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Integer\\ literal\\ is\\ outside\\ the\\ i64\\ range",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/integer-bound-overflow/notes.md b/tests/iii/integer-bound-overflow/notes.md
new file mode 100644
index 0000000..1c3171a
--- /dev/null
+++ b/tests/iii/integer-bound-overflow/notes.md
@@ -0,0 +1,3 @@
+# integer-bound-overflow
+
+The compiler must reject this program: Integer literal is outside the i64 range. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/integer-bound-overflow/program.cps b/tests/iii/integer-bound-overflow/program.cps
new file mode 100644
index 0000000..6bdd156
--- /dev/null
+++ b/tests/iii/integer-bound-overflow/program.cps
@@ -0,0 +1,2 @@
+PROCEDURE Bad(Values : ARRAY[0:9223372036854775808] OF INTEGER)
+ENDPROCEDURE
diff --git a/tests/iii/integer-constant-overflow/case.json b/tests/iii/integer-constant-overflow/case.json
new file mode 100644
index 0000000..6421b0f
--- /dev/null
+++ b/tests/iii/integer-constant-overflow/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Integer\\ literal\\ is\\ outside\\ the\\ i64\\ range",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/integer-constant-overflow/notes.md b/tests/iii/integer-constant-overflow/notes.md
new file mode 100644
index 0000000..b13c24e
--- /dev/null
+++ b/tests/iii/integer-constant-overflow/notes.md
@@ -0,0 +1,3 @@
+# integer-constant-overflow
+
+The compiler must reject this program: Integer literal is outside the i64 range. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/integer-constant-overflow/program.cps b/tests/iii/integer-constant-overflow/program.cps
new file mode 100644
index 0000000..849c3eb
--- /dev/null
+++ b/tests/iii/integer-constant-overflow/program.cps
@@ -0,0 +1 @@
+CONSTANT TooBig = 9223372036854775808
diff --git a/tests/iii/integer-huge-overflow/case.json b/tests/iii/integer-huge-overflow/case.json
new file mode 100644
index 0000000..6421b0f
--- /dev/null
+++ b/tests/iii/integer-huge-overflow/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Integer\\ literal\\ is\\ outside\\ the\\ i64\\ range",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/integer-huge-overflow/notes.md b/tests/iii/integer-huge-overflow/notes.md
new file mode 100644
index 0000000..acc9bfb
--- /dev/null
+++ b/tests/iii/integer-huge-overflow/notes.md
@@ -0,0 +1,3 @@
+# integer-huge-overflow
+
+The compiler must reject this program: Integer literal is outside the i64 range. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/integer-huge-overflow/program.cps b/tests/iii/integer-huge-overflow/program.cps
new file mode 100644
index 0000000..2e4ba62
--- /dev/null
+++ b/tests/iii/integer-huge-overflow/program.cps
@@ -0,0 +1 @@
+OUTPUT 9999999999999999999999999999999999999
diff --git a/tests/iii/integer-negative-overflow/case.json b/tests/iii/integer-negative-overflow/case.json
new file mode 100644
index 0000000..6421b0f
--- /dev/null
+++ b/tests/iii/integer-negative-overflow/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Integer\\ literal\\ is\\ outside\\ the\\ i64\\ range",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/integer-negative-overflow/notes.md b/tests/iii/integer-negative-overflow/notes.md
new file mode 100644
index 0000000..029a543
--- /dev/null
+++ b/tests/iii/integer-negative-overflow/notes.md
@@ -0,0 +1,3 @@
+# integer-negative-overflow
+
+The compiler must reject this program: Integer literal is outside the i64 range. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/integer-negative-overflow/program.cps b/tests/iii/integer-negative-overflow/program.cps
new file mode 100644
index 0000000..e208ba6
--- /dev/null
+++ b/tests/iii/integer-negative-overflow/program.cps
@@ -0,0 +1 @@
+OUTPUT -9223372036854775809
diff --git a/tests/iii/integer-positive-overflow/case.json b/tests/iii/integer-positive-overflow/case.json
new file mode 100644
index 0000000..6421b0f
--- /dev/null
+++ b/tests/iii/integer-positive-overflow/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Integer\\ literal\\ is\\ outside\\ the\\ i64\\ range",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/integer-positive-overflow/notes.md b/tests/iii/integer-positive-overflow/notes.md
new file mode 100644
index 0000000..2c17ff4
--- /dev/null
+++ b/tests/iii/integer-positive-overflow/notes.md
@@ -0,0 +1,3 @@
+# integer-positive-overflow
+
+The compiler must reject this program: Integer literal is outside the i64 range. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/integer-positive-overflow/program.cps b/tests/iii/integer-positive-overflow/program.cps
new file mode 100644
index 0000000..286c0eb
--- /dev/null
+++ b/tests/iii/integer-positive-overflow/program.cps
@@ -0,0 +1 @@
+OUTPUT 9223372036854775808
diff --git a/tests/iii/while-do-rejected/case.json b/tests/iii/while-do-rejected/case.json
new file mode 100644
index 0000000..9908d5e
--- /dev/null
+++ b/tests/iii/while-do-rejected/case.json
@@ -0,0 +1,8 @@
+{
+ "errors": [
+ {
+ "reason": "Expected\\ '<\\-'\\ after\\ identifier\\ 'DO'",
+ "line": 1
+ }
+ ]
+}
diff --git a/tests/iii/while-do-rejected/notes.md b/tests/iii/while-do-rejected/notes.md
new file mode 100644
index 0000000..ed669b5
--- /dev/null
+++ b/tests/iii/while-do-rejected/notes.md
@@ -0,0 +1,3 @@
+# while-do-rejected
+
+The compiler must reject this program: Expected '<-' after identifier 'DO'. The diagnostic must identify line 1; compilation must preserve existing output.
diff --git a/tests/iii/while-do-rejected/program.cps b/tests/iii/while-do-rejected/program.cps
new file mode 100644
index 0000000..b733e21
--- /dev/null
+++ b/tests/iii/while-do-rejected/program.cps
@@ -0,0 +1,3 @@
+WHILE FALSE DO
+ OUTPUT 1
+ENDWHILE