Please take another look at progress on issue #43 in light of the recent fixes for generated golang validity problems.
The user wants me to look at issue #43 and assess progress in light of recent fixes. Let me fetch the issue details and also check what recent fixes have been made.
title: Course examples: unimplemented features preventing transpilation state: OPEN author: associate-1 labels: comments: 2 assignees: projects: milestone: number: 43 -- ## Summary Transpiling the 16 example programs in `kroc/modules/course/examples/` reveals that 11 out of 16 fail to parse due to unimplemented language features. Only `hello_world.occ`, `hello_seq_world.occ`, `hello_raw_world.occ`, `echoing.occ`, and `double_echo.occ` transpile successfully. This is a tracking issue for the full set of missing features discovered. Some have their own dedicated issues. ## Unimplemented Features ### Standard occam features | Feature | Description | Affected files | Issue | |---------|-------------|----------------|-------| | `INLINE FUNCTION` | Function qualifier `INT INLINE FUNCTION f(...)` | `bar.occ` | #44 | | `ALT` replicators | `ALT i = 0 FOR n` (like SEQ/PAR/IF replicators) | `sort_pump.occ`, `sort_pump_2.occ`, `sort_inside.occ`, `sort_inside_2.occ`, `bar.occ` | #45 | | `INT16`/`INT32`/`INT64` | Extended integer width types | `cast.occ`, `casting.occ`, `commstime.occ` | #46 | | `tim ? AFTER expr` | Timer AFTER input (wait until time) | `bar.occ`, `demo.occ`, `sort_inside_2.occ` | | | `PRI ALT` | Prioritised alternation | `bar.occ` | | | Guarded ALT (`&`) | `(condition) & chan ? x` boolean pre-conditions | `bar.occ` | | | Multi-value `CASE` labels | `'*n', '*c'` comma-separated case values | `test_bell.occ` | | | `[][]TYPE` / `[][n]TYPE` | Multi-dimensional array declarations | `bar.occ`, `test_utils.occ` | | | Dotted protocol tags | `bar.blank`, `bar.terminate` in PROTOCOL CASE | `bar.occ` | | | `*"` string escape | Escaped quote character inside string literals | `test_utils.occ` | | ### occam-pi extensions | Feature | Description | Affected files | Issue | |---------|-------------|----------------|-------| | `SHARED CHAN` / `CLAIM` | Shared channels and exclusive access blocks | `bar.occ` | #40 | | `MOBILE` types | Dynamically allocated mobile data | `demo.occ` | #40 | ## Error distribution by file | File | Root causes | |------|-------------| | `bar.occ` | INLINE, PRI ALT, ALT replicator, AFTER, SHARED/CLAIM, guarded ALT, multi-dim arrays, dotted protocol tags | | `cast.occ` | INT16/INT32/INT64 | | `casting.occ` | INT16/INT32/INT64 | | `commstime.occ` | INT64 | | `demo.occ` | AFTER, MOBILE | | `sort_inside.occ` | ALT replicator, multi-dim arrays | | `sort_inside_2.occ` | ALT replicator, AFTER | | `sort_pump.occ` | ALT replicator | | `sort_pump_2.occ` | ALT replicator | | `test_bell.occ` | Multi-value CASE labels | | `test_utils.occ` | Multi-dim arrays, string escape |
5a513cd Merge pull request #58 from codeassociates/fix/scope-boolvars-per-proc 347f176 Scope boolVars per proc/function body to prevent cross-proc leakage 36a462d Merge pull request #55 from codeassociates/fix/typed-abbreviation-type-loss 74b192a Fix typed abbreviations losing declared type in local scope c1adc5f Merge pull request #54 from codeassociates/feat/round-trunc-qualifiers 1a6da77 Support ROUND/TRUNC qualifiers on type conversions babbe52 Merge pull request #53 from codeassociates/fix/bool-numeric-type-conversions 0df6ec8 Fix BOOL↔BYTE/numeric type conversions fb12896 Merge pull request #49 from codeassociates/feat/int16-int32-int64-types 4ed782c Support INT16, INT32, INT64 integer types 5f68a88 Merge pull request #48 from codeassociates/feat/alt-replicator 8f8d542 Support ALT replicators (ALT i = 0 FOR n) 3cbf1cd Merge pull request #47 from codeassociates/feat/inline-function-modifier 14c62e1 Support INLINE function modifier a6f7350 Merge pull request #42 from codeassociates/feat/source-map-error-messages 9227d08 Add source file tracking to parser error messages d6b665f Merge pull request #38 from codeassociates/docs/gen-module-limitation cb5f541 Document gen-module regex-based limitation e8c9709 Merge pull request #36 from codeassociates/fix/readme-course-module-step 25a045a Add missing gen-module step to course module instructions
git log --oneline main..fix/chan-array-dir-params
author: associate-1 association: member edited: false status: none -- ## Status Update (2026-02-22) Since this issue was opened, three features have been implemented: - **`INLINE FUNCTION`** (#44, closed) - **`ALT` replicators** (#45, closed) - **`INT16`/`INT32`/`INT64`** (#46, closed) ### Current results: 10/16 transpile, 6/16 pass `go vet` | File | Transpile | `go vet` | Remaining blockers | |------|-----------|----------|--------------------| | `hello_world.occ` | OK | OK | — | | `hello_seq_world.occ` | OK | OK | — | | `hello_raw_world.occ` | OK | OK | — | | `echoing.occ` | OK | OK | — | | `double_echo.occ` | OK | OK | — | | `commstime.occ` | **OK** | **OK** | — *(was blocked by INT64)* | | `cast.occ` | **OK** | FAIL | BOOL↔BYTE type conversion (`byte(bool)` invalid in Go); `ROUND`/`TRUNC` qualifiers on type casts | | `casting.occ` | **OK** | FAIL | Same as `cast.occ` | | `sort_pump.occ` | **OK** | FAIL | `VAL BYTE x IS 1:` abbreviation inferred as `int` instead of `byte`, causing INT→BYTE assignment error | | `sort_pump_2.occ` | **OK** | FAIL | Same as `sort_pump.occ` | | `bar.occ` | FAIL | — | PRI ALT, SHARED/CLAIM, dotted protocol tags, `tim ? AFTER`, multi-dim arrays, guarded ALT with boolean expressions | | `demo.occ` | FAIL | — | `tim ? AFTER`, `MOBILE` types | | `sort_inside.occ` | FAIL | — | Expression-sized arrays (`[max.delay]BYTE`, `[total - 1]BYTE`) — *not* multi-dim arrays as originally reported | | `sort_inside_2.occ` | FAIL | — | `SIZE` of direction-annotated channel name (`SIZE monitor?`), `tim ? AFTER` | | `test_bell.occ` | FAIL | — | Multi-value `CASE` labels (`'*n', '*c'`) | | `test_utils.occ` | FAIL | — | Multi-dim arrays (`[][2]BYTE`), `*"` string escape | ### Summary of changes since original report - **Files now fully working:** `commstime.occ` (1 new, 6 total) - **Files now transpiling but with codegen bugs:** `cast.occ`, `casting.occ`, `sort_pump.occ`, `sort_pump_2.occ` (4 new) - **Files still failing to parse:** 6 (down from 11) ### Corrections to original error distribution - **`sort_inside.occ`**: Root cause is **expression-sized arrays** (`[expr]TYPE`), not multi-dim arrays or ALT replicators. ALT replicators are now implemented and are not used in this file. - **`sort_inside_2.occ`**: ALT replicator itself works, but `SIZE monitor?` (SIZE of a direction-annotated channel param) fails to parse. Also blocked by `tim ? AFTER`. ### New codegen bugs discovered 1. **BOOL↔BYTE conversion**: Go does not allow `byte(boolVal)`. Needs a conditional expression or helper. Also `BOOL(expr)` type conversion is unhandled. 2. **ROUND/TRUNC qualifiers**: `REAL32 ROUND expr` and `INT64 TRUNC expr` are not implemented — the qualifier is currently parsed as a separate function call. 3. **Typed abbreviation inference**: `VAL BYTE first.col IS 1:` generates `first_col := 1` (inferred as `int`), should generate `var first_col byte = 1` to preserve the declared type. ### Remaining unimplemented features (updated) | Feature | Affected files | |---------|---------------| | `tim ? AFTER expr` | `bar.occ`, `demo.occ`, `sort_inside_2.occ` | | `PRI ALT` | `bar.occ` | | Guarded ALT with boolean expr `(cond) & chan ? x` | `bar.occ` | | `SHARED CHAN` / `CLAIM` | `bar.occ` | | `MOBILE` types | `demo.occ` | | Multi-value `CASE` labels | `test_bell.occ` | | Multi-dim arrays (`[][n]TYPE`) | `bar.occ`, `test_utils.occ` | | Expression-sized arrays (`[expr]TYPE`) | `sort_inside.occ` | | Dotted protocol tags | `bar.occ` | | `*"` string escape | `test_utils.occ` | | `SIZE` of direction-annotated name | `sort_inside_2.occ` | | `ROUND`/`TRUNC` cast qualifiers | `cast.occ`, `casting.occ` | | BOOL↔BYTE type conversions | `cast.occ`, `casting.occ` | | Typed abbreviation type preservation | `sort_pump.occ`, `sort_pump_2.occ` | -- author: associate-1 association: member edited: true status: none -- ## Status Update (2026-02-22) — After PRs #53, #54, and typed abbreviation fix Three codegen bugs from the previous update have been fixed: - **ROUND/TRUNC qualifiers** (#54, merged) — `REAL32 ROUND i16`, `INT64 TRUNC r32`, etc. now generate correctly - **BOOL↔numeric type conversions** (#53, merged) — `BOOL expr` → `((expr) != 0)`, `INT boolExpr` → `_boolToInt(expr)` - **Typed abbreviation type loss** (#55) — `VAL BYTE first.col IS 1:` now emits `var first_col byte = 1` instead of `first_col := 1` ### Current results: 10/16 transpile, 7/16 pass `go vet` | File | Transpile | `go vet` | Remaining blockers | |------|-----------|----------|--------------------| | `hello_world.occ` | OK | OK | — | | `hello_seq_world.occ` | OK | OK | — | | `hello_raw_world.occ` | OK | OK | — | | `echoing.occ` | OK | OK | — | | `double_echo.occ` | OK | OK | — | | `commstime.occ` | OK | OK | — | | `cast.occ` | OK | **FAIL** | `boolVars` scoping bug — #56 | | `casting.occ` | OK | **FAIL** | Same as `cast.occ` — #56 | | `sort_pump.occ` | OK | **FAIL** | Channel array direction covariance — #57 | | `sort_pump_2.occ` | OK | **FAIL** | Same as `sort_pump.occ` — #57 | | `bar.occ` | FAIL | — | PRI ALT, SHARED/CLAIM, dotted protocol tags, `tim ? AFTER`, guarded ALT, multi-dim arrays | | `demo.occ` | FAIL | — | `tim ? AFTER`, MOBILE | | `sort_inside.occ` | FAIL | — | Expression-sized arrays (`[expr]TYPE`) | | `sort_inside_2.occ` | FAIL | — | `SIZE monitor?`, `tim ? AFTER` | | `test_bell.occ` | FAIL | — | Multi-value CASE labels | | `test_utils.occ` | FAIL | — | Multi-dim arrays (`[][n]TYPE`), `*"` string escape | ### Changes from previous update - **Newly passing `go vet`:** `commstime.occ` was already passing; no new files pass vet this round, but previous failures were replaced by different, previously-hidden failures - **ROUND/TRUNC:** fixed — no longer a blocker for `cast.occ`/`casting.occ` - **Typed abbreviation type loss:** fixed — no longer a blocker for `sort_pump.occ`/`sort_pump_2.occ` - **New bugs uncovered:** 2 (filed as #56 and #57) ### Remaining codegen bugs | Bug | Affected files | Issue | |-----|----------------|-------| | `boolVars` map is global/flat — name collisions across scopes | `cast.occ`, `casting.occ` | #56 | | `[]chan T` cannot be passed as `[]<-chan T` in Go (slice covariance) | `sort_pump.occ`, `sort_pump_2.occ` | #57 | ### Remaining unimplemented features (unchanged) | Feature | Affected files | |---------|---------------| | `tim ? AFTER expr` | `bar.occ`, `demo.occ`, `sort_inside_2.occ` | | `PRI ALT` | `bar.occ` | | Guarded ALT (`(cond) & chan ? x`) | `bar.occ` | | `SHARED CHAN` / `CLAIM` | `bar.occ` | | `MOBILE` types | `demo.occ` | | Multi-value CASE labels | `test_bell.occ` | | Multi-dim arrays (`[][n]TYPE`) | `bar.occ`, `test_utils.occ` | | Expression-sized arrays (`[expr]TYPE`) | `sort_inside.occ` | | Dotted protocol tags | `bar.occ` | | `*"` string escape | `test_utils.occ` | | `SIZE` of direction-annotated name | `sort_inside_2.occ` | --
Now let me check the status of issues #56 and #57 and the current branch's fix, then actually run the transpiler against all 16 example files to get the current status.
Good, so the current branch has the fix for #57 (channel array direction covariance), and #56 (boolVars scoping) and #58 were already merged to main. Let me run the transpiler against all 16 examples to get the actual current status.
kroc/modules/course/examples/bar.occ kroc/modules/course/examples/cast.occ kroc/modules/course/examples/casting.occ kroc/modules/course/examples/commstime.occ kroc/modules/course/examples/demo.occ kroc/modules/course/examples/double_echo.occ kroc/modules/course/examples/echoing.occ kroc/modules/course/examples/hello_raw_world.occ kroc/modules/course/examples/hello_seq_world.occ kroc/modules/course/examples/hello_world.occ kroc/modules/course/examples/sort_inside.occ kroc/modules/course/examples/sort_inside_2.occ kroc/modules/course/examples/sort_pump.occ kroc/modules/course/examples/sort_pump_2.occ kroc/modules/course/examples/test_bell.occ kroc/modules/course/examples/test_utils.occ
for f in kroc/modules/course/examples/*.occ; do
base=$(basename "$f" .occ)
out="/tmp/course_${base}.go"
echo "=== $base ==="
if ./occam2go -I kroc/modules/course/libsrc -D TARGET.BITS.PER.WORD=32 -o "$out" "$f" 2>&1; then
echo " TRANSPILE: OK"
if go vet "$out" 2>&1; then
echo " GO VET: OK"
else
echo " GO VET: FAIL"
fi
else
echo " TRANSPILE: FAIL"
fi
echo ""
done=== bar === Parse errors: kroc/modules/course/examples/bar.occ:77: expected variant tag name, got : kroc/modules/course/examples/bar.occ:77: unexpected token: : kroc/modules/course/examples/bar.occ:77: unexpected token in expression: ] kroc/modules/course/examples/bar.occ:77: expected ], got BYTE kroc/modules/course/examples/bar.occ:77: expected IDENT, got NEWLINE kroc/modules/course/examples/bar.occ:78: unexpected token: ; kroc/modules/course/examples/bar.occ:78: expected IDENT, got NEWLINE kroc/modules/course/examples/bar.occ:79: unexpected token: ; kroc/modules/course/examples/bar.occ:79: expected IDENT, got NEWLINE kroc/modules/course/examples/bar.occ:80: unexpected token: ; kroc/modules/course/examples/bar.occ:80: expected IDENT, got NEWLINE kroc/modules/course/examples/bar.occ:81: unexpected token: ; kroc/modules/course/examples/bar.occ:81: expected IDENT, got NEWLINE kroc/modules/course/examples/bar.occ:86: unexpected token: : kroc/modules/course/examples/bar.occ:109: expected type after VAL, got [ kroc/modules/course/examples/bar.occ:109: unexpected token: ] kroc/modules/course/examples/bar.occ:110: expected type after VAL, got [ kroc/modules/course/examples/bar.occ:110: unexpected token: ] kroc/modules/course/examples/bar.occ:111: expected type after VAL, got [ kroc/modules/course/examples/bar.occ:111: unexpected token: ] kroc/modules/course/examples/bar.occ:118: expected type in parameter, got IDENT kroc/modules/course/examples/bar.occ:118: expected ), got CHAN kroc/modules/course/examples/bar.occ:118: expected :, got ! kroc/modules/course/examples/bar.occ:118: unexpected token: ! kroc/modules/course/examples/bar.occ:118: unexpected token: ) kroc/modules/course/examples/bar.occ:123: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:124: unexpected token: ; kroc/modules/course/examples/bar.occ:124: unexpected token: INT kroc/modules/course/examples/bar.occ:125: unexpected token: : kroc/modules/course/examples/bar.occ:125: unexpected token: : kroc/modules/course/examples/bar.occ:128: unexpected token: ; kroc/modules/course/examples/bar.occ:128: expected :, got NEWLINE kroc/modules/course/examples/bar.occ:129: unexpected token: : kroc/modules/course/examples/bar.occ:129: unexpected token: : kroc/modules/course/examples/bar.occ:130: unexpected token: ; kroc/modules/course/examples/bar.occ:130: unexpected token: ( kroc/modules/course/examples/bar.occ:130: expected :, got ) kroc/modules/course/examples/bar.occ:130: unexpected token: ) kroc/modules/course/examples/bar.occ:130: unexpected token: + kroc/modules/course/examples/bar.occ:131: unexpected token: : kroc/modules/course/examples/bar.occ:131: unexpected token: : kroc/modules/course/examples/bar.occ:132: unexpected token: ; kroc/modules/course/examples/bar.occ:133: unexpected token: : kroc/modules/course/examples/bar.occ:133: unexpected token: : kroc/modules/course/examples/bar.occ:134: unexpected token: : kroc/modules/course/examples/bar.occ:138: expected ), got CHAN kroc/modules/course/examples/bar.occ:138: expected :, got ! kroc/modules/course/examples/bar.occ:138: unexpected token: ! kroc/modules/course/examples/bar.occ:138: unexpected token: ) kroc/modules/course/examples/bar.occ:156: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:157: unexpected token: ; kroc/modules/course/examples/bar.occ:171: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:172: unexpected token: ; kroc/modules/course/examples/bar.occ:176: expected IDENT, got AFTER kroc/modules/course/examples/bar.occ:176: unexpected token: AFTER kroc/modules/course/examples/bar.occ:176: unexpected token: ( kroc/modules/course/examples/bar.occ:176: unexpected token: PLUS kroc/modules/course/examples/bar.occ:176: unexpected token: ) kroc/modules/course/examples/bar.occ:182: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:183: unexpected token: ; kroc/modules/course/examples/bar.occ:186: unexpected token: ; kroc/modules/course/examples/bar.occ:189: expected IDENT, got AFTER kroc/modules/course/examples/bar.occ:189: unexpected token: AFTER kroc/modules/course/examples/bar.occ:189: unexpected token: ( kroc/modules/course/examples/bar.occ:189: unexpected token: PLUS kroc/modules/course/examples/bar.occ:189: unexpected token: ) kroc/modules/course/examples/bar.occ:194: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:195: unexpected token: ; kroc/modules/course/examples/bar.occ:212: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:213: unexpected token: ; kroc/modules/course/examples/bar.occ:218: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:219: unexpected token: ; kroc/modules/course/examples/bar.occ:222: unexpected token: ; kroc/modules/course/examples/bar.occ:225: expected IDENT, got AFTER kroc/modules/course/examples/bar.occ:225: unexpected token: AFTER kroc/modules/course/examples/bar.occ:225: unexpected token: ( kroc/modules/course/examples/bar.occ:225: unexpected token: PLUS kroc/modules/course/examples/bar.occ:225: unexpected token: ) kroc/modules/course/examples/bar.occ:228: unexpected token: : kroc/modules/course/examples/bar.occ:232: expected ), got CHAN kroc/modules/course/examples/bar.occ:232: expected :, got ! kroc/modules/course/examples/bar.occ:232: unexpected token: ! kroc/modules/course/examples/bar.occ:232: unexpected token: , kroc/modules/course/examples/bar.occ:233: expected :, got ! kroc/modules/course/examples/bar.occ:233: unexpected token: ! kroc/modules/course/examples/bar.occ:233: unexpected token: , kroc/modules/course/examples/bar.occ:233: unexpected token in expression: ) kroc/modules/course/examples/bar.occ:252: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:254: unexpected token: : kroc/modules/course/examples/bar.occ:267: expected variant tag name, got BYTE kroc/modules/course/examples/bar.occ:267: expected variant tag name, got , kroc/modules/course/examples/bar.occ:267: expected variant tag name, got : kroc/modules/course/examples/bar.occ:270: expected variant tag name, got INT kroc/modules/course/examples/bar.occ:270: expected variant tag name, got : kroc/modules/course/examples/bar.occ:271: expected variant tag name, got : kroc/modules/course/examples/bar.occ:271: expected variant tag name, got : kroc/modules/course/examples/bar.occ:273: expected variant tag name, got INT kroc/modules/course/examples/bar.occ:273: expected variant tag name, got : kroc/modules/course/examples/bar.occ:278: expected variant tag name, got INT kroc/modules/course/examples/bar.occ:278: expected variant tag name, got : kroc/modules/course/examples/bar.occ:283: expected variant tag name, got INT kroc/modules/course/examples/bar.occ:283: expected variant tag name, got : kroc/modules/course/examples/bar.occ:288: expected variant tag name, got INT kroc/modules/course/examples/bar.occ:288: expected variant tag name, got : kroc/modules/course/examples/bar.occ:327: expected & after guard in ALT case kroc/modules/course/examples/bar.occ:338: expected & after guard in ALT case kroc/modules/course/examples/bar.occ:352: expected & after guard in ALT case kroc/modules/course/examples/bar.occ:363: expected ), got CHAN kroc/modules/course/examples/bar.occ:363: expected :, got ! kroc/modules/course/examples/bar.occ:363: unexpected token: ! kroc/modules/course/examples/bar.occ:363: unexpected token: , kroc/modules/course/examples/bar.occ:364: expected :, got ? kroc/modules/course/examples/bar.occ:364: unexpected token: ? kroc/modules/course/examples/bar.occ:364: unexpected token: ) kroc/modules/course/examples/bar.occ:373: expected IDENT, got AFTER kroc/modules/course/examples/bar.occ:373: unexpected token: AFTER kroc/modules/course/examples/bar.occ:373: unexpected token: ( kroc/modules/course/examples/bar.occ:373: unexpected token: PLUS kroc/modules/course/examples/bar.occ:373: unexpected token: ) kroc/modules/course/examples/bar.occ:375: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:376: unexpected token: ; kroc/modules/course/examples/bar.occ:378: unexpected token: ; kroc/modules/course/examples/bar.occ:389: unexpected token in expression: NEWLINE kroc/modules/course/examples/bar.occ:390: unexpected token: ; kroc/modules/course/examples/bar.occ:399: expected channel name or guard in ALT case, got ( kroc/modules/course/examples/bar.occ:399: unexpected token: NOT kroc/modules/course/examples/bar.occ:399: unexpected token: ) kroc/modules/course/examples/bar.occ:399: unexpected token: & kroc/modules/course/examples/bar.occ:399: expected IDENT, got AFTER kroc/modules/course/examples/bar.occ:399: unexpected token: AFTER kroc/modules/course/examples/bar.occ:402: unexpected token: & kroc/modules/course/examples/bar.occ:423: unexpected token: : kroc/modules/course/examples/bar.occ:428: expected ), got CHAN kroc/modules/course/examples/bar.occ:428: expected :, got ! kroc/modules/course/examples/bar.occ:428: unexpected token: ! kroc/modules/course/examples/bar.occ:428: unexpected token: , kroc/modules/course/examples/bar.occ:428: expected :, got ? kroc/modules/course/examples/bar.occ:428: unexpected token: ? kroc/modules/course/examples/bar.occ:428: unexpected token: ) kroc/modules/course/examples/bar.occ:441: unexpected token: : kroc/modules/course/examples/bar.occ:471: unexpected token in expression: CHAN kroc/modules/course/examples/bar.occ:471: unexpected token: : TRANSPILE: FAIL === cast === TRANSPILE: OK GO VET: OK === casting === TRANSPILE: OK GO VET: OK === commstime === TRANSPILE: OK GO VET: OK === demo === Parse errors: kroc/modules/course/examples/demo.occ:16: expected IDENT, got AFTER kroc/modules/course/examples/demo.occ:16: unexpected token: AFTER kroc/modules/course/examples/demo.occ:16: unexpected token: PLUS kroc/modules/course/examples/demo.occ:27: expected type after INITIAL, got IDENT kroc/modules/course/examples/demo.occ:27: unexpected token in expression: ] kroc/modules/course/examples/demo.occ:27: expected ], got INT kroc/modules/course/examples/demo.occ:27: expected ], got ? kroc/modules/course/examples/demo.occ:27: expected :, got ? kroc/modules/course/examples/demo.occ:27: unexpected token: ? kroc/modules/course/examples/demo.occ:27: unexpected token: ] kroc/modules/course/examples/demo.occ:27: expected IDENT, got : kroc/modules/course/examples/demo.occ:27: unexpected token: : kroc/modules/course/examples/demo.occ:35: expected type after array size, got NEWLINE TRANSPILE: FAIL === double_echo === TRANSPILE: OK GO VET: OK === echoing === TRANSPILE: OK GO VET: OK === hello_raw_world === TRANSPILE: OK GO VET: OK === hello_seq_world === TRANSPILE: OK GO VET: OK === hello_world === TRANSPILE: OK GO VET: OK === sort_inside === Parse errors: kroc/modules/course/examples/sort_inside.occ:309: expected type after array size, got NEWLINE kroc/modules/course/examples/sort_inside.occ:333: expected type after array size, got NEWLINE kroc/modules/course/examples/sort_inside.occ:336: expected type after array size, got NEWLINE TRANSPILE: FAIL === sort_inside_2 === Parse errors: kroc/modules/course/examples/sort_inside_2.occ:294: expected indented block after ALT kroc/modules/course/examples/sort_inside_2.occ:294: unexpected token: ? kroc/modules/course/examples/sort_inside_2.occ:323: expected IDENT, got AFTER kroc/modules/course/examples/sort_inside_2.occ:323: unexpected token: AFTER kroc/modules/course/examples/sort_inside_2.occ:323: unexpected token: PLUS TRANSPILE: FAIL === sort_pump === TRANSPILE: OK GO VET: OK === sort_pump_2 === TRANSPILE: OK GO VET: OK === test_bell === Parse errors: kroc/modules/course/examples/test_bell.occ:39: unexpected token: , kroc/modules/course/examples/test_bell.occ:39: unexpected token: BYTE_LIT kroc/modules/course/examples/test_bell.occ:41: unexpected token: ELSE kroc/modules/course/examples/test_bell.occ:77: unexpected token: , kroc/modules/course/examples/test_bell.occ:77: unexpected token: BYTE_LIT kroc/modules/course/examples/test_bell.occ:79: unexpected token: ELSE TRANSPILE: FAIL === test_utils === Parse errors: kroc/modules/course/examples/test_utils.occ:19: expected type after VAL, got [ kroc/modules/course/examples/test_utils.occ:19: unexpected token: INT kroc/modules/course/examples/test_utils.occ:19: unexpected token: ] kroc/modules/course/examples/test_utils.occ:75: expected ), got STRING kroc/modules/course/examples/test_utils.occ:75: unexpected token: STRING kroc/modules/course/examples/test_utils.occ:75: unexpected token: * kroc/modules/course/examples/test_utils.occ:75: unexpected token: STRING kroc/modules/course/examples/test_utils.occ:75: unexpected token: , kroc/modules/course/examples/test_utils.occ:75: unexpected token: INT kroc/modules/course/examples/test_utils.occ:75: unexpected token: , kroc/modules/course/examples/test_utils.occ:75: unexpected token in expression: ) TRANSPILE: FAIL
Great progress! Let me summarize the results:
Transpile OK + go vet OK (10/16): 1. hello_world.occ 2. hello_seq_world.occ 3. hello_raw_world.occ 4. echoing.occ 5. double_echo.occ 6. commstime.occ 7. cast.occ ← NEW (was FAIL) 8. casting.occ ← NEW (was FAIL) 9. sort_pump.occ ← NEW (was FAIL) 10. sort_pump_2.occ ← NEW (was FAIL)
Transpile FAIL (6/16): 1. bar.occ - still many issues 2. demo.occ - AFTER, MOBILE 3. sort_inside.occ - expression-sized arrays 4. sort_inside_2.occ - SIZE of direction-annotated name, AFTER 5. test_bell.occ - multi-value CASE labels 6. test_utils.occ - multi-dim arrays, string escape
We've jumped from 7 to 10 passing tests with the fixes for scoping issues, though there are still six files failing due to various language features like expression-sized arrays, multi-value case labels, and multi-dimensional array handling.
gh issue view 56 --json state,title -q '.state + " - " + .title' && gh issue view 57 --json state,title -q '.state + " - " + .title'
CLOSED - boolVars map is global: name collisions cause invalid Go code CLOSED - Channel array slices incompatible with direction-restricted params
Here's the updated picture. The recent fixes have made significant progress:
go vet| File | Transpile | go vet |
Status |
|---|---|---|---|
hello_world.occ |
OK | OK | |
hello_seq_world.occ |
OK | OK | |
hello_raw_world.occ |
OK | OK | |
echoing.occ |
OK | OK | |
double_echo.occ |
OK | OK | |
commstime.occ |
OK | OK | |
cast.occ |
OK | OK | Fixed by #56 (boolVars scoping) + #53 + #54 |
casting.occ |
OK | OK | Fixed by #56 + #53 + #54 |
sort_pump.occ |
OK | OK | Fixed by #55 (typed abbrev) + #57 (chan array dir) |
sort_pump_2.occ |
OK | OK | Fixed by #55 + #57 |
bar.occ |
FAIL | — | PRI ALT, SHARED/CLAIM, dotted protocol tags, AFTER, guarded ALT, multi-dim arrays |
demo.occ |
FAIL | — | tim ? AFTER, MOBILE |
sort_inside.occ |
FAIL | — | Expression-sized arrays ([expr]TYPE) |
sort_inside_2.occ |
FAIL | — | SIZE monitor?, tim ? AFTER |
test_bell.occ |
FAIL | — | Multi-value CASE labels |
test_utils.occ |
FAIL | — | Multi-dim arrays ([][n]TYPE), *" string escape |
go vetgo vetgo vetAll 4 files that were transpiling but failing go vet are now clean. The remaining 6 files all fail at parse time due to unimplemented language features.
| Feature | Files blocked | Difficulty |
|---|---|---|
tim ? AFTER expr |
demo.occ, sort_inside_2.occ, bar.occ |
Medium — needs parser + codegen for timer AFTER input |
Multi-value CASE labels ('*n', '*c') |
test_bell.occ |
Easy — extend CASE label parsing to accept comma-separated values |
Expression-sized arrays ([expr]TYPE) |
sort_inside.occ |
Medium — parser currently expects literal size |
SIZE monitor? (SIZE of direction-annotated name) |
sort_inside_2.occ |
Easy — strip direction suffix in SIZE expression |
Multi-dim arrays ([][n]TYPE) |
test_utils.occ, bar.occ |
Medium |
*" string escape |
test_utils.occ |
Easy — add escape sequence to lexer |
| PRI ALT / guarded ALT / SHARED/CLAIM / dotted protocol tags | bar.occ only |
Hard — bar.occ needs many features |
The easiest wins to unblock more files would be multi-value CASE labels (unblocks test_bell.occ) and tim ? AFTER (unblocks demo.occ and sort_inside_2.occ, partially unblocks bar.occ).
Thank you. Please add a comment to the main bug report with your latest findings then open a set of new issues to cover the remaining unimplemented features you've listed above.
The user wants me to: 1. Add a comment to issue #43 with the latest findings 2. Open new issues for the remaining unimplemented features
Let me first add the comment, then create the issues. I need to figure out which features already have issues and which need new ones. Looking at the original issue, some features already had dedicated issues (#44, #45, #46) but those are closed. Let me check what open issues exist.
43 OPEN Course examples: unimplemented features preventing transpilation 2026-02-23T03:26:24Z 40 OPEN Support KRoC mobile/shared channel extensions 2026-02-22T16:52:58Z
Good — #40 already covers SHARED/CLAIM and MOBILE. Let me add the comment and create the new issues.
gh issue comment 43 --body "$(cat <<'EOF' ## Status Update — After PRs #55, #56, #57, #58 Four codegen bugs have been fixed since the last update: - **boolVars scoping** (#56, closed) — scoped per proc/function body to prevent cross-proc leakage - **Channel array direction covariance** (#57, closed via `fix/chan-array-dir-params`) — direction dropped from `[]CHAN OF TYPE` params since Go slices are invariant - **Typed abbreviation type loss** (#55, closed) — already noted in previous update - **boolVars per-proc scoping** (#58, merged) — related follow-up to #56 ### Current results: 10/16 transpile, 10/16 pass `go vet` | File | Transpile | `go vet` | Remaining blockers | |------|-----------|----------|--------------------| | `hello_world.occ` | OK | OK | — | | `hello_seq_world.occ` | OK | OK | — | | `hello_raw_world.occ` | OK | OK | — | | `echoing.occ` | OK | OK | — | | `double_echo.occ` | OK | OK | — | | `commstime.occ` | OK | OK | — | | `cast.occ` | OK | **OK** | — *(was blocked by boolVars scoping)* | | `casting.occ` | OK | **OK** | — *(was blocked by boolVars scoping)* | | `sort_pump.occ` | OK | **OK** | — *(was blocked by chan array direction)* | | `sort_pump_2.occ` | OK | **OK** | — *(was blocked by chan array direction)* | | `bar.occ` | FAIL | — | PRI ALT, SHARED/CLAIM, dotted protocol tags, `tim ? AFTER`, guarded ALT, multi-dim arrays | | `demo.occ` | FAIL | — | `tim ? AFTER`, MOBILE | | `sort_inside.occ` | FAIL | — | Expression-sized arrays (`[expr]TYPE`) | | `sort_inside_2.occ` | FAIL | — | `SIZE monitor?`, `tim ? AFTER` | | `test_bell.occ` | FAIL | — | Multi-value CASE labels | | `test_utils.occ` | FAIL | — | Multi-dim arrays (`[][n]TYPE`), `*"` string escape | ### Changes from previous update - **Newly passing `go vet`:** `cast.occ`, `casting.occ`, `sort_pump.occ`, `sort_pump_2.occ` (4 new, 10 total) - **All codegen bugs from the previous update are resolved** — no files transpile but fail vet - **Still failing to parse:** 6 files (unchanged from previous update) ### Progress since issue was opened | Milestone | Transpile | `go vet` | |-----------|-----------|----------| | Original report | 5/16 | 5/16 | | After #44, #45, #46 | 10/16 | 6/16 | | After #53, #54, #55 | 10/16 | 7/16 | | **Current** (after #56, #57, #58) | **10/16** | **10/16** | ### Remaining work — new issues filed The remaining 6 files are all blocked at parse time by unimplemented language features. Individual issues have been filed: | Feature | Affected files | Issue | |---------|---------------|-------| | `tim ? AFTER expr` | `bar.occ`, `demo.occ`, `sort_inside_2.occ` | #59 | | Multi-value CASE labels | `test_bell.occ` | #60 | | Expression-sized arrays (`[expr]TYPE`) | `sort_inside.occ` | #61 | | `SIZE` of direction-annotated name | `sort_inside_2.occ` | #62 | | Multi-dimensional arrays (`[][n]TYPE`) | `bar.occ`, `test_utils.occ` | #63 | | `*"` string escape | `test_utils.occ` | #64 | | PRI ALT | `bar.occ` | #65 | | Guarded ALT with boolean conditions | `bar.occ` | #66 | | Dotted protocol tags | `bar.occ` | #67 | SHARED/CLAIM and MOBILE are tracked in #40. EOF )"
gh issue create --title "Support timer AFTER input (tim ? AFTER expr)" --body "$(cat <<'EOF' ## Summary Occam's `tim ? AFTER expr` construct waits until the timer value exceeds `expr`. This is used for timed delays and is distinct from `tim ? t` (which just reads the current time). ## Occam syntax ```occam TIMER tim: INT t: SEQ tim ? t -- read current time tim ? AFTER t PLUS delay -- wait until time passes t + delay ``` ## Proposed Go mapping ```go t = time.Now().UnixMicro() time.Sleep(time.Duration(t + delay - time.Now().UnixMicro()) * time.Microsecond) ``` Or possibly using `AFTER` comparison semantics (modular time comparison). ## Affected files - `bar.occ` (lines 176, 189, 225, 373) - `demo.occ` (line 16) - `sort_inside_2.occ` (line 323) ## Work required 1. **Parser**: Detect `AFTER` keyword after `?` in channel/timer input and parse the delay expression 2. **AST**: Add an `AfterExpr` field (or similar) to the input node 3. **Codegen**: Generate `time.Sleep(...)` or equivalent Part of #43. EOF )"
gh issue create --title "Support multi-value CASE labels" --body "$(cat <<'EOF'
## Summary
Occam CASE statements can have multiple comma-separated values on a single label. Currently only single-value labels are parsed.
## Occam syntax
```occam
CASE ch
'*n', '*c'
SKIP
ELSE
out ! ch
```
## Proposed Go mapping
```go
switch ch {
case '\n', '\r':
// SKIP
default:
out <- ch
}
```
## Affected files
- `test_bell.occ` (lines 39, 77)
## Work required
1. **Parser**: After parsing the first case value, check for comma and parse additional values
2. **AST**: Change `CaseOption.Value` from single expression to a list
3. **Codegen**: Emit comma-separated values in Go `case` clause
Part of #43.
EOF
)"gh issue create --title "Support expression-sized array declarations" --body "$(cat <<'EOF' ## Summary Occam allows array sizes to be arbitrary expressions (typically referencing variables or constants), not just integer literals. Currently the parser only accepts literal integers as array sizes. ## Occam syntax ```occam VAL INT max.delay IS 100: [max.delay]BYTE buffer: [total - 1]BYTE temp: ``` ## Proposed Go mapping ```go maxDelay := 100 buffer := make([]byte, maxDelay) temp := make([]byte, total - 1) ``` Since Go arrays require compile-time constant sizes, expression-sized arrays should map to slices via `make()`. ## Affected files - `sort_inside.occ` (lines 309, 333, 336) ## Work required 1. **Parser**: Parse the array size as a full expression instead of requiring an integer literal 2. **Codegen**: When array size is not a literal, generate `make([]type, expr)` instead of a fixed-size array Part of #43. EOF )"
gh issue create --title "Support SIZE of direction-annotated channel name" --body "$(cat <<'EOF'
## Summary
When a channel parameter has a direction annotation (e.g., `monitor?`), the `SIZE` operator should work on it by stripping the direction suffix. Currently `SIZE monitor?` fails to parse.
## Occam syntax
```occam
PROC foo([]CHAN OF INT monitor?)
SEQ i = 0 FOR SIZE monitor?
...
```
## Proposed Go mapping
```go
func foo(monitor []chan int) {
for i := 0; i < len(monitor); i++ {
...
}
}
```
The `?` suffix is purely a direction annotation and should be stripped when generating the `len()` call.
## Affected files
- `sort_inside_2.occ` (line 294)
## Work required
1. **Parser**: When parsing `SIZE`, handle the case where the operand identifier has a trailing `?` or `!` direction annotation
2. **Codegen**: Generate `len(name)` with the direction suffix stripped
Part of #43.
EOF
)"gh issue create --title "Support multi-dimensional arrays ([][n]TYPE)" --body "$(cat <<'EOF'
## Summary
Occam supports multi-dimensional arrays such as `[][2]BYTE` (open first dimension, fixed second) and `[n][m]TYPE` (both fixed). These are currently not parsed.
## Occam syntax
```occam
VAL [][2]BYTE pairs IS [['A', 'a'], ['B', 'b']]:
[10][20]INT grid:
```
## Proposed Go mapping
```go
var pairs = [][2]byte{{'A', 'a'}, {'B', 'b'}}
var grid [10][20]int
```
Or using slices for open dimensions:
```go
var pairs [][]byte = [][]byte{{'A', 'a'}, {'B', 'b'}}
```
## Affected files
- `bar.occ` (multi-dim array params/declarations)
- `test_utils.occ` (line 19: `VAL [][2]BYTE`)
## Work required
1. **Parser**: After parsing `[n]`, check for another `[` to handle nested array dimensions
2. **AST**: Extend array type representation to support multiple dimensions
3. **Codegen**: Generate nested Go array/slice types
Part of #43.
EOF
)"gh issue create --title 'Support *" string escape sequence' --body "$(cat <<'EOF'
## Summary
Occam uses `*"` inside string literals to represent a literal double-quote character. Currently the lexer does not handle this escape sequence, causing parse failures.
## Occam syntax
```occam
VAL []BYTE msg IS "He said *"hello*"":
```
## Proposed Go mapping
```go
var msg []byte = []byte("He said \"hello\"")
```
## Affected files
- `test_utils.occ` (line 75)
## Work required
1. **Lexer**: In string literal scanning, recognize `*"` as an escape sequence that produces a `"` character (rather than terminating the string)
This is a small addition to the existing occam escape sequence handling (`*n`, `*c`, `*t`, etc.).
Part of #43.
EOF
)"gh issue create --title "Support PRI ALT (prioritised alternation)" --body "$(cat <<'EOF'
## Summary
`PRI ALT` is a prioritised version of `ALT` where earlier guards have priority over later ones when multiple are ready simultaneously. Currently only `ALT` is supported.
## Occam syntax
```occam
PRI ALT
in ? x
... handle input
tim ? AFTER timeout
... handle timeout
```
## Proposed Go mapping
Go's `select` does not have built-in priority. Options:
1. **Simple approach**: Map `PRI ALT` to `select` (same as `ALT`), accepting the loss of priority semantics. Add a comment noting the limitation.
2. **Faithful approach**: Use nested `select` with `default` clauses to check higher-priority channels first.
## Affected files
- `bar.occ` (multiple PRI ALT blocks)
## Work required
1. **Lexer**: Recognize `PRI` keyword (if not already)
2. **Parser**: Parse `PRI ALT` as a variant of ALT
3. **AST**: Add a `Priority` flag to the ALT node
4. **Codegen**: Generate appropriate Go select construct
Part of #43.
EOF
)"gh issue create --title "Support guarded ALT with boolean pre-conditions" --body "$(cat <<'EOF'
## Summary
Occam ALT cases can have boolean guard pre-conditions using the `&` operator. A guard that evaluates to FALSE disables that ALT branch. Currently the parser does not support this syntax.
## Occam syntax
```occam
ALT
running & in ? x
... only considered if running is TRUE
(NOT paused) & tim ? AFTER timeout
... only considered if paused is FALSE
TRUE & stop ? any
... always considered
```
## Proposed Go mapping
```go
select {
case x = <-in: // wrap in: if running { ... }
case <-time.After(...): // wrap in: if !paused { ... }
case any = <-stop: // always active
}
```
For `reflect.Select`-based ALT replicators, disabled guards can be handled by setting the channel to `nil` (which makes a select case block forever, effectively disabling it).
## Affected files
- `bar.occ` (lines 327, 338, 352, 399, 402)
## Work required
1. **Parser**: Before parsing a channel input in ALT, check for `expr &` guard prefix
2. **AST**: Add a `Guard` expression field to ALT case nodes
3. **Codegen**: Conditionally enable/disable select cases based on guard value
Part of #43.
EOF
)"gh issue create --title "Support dotted protocol tags (e.g., bar.data)" --body "$(cat <<'EOF'
## Summary
Occam variant protocol tags can contain dots (e.g., `bar.data`, `bar.terminate`, `bar.blank`). Currently the parser treats the dot as a field access operator rather than part of the tag name.
## Occam syntax
```occam
PROTOCOL BAR.PROTO
CASE
bar.data ; INT ; BYTE
bar.terminate
bar.blank ; INT
:
```
## Proposed Go mapping
Dots in tag names would be replaced with underscores (consistent with `goIdent()`):
```go
type _proto_BAR_PROTO interface{ _tag_BAR_PROTO() }
type _proto_BAR_PROTO_bar_data struct { _0 int; _1 byte }
type _proto_BAR_PROTO_bar_terminate struct{}
type _proto_BAR_PROTO_bar_blank struct { _0 int }
```
## Affected files
- `bar.occ` (protocol declaration and usage throughout)
## Work required
1. **Parser**: When parsing protocol tag names, allow dotted identifiers (consume `IDENT.IDENT` as a single tag name)
2. **Codegen**: Use `goIdent()` to convert dots to underscores in generated Go identifiers
Part of #43.
EOF
)"I notice the issue numbers in my comment were placeholders (#59-#67) but the actual issues created are #60-#68. The timer AFTER issue got #60, not #59. Let me check and update the comment accordingly.
Wait, actually the first issue (timer AFTER) returned https://github.com/codeassociates/occam2go/issues/60, and the numbering went up to #68 for dotted protocol tags. But in my comment I referenced #59-#67. Let me check what #59 is.
Let me check the actual issue numbers that were assigned, since my comment referenced placeholders.
gh issue list --state open --limit 20 --json number,title -q '.[] | "#\(.number) \(.title)"'
#68 Support dotted protocol tags (e.g., bar.data) #67 Support guarded ALT with boolean pre-conditions #66 Support PRI ALT (prioritised alternation) #65 Support *" string escape sequence #64 Support multi-dimensional arrays ([][n]TYPE) #63 Support SIZE of direction-annotated channel name #62 Support expression-sized array declarations #61 Support multi-value CASE labels #60 Support timer AFTER input (tim ? AFTER expr) #43 Course examples: unimplemented features preventing transpilation #40 Support KRoC mobile/shared channel extensions
The issue numbers in my comment (#59–#67) are off by one — the actual numbers are #60–#68. Let me fix the comment.
gh issue comment 43 --edit-last --body "$(cat <<'EOF' ## Status Update — After PRs #55, #56, #57, #58 Four codegen bugs have been fixed since the last update: - **boolVars scoping** (#56, closed) — scoped per proc/function body to prevent cross-proc leakage - **Channel array direction covariance** (#57, closed via `fix/chan-array-dir-params`) — direction dropped from `[]CHAN OF TYPE` params since Go slices are invariant - **Typed abbreviation type loss** (#55, closed) — already noted in previous update - **boolVars per-proc scoping** (#58, merged) — related follow-up to #56 ### Current results: 10/16 transpile, 10/16 pass `go vet` | File | Transpile | `go vet` | Remaining blockers | |------|-----------|----------|--------------------| | `hello_world.occ` | OK | OK | — | | `hello_seq_world.occ` | OK | OK | — | | `hello_raw_world.occ` | OK | OK | — | | `echoing.occ` | OK | OK | — | | `double_echo.occ` | OK | OK | — | | `commstime.occ` | OK | OK | — | | `cast.occ` | OK | **OK** | — *(was blocked by boolVars scoping)* | | `casting.occ` | OK | **OK** | — *(was blocked by boolVars scoping)* | | `sort_pump.occ` | OK | **OK** | — *(was blocked by chan array direction)* | | `sort_pump_2.occ` | OK | **OK** | — *(was blocked by chan array direction)* | | `bar.occ` | FAIL | — | PRI ALT, SHARED/CLAIM, dotted protocol tags, `tim ? AFTER`, guarded ALT, multi-dim arrays | | `demo.occ` | FAIL | — | `tim ? AFTER`, MOBILE | | `sort_inside.occ` | FAIL | — | Expression-sized arrays (`[expr]TYPE`) | | `sort_inside_2.occ` | FAIL | — | `SIZE monitor?`, `tim ? AFTER` | | `test_bell.occ` | FAIL | — | Multi-value CASE labels | | `test_utils.occ` | FAIL | — | Multi-dim arrays (`[][n]TYPE`), `*"` string escape | ### Changes from previous update - **Newly passing `go vet`:** `cast.occ`, `casting.occ`, `sort_pump.occ`, `sort_pump_2.occ` (4 new, 10 total) - **All codegen bugs from the previous update are resolved** — no files transpile but fail vet - **Still failing to parse:** 6 files (unchanged from previous update) ### Progress since issue was opened | Milestone | Transpile | `go vet` | |-----------|-----------|----------| | Original report | 5/16 | 5/16 | | After #44, #45, #46 | 10/16 | 6/16 | | After #53, #54, #55 | 10/16 | 7/16 | | **Current** (after #56, #57, #58) | **10/16** | **10/16** | ### Remaining work — new issues filed The remaining 6 files are all blocked at parse time by unimplemented language features. Individual issues have been filed: | Feature | Affected files | Issue | |---------|---------------|-------| | `tim ? AFTER expr` | `bar.occ`, `demo.occ`, `sort_inside_2.occ` | #60 | | Multi-value CASE labels | `test_bell.occ` | #61 | | Expression-sized arrays (`[expr]TYPE`) | `sort_inside.occ` | #62 | | `SIZE` of direction-annotated name | `sort_inside_2.occ` | #63 | | Multi-dimensional arrays (`[][n]TYPE`) | `bar.occ`, `test_utils.occ` | #64 | | `*"` string escape | `test_utils.occ` | #65 | | PRI ALT | `bar.occ` | #66 | | Guarded ALT with boolean conditions | `bar.occ` | #67 | | Dotted protocol tags | `bar.occ` | #68 | SHARED/CLAIM and MOBILE are tracked in #40. EOF )"
Done. Here's what I posted:
Comment on #43 — Updated status showing 10/16 files now fully passing go vet (up from 5/16 when the issue was opened), with a progress timeline and links to all new issues.
9 new issues created:
| # | Feature | Easiest wins |
|---|---|---|
| #60 | tim ? AFTER expr (timer delay) |
Unblocks 3 files |
| #61 | Multi-value CASE labels | Unblocks test_bell.occ |
| #62 | Expression-sized arrays | Unblocks sort_inside.occ |
| #63 | SIZE of direction-annotated name |
Unblocks sort_inside_2.occ (with #60) |
| #64 | Multi-dimensional arrays | Unblocks test_utils.occ (with #65) |
| #65 | *" string escape |
Small lexer change |
| #66 | PRI ALT | bar.occ only |
| #67 | Guarded ALT with boolean conditions | bar.occ only |
| #68 | Dotted protocol tags | bar.occ only |
SHARED/CLAIM and MOBILE were already tracked in #40. The bar.occ file remains the hardest to unblock since it depends on 6+ features including the occam-pi extensions.
Thank you. Great work. One thing though: in the summary above you helpfully provided an assesment of the relative implementation difficulty of the remaining issues. However I don't see that difficulty information in either the main bug summary comment nor the newly opened issues. Apologies if it's there and I missed it. It would be useful to capture that information for future project planning.
You're right, that difficulty assessment didn't make it into the issues. Let me add it to the tracking comment and to each individual issue.
gh issue comment 43 --edit-last --body "$(cat <<'EOF' ## Status Update — After PRs #55, #56, #57, #58 Four codegen bugs have been fixed since the last update: - **boolVars scoping** (#56, closed) — scoped per proc/function body to prevent cross-proc leakage - **Channel array direction covariance** (#57, closed via `fix/chan-array-dir-params`) — direction dropped from `[]CHAN OF TYPE` params since Go slices are invariant - **Typed abbreviation type loss** (#55, closed) — already noted in previous update - **boolVars per-proc scoping** (#58, merged) — related follow-up to #56 ### Current results: 10/16 transpile, 10/16 pass `go vet` | File | Transpile | `go vet` | Remaining blockers | |------|-----------|----------|--------------------| | `hello_world.occ` | OK | OK | — | | `hello_seq_world.occ` | OK | OK | — | | `hello_raw_world.occ` | OK | OK | — | | `echoing.occ` | OK | OK | — | | `double_echo.occ` | OK | OK | — | | `commstime.occ` | OK | OK | — | | `cast.occ` | OK | **OK** | — *(was blocked by boolVars scoping)* | | `casting.occ` | OK | **OK** | — *(was blocked by boolVars scoping)* | | `sort_pump.occ` | OK | **OK** | — *(was blocked by chan array direction)* | | `sort_pump_2.occ` | OK | **OK** | — *(was blocked by chan array direction)* | | `bar.occ` | FAIL | — | PRI ALT, SHARED/CLAIM, dotted protocol tags, `tim ? AFTER`, guarded ALT, multi-dim arrays | | `demo.occ` | FAIL | — | `tim ? AFTER`, MOBILE | | `sort_inside.occ` | FAIL | — | Expression-sized arrays (`[expr]TYPE`) | | `sort_inside_2.occ` | FAIL | — | `SIZE monitor?`, `tim ? AFTER` | | `test_bell.occ` | FAIL | — | Multi-value CASE labels | | `test_utils.occ` | FAIL | — | Multi-dim arrays (`[][n]TYPE`), `*"` string escape | ### Changes from previous update - **Newly passing `go vet`:** `cast.occ`, `casting.occ`, `sort_pump.occ`, `sort_pump_2.occ` (4 new, 10 total) - **All codegen bugs from the previous update are resolved** — no files transpile but fail vet - **Still failing to parse:** 6 files (unchanged from previous update) ### Progress since issue was opened | Milestone | Transpile | `go vet` | |-----------|-----------|----------| | Original report | 5/16 | 5/16 | | After #44, #45, #46 | 10/16 | 6/16 | | After #53, #54, #55 | 10/16 | 7/16 | | **Current** (after #56, #57, #58) | **10/16** | **10/16** | ### Remaining work — new issues filed The remaining 6 files are all blocked at parse time by unimplemented language features. Individual issues have been filed, with estimated difficulty: | Feature | Affected files | Difficulty | Issue | |---------|---------------|------------|-------| | `tim ? AFTER expr` | `bar.occ`, `demo.occ`, `sort_inside_2.occ` | Medium — parser, AST, and codegen changes across timer input handling | #60 | | Multi-value CASE labels | `test_bell.occ` | Easy — extend case label parsing to accept comma-separated values | #61 | | Expression-sized arrays (`[expr]TYPE`) | `sort_inside.occ` | Medium — parser must accept expressions as array sizes; codegen must emit `make()` for non-literal sizes | #62 | | `SIZE` of direction-annotated name | `sort_inside_2.occ` | Easy — strip trailing `?`/`!` direction suffix when parsing SIZE operand | #63 | | Multi-dimensional arrays (`[][n]TYPE`) | `bar.occ`, `test_utils.occ` | Medium — parser, AST, and codegen must all support nested array dimensions | #64 | | `*"` string escape | `test_utils.occ` | Easy — small addition to existing escape sequence handling in the lexer | #65 | | PRI ALT | `bar.occ` | Medium — new keyword, AST flag, and codegen strategy (Go `select` has no native priority) | #66 | | Guarded ALT with boolean conditions | `bar.occ` | Medium — parser must handle `expr &` prefix on ALT cases; codegen must conditionally enable/disable select cases | #67 | | Dotted protocol tags | `bar.occ` | Easy — allow dotted identifiers in protocol tag positions; `goIdent()` already converts dots to underscores | #68 | SHARED/CLAIM and MOBILE are tracked in #40 (hard — significant language extension). ### Suggested implementation order Easiest wins first, maximizing files unblocked per effort: 1. **#61** (multi-value CASE) — easy, unblocks `test_bell.occ` 2. **#65** (`*"` escape) + **#64** (multi-dim arrays) — unblocks `test_utils.occ` 3. **#63** (SIZE direction) + **#60** (timer AFTER) — unblocks `sort_inside_2.occ` and `demo.occ` 4. **#62** (expression-sized arrays) — unblocks `sort_inside.occ` 5. **#68** (dotted tags) + **#67** (guarded ALT) + **#66** (PRI ALT) + **#40** (SHARED/CLAIM/MOBILE) — chipping away at `bar.occ` EOF )"
gh issue edit 60 --body "$(cat <<'EOF' **Difficulty: Medium** — Parser, AST, and codegen changes across timer input handling. ## Summary Occam's `tim ? AFTER expr` construct waits until the timer value exceeds `expr`. This is used for timed delays and is distinct from `tim ? t` (which just reads the current time). ## Occam syntax ```occam TIMER tim: INT t: SEQ tim ? t -- read current time tim ? AFTER t PLUS delay -- wait until time passes t + delay ``` ## Proposed Go mapping ```go t = time.Now().UnixMicro() time.Sleep(time.Duration(t + delay - time.Now().UnixMicro()) * time.Microsecond) ``` Or possibly using `AFTER` comparison semantics (modular time comparison). ## Affected files - `bar.occ` (lines 176, 189, 225, 373) - `demo.occ` (line 16) - `sort_inside_2.occ` (line 323) ## Work required 1. **Parser**: Detect `AFTER` keyword after `?` in channel/timer input and parse the delay expression 2. **AST**: Add an `AfterExpr` field (or similar) to the input node 3. **Codegen**: Generate `time.Sleep(...)` or equivalent Part of #43. EOF )"
gh issue edit 61 --body "$(cat <<'EOF'
**Difficulty: Easy** — Extend case label parsing to accept comma-separated values; small AST and codegen changes.
## Summary
Occam CASE statements can have multiple comma-separated values on a single label. Currently only single-value labels are parsed.
## Occam syntax
```occam
CASE ch
'*n', '*c'
SKIP
ELSE
out ! ch
```
## Proposed Go mapping
```go
switch ch {
case '\n', '\r':
// SKIP
default:
out <- ch
}
```
## Affected files
- `test_bell.occ` (lines 39, 77)
## Work required
1. **Parser**: After parsing the first case value, check for comma and parse additional values
2. **AST**: Change `CaseOption.Value` from single expression to a list
3. **Codegen**: Emit comma-separated values in Go `case` clause
Part of #43.
EOF
)"gh issue edit 62 --body "$(cat <<'EOF' **Difficulty: Medium** — Parser must accept expressions as array sizes; codegen must emit `make()` for non-literal sizes since Go arrays require compile-time constants. ## Summary Occam allows array sizes to be arbitrary expressions (typically referencing variables or constants), not just integer literals. Currently the parser only accepts literal integers as array sizes. ## Occam syntax ```occam VAL INT max.delay IS 100: [max.delay]BYTE buffer: [total - 1]BYTE temp: ``` ## Proposed Go mapping ```go maxDelay := 100 buffer := make([]byte, maxDelay) temp := make([]byte, total - 1) ``` Since Go arrays require compile-time constant sizes, expression-sized arrays should map to slices via `make()`. ## Affected files - `sort_inside.occ` (lines 309, 333, 336) ## Work required 1. **Parser**: Parse the array size as a full expression instead of requiring an integer literal 2. **Codegen**: When array size is not a literal, generate `make([]type, expr)` instead of a fixed-size array Part of #43. EOF )"
gh issue edit 63 --body "$(cat <<'EOF'
**Difficulty: Easy** — Strip trailing `?`/`!` direction suffix when parsing SIZE operand.
## Summary
When a channel parameter has a direction annotation (e.g., `monitor?`), the `SIZE` operator should work on it by stripping the direction suffix. Currently `SIZE monitor?` fails to parse.
## Occam syntax
```occam
PROC foo([]CHAN OF INT monitor?)
SEQ i = 0 FOR SIZE monitor?
...
```
## Proposed Go mapping
```go
func foo(monitor []chan int) {
for i := 0; i < len(monitor); i++ {
...
}
}
```
The `?` suffix is purely a direction annotation and should be stripped when generating the `len()` call.
## Affected files
- `sort_inside_2.occ` (line 294)
## Work required
1. **Parser**: When parsing `SIZE`, handle the case where the operand identifier has a trailing `?` or `!` direction annotation
2. **Codegen**: Generate `len(name)` with the direction suffix stripped
Part of #43.
EOF
)"gh issue edit 64 --body "$(cat <<'EOF'
**Difficulty: Medium** — Parser, AST, and codegen must all support nested array dimensions.
## Summary
Occam supports multi-dimensional arrays such as `[][2]BYTE` (open first dimension, fixed second) and `[n][m]TYPE` (both fixed). These are currently not parsed.
## Occam syntax
```occam
VAL [][2]BYTE pairs IS [['A', 'a'], ['B', 'b']]:
[10][20]INT grid:
```
## Proposed Go mapping
```go
var pairs = [][2]byte{{'A', 'a'}, {'B', 'b'}}
var grid [10][20]int
```
Or using slices for open dimensions:
```go
var pairs [][]byte = [][]byte{{'A', 'a'}, {'B', 'b'}}
```
## Affected files
- `bar.occ` (multi-dim array params/declarations)
- `test_utils.occ` (line 19: `VAL [][2]BYTE`)
## Work required
1. **Parser**: After parsing `[n]`, check for another `[` to handle nested array dimensions
2. **AST**: Extend array type representation to support multiple dimensions
3. **Codegen**: Generate nested Go array/slice types
Part of #43.
EOF
)"gh issue edit 65 --body "$(cat <<'EOF'
**Difficulty: Easy** — Small addition to existing escape sequence handling in the lexer.
## Summary
Occam uses `*"` inside string literals to represent a literal double-quote character. Currently the lexer does not handle this escape sequence, causing parse failures.
## Occam syntax
```occam
VAL []BYTE msg IS "He said *"hello*"":
```
## Proposed Go mapping
```go
var msg []byte = []byte("He said \"hello\"")
```
## Affected files
- `test_utils.occ` (line 75)
## Work required
1. **Lexer**: In string literal scanning, recognize `*"` as an escape sequence that produces a `"` character (rather than terminating the string)
This is a small addition to the existing occam escape sequence handling (`*n`, `*c`, `*t`, etc.).
Part of #43.
EOF
)"gh issue edit 66 --body "$(cat <<'EOF'
**Difficulty: Medium** — New keyword, AST flag, and codegen strategy needed. Go `select` has no native priority semantics, so a faithful implementation requires nested selects with `default` clauses or a similar workaround.
## Summary
`PRI ALT` is a prioritised version of `ALT` where earlier guards have priority over later ones when multiple are ready simultaneously. Currently only `ALT` is supported.
## Occam syntax
```occam
PRI ALT
in ? x
... handle input
tim ? AFTER timeout
... handle timeout
```
## Proposed Go mapping
Go's `select` does not have built-in priority. Options:
1. **Simple approach**: Map `PRI ALT` to `select` (same as `ALT`), accepting the loss of priority semantics. Add a comment noting the limitation.
2. **Faithful approach**: Use nested `select` with `default` clauses to check higher-priority channels first.
## Affected files
- `bar.occ` (multiple PRI ALT blocks)
## Work required
1. **Lexer**: Recognize `PRI` keyword (if not already)
2. **Parser**: Parse `PRI ALT` as a variant of ALT
3. **AST**: Add a `Priority` flag to the ALT node
4. **Codegen**: Generate appropriate Go select construct
Part of #43.
EOF
)"gh issue edit 67 --body "$(cat <<'EOF'
**Difficulty: Medium** — Parser must handle `expr &` prefix on ALT cases; codegen must conditionally enable/disable select cases (e.g., by setting channels to `nil` when the guard is false).
## Summary
Occam ALT cases can have boolean guard pre-conditions using the `&` operator. A guard that evaluates to FALSE disables that ALT branch. Currently the parser does not support this syntax.
## Occam syntax
```occam
ALT
running & in ? x
... only considered if running is TRUE
(NOT paused) & tim ? AFTER timeout
... only considered if paused is FALSE
TRUE & stop ? any
... always considered
```
## Proposed Go mapping
```go
select {
case x = <-in: // wrap in: if running { ... }
case <-time.After(...): // wrap in: if !paused { ... }
case any = <-stop: // always active
}
```
For `reflect.Select`-based ALT replicators, disabled guards can be handled by setting the channel to `nil` (which makes a select case block forever, effectively disabling it).
## Affected files
- `bar.occ` (lines 327, 338, 352, 399, 402)
## Work required
1. **Parser**: Before parsing a channel input in ALT, check for `expr &` guard prefix
2. **AST**: Add a `Guard` expression field to ALT case nodes
3. **Codegen**: Conditionally enable/disable select cases based on guard value
Part of #43.
EOF
)"gh issue edit 68 --body "$(cat <<'EOF'
**Difficulty: Easy** — Allow dotted identifiers in protocol tag positions. `goIdent()` already converts dots to underscores, so codegen should need minimal changes.
## Summary
Occam variant protocol tags can contain dots (e.g., `bar.data`, `bar.terminate`, `bar.blank`). Currently the parser treats the dot as a field access operator rather than part of the tag name.
## Occam syntax
```occam
PROTOCOL BAR.PROTO
CASE
bar.data ; INT ; BYTE
bar.terminate
bar.blank ; INT
:
```
## Proposed Go mapping
Dots in tag names would be replaced with underscores (consistent with `goIdent()`):
```go
type _proto_BAR_PROTO interface{ _tag_BAR_PROTO() }
type _proto_BAR_PROTO_bar_data struct { _0 int; _1 byte }
type _proto_BAR_PROTO_bar_terminate struct{}
type _proto_BAR_PROTO_bar_blank struct { _0 int }
```
## Affected files
- `bar.occ` (protocol declaration and usage throughout)
## Work required
1. **Parser**: When parsing protocol tag names, allow dotted identifiers (consume `IDENT.IDENT` as a single tag name)
2. **Codegen**: Use `goIdent()` to convert dots to underscores in generated Go identifiers
Part of #43.
EOF
)"All done. Each of the 9 issues (#60–#68) now has a Difficulty line at the top of its body (Easy/Medium), and the tracking comment on #43 has been updated with a difficulty column in the table plus a suggested implementation order that prioritizes easy wins that unblock the most files.
You're welcome! Good progress overall — 10/16 fully passing is a solid milestone, and the remaining work is well-mapped out now.