REXX Language implementation
Level B is statically typed. Every expression has a type known to the compiler, and assignments, arguments, returns, method calls, and factory calls are checked against those types.
The built-in Level B value types are:
| Type | Purpose |
|---|---|
.void |
No usable value. Used for procedures that do not return a value. |
.boolean |
Boolean truth value. |
.int |
Integer value. |
.float |
Binary floating-point value unless the source uses decimal float options. |
.decimal |
Decimal numeric value. |
.string |
Character string value. |
.binary |
Binary byte sequence. |
.object |
Object value. Interfaces and classes are object-shaped contracts. |
The canonical integer spelling in source is .int.
Type names can be used as constructors:
count = .int(0)
name = .string("Ada")
ok = .boolean(1)
payload = .binary()
Class and interface names also use the dotted form. A factory call creates an object through the selected class or interface provider:
item = .cacheentry("abc")
asset = .asset("log.txt")
Namespace-qualified contracts use a double dot:
client = .net..httpclient("example.com", 443, 1)
The left side of namespace..symbol must name an imported namespace.
namespace::symbol remains accepted as a compatibility alias.
Arrays are declared from a base type:
words = .string[]
numbers = .int[10]
grid = .int[10, 10]
window = .int[0 to 10]
grow = .int[-2 to *]
An array value carries its element type and dimensions. Procedure signatures can accept arrays in the same way:
main: procedure = .int
arg args = .string[]
Level B supports integer, float, and decimal arithmetic. The file-level
options instruction selects the parser’s arithmetic standard, and a
procedure-level numeric instruction can set numeric context such as digits,
form, fuzz, case, and standard.
The compiler performs type validation before bytecode emission. Numeric conversions are explicit where precision or representation could otherwise be surprising:
i = .int(42)
f = .float(i)
d = .decimal("42.50")
.string values are character data. .binary values are byte data. Keep the
two distinct when working with sockets, files, encodings, or native payloads:
string operations are text operations, while binary operations preserve bytes.
Classes and interfaces are object contracts. A concrete class instance can be assigned to an interface it implements:
shape = .box()
Level B supports:
expr is .type for boolean type testsexpr as .type for checked caststypeof(expr) for concrete type introspectionObjects can also carry native payloads when exposed through the plugin API, but ordinary Level B code should interact with objects through factories, methods, and interfaces.
The compiler infers a variable type from the first binding in many common cases:
total = 0 /* .int */
label = "ready" /* .string */
Use explicit constructors or declarations when the intended type is not obvious from the initializer, when a signature is being published, or when a value must be an object or array contract.