REXX Language implementation
Use this guide when you need to write or edit .rexx in this repository.
Generic training data about “REXX” is often too vague, too classic-Rexx
oriented, or simply wrong for cREXX Level B as it exists in this tree.
This guide is intentionally grounded in code that already compiles here. When in doubt, copy the nearest repo pattern instead of inventing syntax.
For Level B authoring, these sources are more reliable than model memory:
docs/ai-context/CREXX_ARCHITECTURE.mddocs/ai-context/CREXX_LIBS.mddocs/books/crexx_language_reference/classes_and_interfaces.mddocs/books/crexx_language_reference/data_types.mddocs/books/crexx_language_reference/statements.md.rexx files in lib/, bin/, compiler/exits/, debugger/, and tests/Use explicit options levelb, a namespace, and an exposed symbol:
options levelb
namespace rxfnsb expose abs
abs: procedure = .string
arg number = .string
if left(number,1) = '-' then number = substr(number,2)
return number
Reference:
lib/rxfnsb/rexx/abs.rexxSmall scripts can use top-level arg directly instead of a main: routine:
options levelb
import rxfnsb
arg searches = .string[]
if searches.0 < 1 then searches.1 = ".rexx"
ordered_searches = .string[]
address cmd "sort" input searches output ordered_searches
References:
tests/demo/countlines.rexxcompiler/exits/address/test_address.rexxLonger tools often use main: plus procedure expose for module state:
options levelb
namespace rxdb expose stephandler
import rxfnsb
import globals
main: procedure = .int expose next_instruction last_instruction mode
arg cmd_line = .string[]
Reference:
debugger/rxdb.rexxWhen you really need caller-owned state, use arg expose ...:
pushidentifier: procedure = .int
arg expose tokens = .token[], text = .string, value_type = ".unknown"
index = tokens[0] + 1
tokens[index] = .token(...)
return index
Reference:
compiler/exits/ExitTestSupport.rexxIn this repo, typed procedures and typed arg declarations are the normal
Level B style. Do not default to untyped classic-Rexx-looking code when you
are editing standard libraries, tools, exits, or tests.
Common examples in-tree:
procedure = .intprocedure = .stringprocedure = .token[]arg name = .stringarg cmd_line = .string[]arg expose tokens = .token[]References:
lib/rxfnsb/rexx/abs.rexxdebugger/rxdb.rexxcompiler/exits/ExitTestSupport.rexxtests/levelbfunc.rexxDo not treat namespace use as documentation sugar. It is part of how source is validated, imported, and linked.
Important points:
namespace and import clauses are real inputs to compilationnamespace..symbol is the canonical qualified-reference formnamespace::symbol is accepted as a compatibility alias, but do not prefer it.. must be an imported namespaceReferences:
docs/ai-context/CREXX_ARCHITECTURE.mddocs/books/crexx_programming_guide/intralanguage.mddocs/books/crexx_language_reference/classes_and_interfaces.mdThe compiler does a lightweight pre-scan of the leading options,
namespace, and import clauses before full parsing. Preserve that structure
when editing existing files.
Practical guidance:
options levelb near the topnamespace and import in the leading header blockReference:
docs/ai-context/CREXX_ARCHITECTURE.mddocs/books/crexx_programming_guide/rxc.mdIf a module declares namespace-exposed globals, Level B automatically binds
them into local procedure scopes. Do not add procedure expose ... just out
of habit when a namespace-exposed module global is what you actually want.
Use procedure expose or arg expose when:
rxdbReferences:
docs/ai-context/CREXX_ARCHITECTURE.mddocs/books/crexx_programming_guide/global_variables.mddebugger/rxdb.rexxDo not reason about them as loose classic stem variables only.
Patterns used in-tree:
items = .string[]items[0] for countitems[1] for first elementitems.1 is also used in older codeReferences:
tests/demo/countlines.rexxcompiler/exits/ExitTestSupport.rexxdocs/books/crexx_language_reference/data_types.mdUse *: factory or name: factory; do not write = .type on a factory. The
factory result is inferred from the owning contract: an interface factory
returns that interface and a class factory returns that concrete class. In a
class factory, bare return returns the constructed object, so there is no
source-level this value to mention.
vehicle: interface
*: factory
arg name = .string
describe: method = .string
car: class implements .vehicle
_name = .string
*: factory
arg name = .string
_name = name
return
describe: method = .string
return _name
Reference:
docs/books/crexx_language_reference/classes_and_interfaces.mdaddress command is the standard shell-out patternWhen Level B code shells out, copy the repo pattern instead of inventing a new API shape:
out = .string[]
err = .string[]
address command "echo #42" output out error err
if rc <> 0 then say "command failed"
References:
compiler/exits/address/test_address.rexxbin/crexx.rexxtests/demo/countlines.rexxdo groupsBlock-scoped signal handling is written with on signal clauses on a simple
do ... end group:
do
risky_work()
on signal conversion_error as problem
say problem.source()
on signal
call cleanup()
end
Do not attach on signal directly to counted, conditional, forever, or
expression-form do loops. To protect part of a loop, nest a simple
signal-handling do ... end group inside the loop body.
If as name is omitted, the handler has no local signal object. That is fine
for fixed cleanup/logging handlers.
References:
docs/books/crexx_language_reference/statements.mddocs/ai-context/LEVELB_SIGNALS_TRACE_WORKING.mdcompiler/exits/signal/test_signal_block.rexxThe crexx driver can compile simple headerless top-level scripts with
synthetic defaults (--level levelb --import rxfnsb). That is useful for end
users, but repo code should usually stay explicit with options levelb and
imports unless there is a strong reason not to.
Reference:
docs/books/crexx_language_reference/tools.mddocs/books/crexx_programming_guide/crexx.mdLevel B programs receive command-line arguments through arg, and when the
compiler synthesizes the file-level main() wrapper, the VM argv payload is
available there as a .string[].
Program-side guidance:
arg fn = .string[] (or a typed equivalent)fn.0 / fn[0] for the countfn.1..fn.fn.0main, model it on in-tree patterns such as arg cmd_line = .string[]Launcher-side guidance:
crexx or rxvm
invocation syntaxReferences:
docs/books/crexx_language_reference/arguments.mddocs/ai-context/CREXX_ARCHITECTURE.mddebugger/rxdb.rexxtests/demo/countlines.rexxlib/rxfnsb/rexx/abs.rexxlib/rxfnsb/rexx/fileio.rexxlib/rxfnsb/rexx/regex.rexxtests/demo/countlines.rexxbin/crexx.rexxcompiler/exits/address/test_address.rexxdebugger/rxdb.rexxcompiler/exits/ExitTestSupport.rexxcompiler/exits/address/Address.rexxcompiler/exits/parse/Parse.rexxtests/levelbfunc.rexxcompiler/exits/ExitTestSupport.rexxdocs/books/crexx_programming_guide/global_variables.mddocs/books/crexx_programming_guide/global_procedures.mddocs/books/crexx_language_reference/arguments.mddebugger/rxdb.rexxtests/demo/countlines.rexxWhen writing Level B code:
.rexx examples before editing.namespace..symbol qualification.If a proposed snippet does not resemble existing repo code in lib/,
debugger/, compiler/exits/, bin/, or tests/, stop and verify it before
committing it.