CREXX

REXX Language implementation

View the Project on GitHub adesutherland/CREXX

crexx Debugging Workflow

When investigating compiler bugs, follow this exact workflow to isolate the issue:

1. The Build Step

Always ensure the compiler is built before testing. Command: cmake --build cmake-build-debug (or standard cmake build dir).

2. AST Verification (-d2)

If a bug involves parsing, scoping, or grammar logic, dump the AST. Command: ./rxc -d2 <test_file.rexx> Analysis: Look at the tree output to ensure the Lemon parser (compiler/rxcpbgmr.y or rxcpopgr.y) pushed and popped scopes correctly and attached the right variable nodes.

3. Symbol Table / IR Verification (-d3)

If the AST is correct but the emitted assembly is wrong, dump the compiler internals. Command: ./rxc -d3 <test_file.rexx> Analysis: Trace the variable lifecycle and verify the register allocation before it hits the rxas assembler.

4. Running the Code

To test end-to-end execution:

  1. Compile: ./rxc test.crexx (produces test.rxas)
  2. Assemble: ./rxas test.rxas (produces test.rxbin)
  3. Execute: ./rxvm test.rxbin

CTest Result Contracts

Do not use PASS_REGULAR_EXPRESSION to represent an expected process failure. CMake deliberately ignores an ordinary nonzero exit code when that property matches. Expected-negative runtime tests must use the checked runtime helpers in cmake/CrexxLinkedRuntime.cmake, specifying the exact nonzero exit code, required output, forbidden output, and a concise failure description. A valid negative test prints, for example:

EXPECTED FAILURE: SIGNAL ERROR at bytecode address 15, exit code 3; test passed

The crexx_expected_failure_contract CTest proves that the assertion helper accepts the specified failure and rejects unexpected success. Existing positive tests that still use PASS_REGULAR_EXPRESSION are covered by the serialized ctest_pass_regex_exit_contract: their normal registration validates output, and the contract independently executes them and requires exit code zero. This audit intentionally adds time to a full CTest sweep and prevents a matched success marker from masking a later process failure.

Verbose CTest output also lists CREXX_DIAGNOSTICS=raw for compiler tests. That is the deterministic machine-readable diagnostic mode used by golden tests, not an error indication.

5. RXPP And Source-Map Diagnostics

For .rxpp problems, split the pipeline before changing compiler C code:

  1. Run rxpp directly and inspect the generated .crexx.
  2. RXPP emits options ... srcmap by default. Compile the generated file with rxc --diagnostics raw and check for SRCMAP_MALFORMED or SRCMAP_UNBALANCED before debugging normal parser/validator behavior.
  3. Confirm literal @ is escaped as @@ in default srcmap mode. Only explicit ##CFLAG nosrcmap output should preserve literal @ unchanged.
  4. For macro diagnostics, check whether the innermost generated token is inside a nested @...{ ... @} span. rxc intentionally chooses the narrowest enclosing source-map span.

Focused coverage:

ctest --test-dir cmake-build-release -R 'rxc_srcmap|rxpp_(smoke|srcmap|diagnostics|diagnostic_catalogs)' --output-on-failure

See docs/ai-context/RXPP_PREPROCESSOR.md for the marker syntax and component layout. For RXPP warning/error text, set CREXX_DIAGNOSTICS=raw to inspect the stable RXPP_* code and parameters before checking localized wording.

6. Isolating Assembler Keyhole Optimiser Bugs

If generated .rxas looks correct but the .rxbin or disassembly looks wrong, compare assembler output with and without the keyhole optimiser:

./rxas -n -o test_noopt test.rxas
./rxas -o test_opt test.rxas
./rxdas -o test_noopt.dis test_noopt.rxbin
./rxdas -o test_opt.dis test_opt.rxbin
diff -u test_noopt.dis test_opt.dis

rxc -n disables compiler optimisation when compiling source REXX. rxas -n specifically disables the assembler keyhole optimiser. Use rxas -n when the assembly input is already known and the question is whether peephole rules, instruction-flow metadata, or hidden register-use handling changed the bytecode incorrectly.

7. RXDB Trace Debugger

debugger/rxdb.crexx is the early Level B debugger prototype. It now delegates source lookup, ASM instruction decoding, module/procedure lookup, breakpoint enable/disable, and default trace filtering to rxfnsb.trace classes:

Debugger presentation lives outside the runtime library in debugger/rxdb_gui.crexx, which exposes .rxdbtextgui for banners, prompts, ANSI cursor control, and plain text output.

The default rxdb UI still uses ANSI cursor control. For log-friendly or LLM-readable output, run:

rxdb llm

text and plain are accepted aliases. The text mode is intentionally a small prototype surface for debugging the trace runtime without escape sequences. llm mode batches Enter-driven stepping in groups of 50 trace events and prints that policy in the banner and running prompt.

RXDB is experimental for the Release 1 beta line. Keep automated coverage to a small launch/usage smoke test until the debugger command model and UI contract are promoted into release scope.

The certified TRACE compiler exit also has a log-friendly TRACE LLM mode. It writes escaped JSON-lines-style records through the trace runtime and can be combined with TO STDERR or TO FILE expr when debugger automation needs a separate trace stream.

See docs/ai-context/CREXX_TRACE_REQUIREMENTS.md for the TRACE compatibility target, current implementation status, output formats, and enhancement roadmap.

Keep watch-value reads in the interrupt handler unless the VM exposes a frame-safe abstraction: metalinkpreg must inspect the interrupted child frame, and moving that operation behind an ordinary method call changes the frame being linked. The shared rxfnsb.trace controller should own metadata lookup and target selection; generated/debugger handlers should limit themselves to the unavoidable frame-local register link and then hand the value back to the shared trace runtime.

8. High-Risk Compiler Change Checklist

For broad compiler work such as new source syntax, type-system changes, metadata changes, reference/value ownership, or inliner behaviour, treat the work as a staged pipeline change rather than a single parser patch.

Process lessons:

Reference source-syntax lessons:

Useful focused commands from the reference source slice:

cmake --build cmake-build-debug --target rxc rxas rxvm library compiler_exit_bin crexx_test_driver
ctest --test-dir cmake-build-debug -R 'reference_source_' --output-on-failure
ctest --test-dir cmake-build-debug -R 'reference_(iterator|generated|source)|type_ops|arg_semantics_(scalar|array|object)|object_reference_regression|inline_test_ref_|inline_ref_array_count|inline_test_block_expr_live_sibling' --output-on-failure
cmake --build cmake-build-asan --target rxc rxas rxvm library crexx_test_driver
ctest --test-dir cmake-build-asan -R 'reference_source_|reference_(iterator|generated)' --output-on-failure

9. Known Build and Platform Issues

When encountering unusual build or execution errors on new platforms (e.g., macOS ARM, Windows), keep these documented issues in mind: