Claude Code transcript - page 1/2

Please take another look at progress on issue #43 in light of the recent fixes for generated golang validity problems.

Thinking

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.

$ Bash
View issue #43 details
gh issue view 43
$ Bash
Recent commits on main
git log --oneline -20 main
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
$ Bash
View issue #43 comments
gh issue view 43 --comments
$ Bash
Commits on current branch not in main
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` |
--
235652f Drop direction from channel array params to fix Go slice covariance issue
Thinking

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.

$ Bash
Build the transpiler
go build -o occam2go .
$ Bash
List all course example files
ls kroc/modules/course/examples/*.occ
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
$ Bash
Transpile all 16 examples and run go vet
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
Thinking

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.

$ Bash
Check status of issues #56 and #57
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:

Current results: 10/16 transpile, 10/16 pass 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

Summary of progress since the issue was opened

  • Originally: 5/16 transpile, 5/16 pass go vet
  • After #44, #45, #46: 10/16 transpile, 6/16 pass go vet
  • After #53, #54, #55, #56, #57/current branch: 10/16 transpile, 10/16 pass go vet

All 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.

Remaining blockers for the final 6 files

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.

Thinking

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.

$ Bash
Check existing open issues
gh issue list --state open --limit 20
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.

$ Bash
Add status comment to issue #43
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
)"
https://github.com/codeassociates/occam2go/issues/43#issuecomment-3942479073

Now let me create the individual issues. I'll create them in parallel batches.

$ Bash
Create issue: timer AFTER input
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
)"
$ Bash
Create issue: multi-value CASE labels
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
)"
$ Bash
Create issue: expression-sized arrays
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
)"
$ Bash
Create issue: SIZE of direction-annotated name
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
)"
$ Bash
Create issue: multi-dim arrays
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
)"
$ Bash
Create issue: *" string escape
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
)"
$ Bash
Create issue: PRI ALT
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
)"
$ Bash
Create issue: guarded ALT
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
)"
$ Bash
Create issue: dotted protocol tags
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
)"
https://github.com/codeassociates/occam2go/issues/60
https://github.com/codeassociates/occam2go/issues/61
https://github.com/codeassociates/occam2go/issues/62
https://github.com/codeassociates/occam2go/issues/63
https://github.com/codeassociates/occam2go/issues/64
https://github.com/codeassociates/occam2go/issues/65
https://github.com/codeassociates/occam2go/issues/66
https://github.com/codeassociates/occam2go/issues/67
https://github.com/codeassociates/occam2go/issues/68
Thinking

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.

$ Bash
List all open issues with numbers
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.

$ Bash
Fix issue numbers in 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
)"
https://github.com/codeassociates/occam2go/issues/43#issuecomment-3942479073

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.

$ Bash
Update comment with difficulty and implementation order
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
)"
https://github.com/codeassociates/occam2go/issues/43#issuecomment-3942479073

Now let me add difficulty labels to each individual issue.

$ Bash
Add difficulty to #60
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
)"
https://github.com/codeassociates/occam2go/issues/60
$ Bash
Add difficulty to #61
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
)"
https://github.com/codeassociates/occam2go/issues/61
$ Bash
Add difficulty to #62
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
)"
https://github.com/codeassociates/occam2go/issues/62
$ Bash
Add difficulty to #63
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
)"
https://github.com/codeassociates/occam2go/issues/63
$ Bash
Add difficulty to #64
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
)"
https://github.com/codeassociates/occam2go/issues/64
$ Bash
Add difficulty to #65
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
)"
$ Bash
Add difficulty to #66
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
)"
$ Bash
Add difficulty to #67
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
)"
$ Bash
Add difficulty to #68
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
)"
https://github.com/codeassociates/occam2go/issues/65
https://github.com/codeassociates/occam2go/issues/66
https://github.com/codeassociates/occam2go/issues/67
https://github.com/codeassociates/occam2go/issues/68

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.

Thank you!

You're welcome! Good progress overall — 10/16 fully passing is a solid milestone, and the remaining work is well-mapped out now.

Caveat: The messages below were generated by the user while running local commands. DO NOT respond to these messages or otherwise consider them in your response unless the user explicitly asks you to.