Basic Syntax
Basic Syntax
Fundamental language constructs and variable management in RexxJS Rexx.
Variable Management
Variable Assignment
LET variable = value
LET result = functionName param=value
Examples:
LET name = "John"
LET age = 30
LET total = calculateTax amount=100 rate=0.08
Variable Substitution
Variables are automatically resolved in function parameters and expressions:
LET base = 10
LET multiplier = 3
LET result = base + multiplier * 4 -- Evaluates to 22
createMeal potatoes=base*2 chicken=result/5
Operations vs Functions
RexxJS distinguishes between two types of callable code:
Operations (Imperative Commands)
Operations are side-effect actions called without parentheses:
-- Load a library with operations
REQUIRE "cwd:libs/bathhouse.js"
-- Operations: imperative commands (no parentheses)
SERVE_GUEST guest="river_spirit" bath="herbal"
CLEAN_BATHHOUSE area="main_hall" intensity="deep"
ISSUE_TOKEN worker="chihiro" task="cleaning"
Characteristics:
- ❌ No parentheses in call syntax
- ✅ Named parameters only (passed as object)
- ✅ Used for state changes and side effects
- ❌ Cannot be used in expressions or pipes
- ✅ Loaded via REQUIRE alongside functions
Functions (Expressions)
Functions are pure/query operations called with parentheses:
-- Functions: expressions (with parentheses, return values)
LET capacity = BATHHOUSE_CAPACITY()
LET count = COUNT_TOKENS()
LET spirit = IDENTIFY_SPIRIT(description="muddy")
-- String functions
LET upper = UPPER(string="hello world")
LET length = LENGTH(string=upper)
-- Math functions
LET maximum = MAX(x=10, y=25, z=15)
LET absolute = ABS(value=-42)
-- Utility functions
LET today = DATE()
LET timestamp = NOW()
Characteristics:
- ✅ Always use parentheses (even if no params)
- ✅ Support both positional AND named parameters
- ✅ Can be used in expressions, assignments, pipes
- ✅ Parameters converted via parameter-converter
- ✅ Work with pipe operator:
data |> FUNC(param=val)
Named vs Positional Parameters
Functions support both parameter styles interchangeably:
-- Positional parameters
LET sub1 = SUBSTR("hello world", 7, 5) -- "world"
LET spirit1 = IDENTIFY_SPIRIT("muddy") -- "river_spirit"
-- Named parameters
LET sub2 = SUBSTR(start=7, length=5) -- Works with piped data
LET spirit2 = IDENTIFY_SPIRIT(description="hungry") -- "no_face"
-- Named parameters in pipes
LET result = "hello world" |> SUBSTR(start=7, length=5) -- "world"
LET cleaned = " text " |> STRIP() |> SUBSTR(start=2, length=3) -- "ext"
Parameter Conversion:
- The parameter-converter translates named params to positional args
- Functions like
SUBSTR,POS,WORDPOSdesigned for data-first piping - Piped value becomes first argument, named params fill remaining positions
Parameter Types
Functions support multiple parameter types:
-- Strings (quoted)
DOM_TYPE(selector="#input", text="Hello World")
-- Numbers (unquoted)
LET result = MATH_POWER(base=2, exponent=10)
-- Booleans
LET valid = IS_EMAIL(email="user@example.com")
-- Expressions
LET calculated = MAX(x=base*2, y=multiplier+5, z=10)
Mathematical Expressions
Full Arithmetic Support
- Basic Operators:
+,-,*,/ - Operator Precedence: Proper mathematical precedence
- Parentheses Support:
(expression)for grouping - Variable Integration: Use variables in expressions
Examples:
LET base = 10
LET multiplier = 3
LET result = base + multiplier * 4 -- Evaluates to 22
LET withParens = (base + multiplier) * 4 -- Evaluates to 52
-- In function parameters
createMeal potatoes=base*2 chicken=result/5
-- In loop ranges
DO i = 1 TO result/4
prepareDish servings=i*2+1
END
Pipe Operator
Function Chaining with |>
The pipe operator |> enables elegant left-to-right data flow by passing the result of one expression as the first argument to the next function:
-- Basic piping
LET result = "hello" |> UPPER()
-- Equivalent to: UPPER(string="hello")
-- Result: "HELLO"
-- Multi-stage pipeline
LET cleaned = " hello world " |> TRIM() |> UPPER() |> LENGTH()
-- Equivalent to: LENGTH(string=UPPER(string=TRIM(string=" hello world ")))
-- Result: 11
-- Piping with named parameters
LET words = "a,b,c" |> SPLIT(separator=",")
-- Equivalent to: SPLIT(string="a,b,c", separator=",")
-- Result: ["a", "b", "c"]
-- Named parameters in chained pipes
LET result = "hello world" |> SUBSTR(start=7, length=5)
-- Piped value becomes first arg, named params fill rest
-- Equivalent to: SUBSTR(string="hello world", start=7, length=5)
-- Result: "world"
-- Complex pipeline with named parameters
LET processed = " hello " |> STRIP() |> SUBSTR(start=2, length=3)
-- Result: "ell"
Complex Data Transformations
The pipe operator excels at building readable data transformation pipelines:
-- String processing pipeline
LET text = " HELLO WORLD "
LET result = text |> TRIM |> LOWER |> SPLIT separator=" " |> ARRAY_LENGTH
-- Result: 2
-- Combining arithmetic and piping
LET value = 5 + 3 |> ABS |> MATH_POWER exponent=2
-- Evaluates: (5 + 3) = 8, then ABS(8) = 8, then MATH_POWER(8, 2) = 64
-- Array processing
LET data = "apple,banana,cherry"
LET count = data |> SPLIT separator="," |> ARRAY_LENGTH
-- Result: 3
Operator Precedence
The pipe operator has the lowest precedence of all operators, meaning arithmetic expressions are evaluated first:
LET result = 10 * 2 |> ABS
-- Evaluates as: (10 * 2) |> ABS = 20 |> ABS = 20
LET value = 5 + 3 |> UPPER
-- ❌ Error: (5 + 3) = 8, then UPPER(8) - numbers can't be uppercased
-- Use parentheses to control precedence
LET text = ("Hello" |> UPPER) || " World"
-- Result: "HELLO World"
Pipe-Friendly Functions
Functions where data is the first parameter work naturally with piping:
String Functions (see String Functions):
UPPER,LOWER,TRIM,REVERSE,LENGTHSLUG,WORD_FREQUENCY,SENTIMENT_ANALYSIS
Array Functions (see Array Functions):
ARRAY_LENGTH,ARRAY_REVERSE,ARRAY_UNIQUE,ARRAY_FLATTENARRAY_MIN,ARRAY_MAX,ARRAY_SUM,ARRAY_AVERAGE
Encoding Functions (see Web Functions):
BASE64_ENCODE,BASE64_DECODEURL_ENCODE,URL_DECODE
Validation Functions (see Validation Functions):
IS_EMAIL,IS_URL,IS_NUMBER,IS_INTEGER
String Concatenation vs Addition
Important: RexxJS follows strict REXX semantics for operators:
-- ✅ Arithmetic addition (numeric operands only)
LET sum = 100 + 11 -- Result: 111
LET total = "50" + "25" -- Result: 75 (automatic numeric coercion)
-- ❌ String concatenation with + is NOT supported
LET text = "Hello" + " World" -- Error: "Hello" is not a number
-- ✅ Use || for string concatenation
LET greeting = "Hello" || " World" -- Result: "Hello World"
LET fullName = firstName || " " || lastName
-- Combining pipes and concatenation
LET result = "hello" |> UPPER || " WORLD"
-- Result: "HELLO WORLD"
Best Practices
Use pipes for readability:
-- ❌ Hard to read (nested function calls)
LET result = ARRAY_LENGTH array=SPLIT string=TRIM string=UPPER string=text separator=" "
-- ✅ Easy to read (left-to-right flow)
LET result = text |> UPPER |> TRIM |> SPLIT separator=" " |> ARRAY_LENGTH
Multi-line pipelines for clarity:
-- Format complex pipelines across multiple lines
LET result = rawData
|> TRIM
|> LOWER
|> SPLIT separator=","
|> ARRAY_UNIQUE
|> ARRAY_LENGTH
Know when NOT to use pipes:
-- Functions where data is NOT the first parameter
LET position = POS needle="world" haystack="hello world" -- Can't pipe efficiently
-- Simple single function calls
LET upper = UPPER string="hello" -- No need for pipe here
String Interpolation
Variable Interpolation in Strings
Use {variable} syntax for dynamic string content:
LET mealName = 'Special Dinner'
LET guest = 'VIP'
-- Basic interpolation
prepareDish name="Today's {mealName}" servings=4
-- Multiple variables
LET greeting = "Welcome {firstName} {lastName}"
-- Complex variable paths
LET status = "Current stock: {stock.quantity} units"
Configurable Interpolation Patterns
RexxJS supports multiple interpolation patterns that can be switched globally:
-- Default RexxJS pattern: {variable} (default)
LET name = "Alice"
SAY "Hello {name}"
-- Switch to Handlebars pattern:
INTERPOLATION HANDLEBARS
SAY "Hello "
-- Switch to Shell pattern: ${variable}
INTERPOLATION SHELL
SAY "Hello ${name}"
-- Switch to Batch pattern: %variable%
INTERPOLATION BATCH
SAY "Hello %name%"
-- Reset to default
INTERPOLATION DEFAULT
Available Patterns:
DEFAULTorREXX:{variable}(default)HANDLEBARS: ``SHELL:${variable}BATCH:%variable%CUSTOM:$$variable$$BRACKETS:[variable]
Creating Custom Interpolation Patterns
INTERPOLATION PATTERN Statement
Create custom interpolation patterns with the INTERPOLATION PATTERN statement:
-- Syntax: INTERPOLATION PATTERN name=NAME start="delimiter" end="delimiter"
INTERPOLATION PATTERN name=ANGLES start="<<" end=">>"
INTERPOLATION PATTERN name=PIPES start="|" end="|"
INTERPOLATION PATTERN name=RUBY start="#{" end="}"
Using Custom Patterns
After defining a custom pattern, switch to it using the pattern name:
-- Define custom pattern
INTERPOLATION PATTERN name=ANGLES start="<<" end=">>"
-- Switch to the custom pattern
INTERPOLATION ANGLES
LET user = "Bob"
SAY "User: <<user>>" -- Outputs: User: Bob
-- Define and use another pattern
INTERPOLATION PATTERN name=PIPES start="|" end="|"
INTERPOLATION PIPES
SAY "Status: |user| is active" -- Outputs: Status: Bob is active
-- Switch back to default
INTERPOLATION DEFAULT
SAY "Back to {user}" -- Outputs: Back to Bob
Custom Pattern Examples
-- Ruby-style interpolation
INTERPOLATION PATTERN name=RUBY start="#{" end="}"
INTERPOLATION RUBY
LET count = 5
SAY "Found #{count} items" -- Outputs: Found 5 items
-- Angle bracket style
INTERPOLATION PATTERN name=XML start="<%" end="%>"
INTERPOLATION XML
LET title = "Welcome"
SAY "<%title%> to our site" -- Outputs: Welcome to our site
-- Double pipe style
INTERPOLATION PATTERN name=WIKI start="||" end="||"
INTERPOLATION WIKI
LET page = "HomePage"
SAY "Visit ||page|| for more info" -- Outputs: Visit HomePage for more info
Pattern Validation
Custom patterns must:
- Have unique names (case-insensitive)
- Use non-empty start and end delimiters
- Not conflict with existing pattern names
-- ✅ Valid custom patterns
INTERPOLATION PATTERN name=CUSTOM1 start="@@" end="@@"
INTERPOLATION PATTERN name=SPECIAL start="<?" end="?>"
-- ❌ Invalid patterns (will cause errors)
INTERPOLATION PATTERN name=DEFAULT start="[" end="]" -- Reserved name
INTERPOLATION PATTERN name=EMPTY start="" end="]" -- Empty delimiter
Interpolation Features
- Complex Variable Paths:
{object.property}notation - Missing Variable Handling: Placeholder preserved if variable not found
- Control Flow Integration: Works within IF/DO/SELECT statements
- Numeric Variable Support: Automatic string conversion
- Pattern Switching: Change delimiters globally with
INTERPOLATIONstatement - Custom Delimiters: Create your own patterns with
INTERPOLATION PATTERN
HEREDOC Strings
Multi-line String Literals
Use HEREDOC syntax for multi-line content with custom delimiters:
LET content = <<DELIMITER
Multi-line content
can span several lines
and preserve formatting
DELIMITER
JSON Auto-parsing
When the delimiter contains “JSON” (case-insensitive), the content is automatically parsed as JSON:
-- ✅ Auto-parsed as JavaScript object
LET user = <<JSON
{
"name": "Alice Smith",
"age": 30,
"settings": {
"theme": "dark",
"notifications": true
}
}
JSON
-- Now you can access properties directly
LET userName = user.name -- "Alice Smith"
LET userTheme = user.settings.theme -- "dark"
JSON Auto-parsing Rules:
- Delimiter matching: Contains “json”, “JSON”, “Json”, “MYJSON”, etc.
- Content validation: Must be valid JSON starting with
{or[ - Fallback behavior: Invalid JSON remains as string
- Array support: JSON arrays are parsed as JavaScript arrays
Examples:
-- ✅ These delimiters trigger JSON parsing
LET config = <<JSON
{"theme": "dark"}
JSON
LET data = <<json
["item1", "item2", "item3"]
json
LET settings = <<CONFIGJSON
{"enabled": true, "timeout": 5000}
CONFIGJSON
-- ❌ These remain as strings
LET text = <<DATA
{"not": "parsed"}
DATA
LET content = <<CONFIG
{"stays": "as string"}
CONFIG
Use Cases
- Configuration files: Store complex settings as JSON
- API responses: Handle JSON data from web services
- Test data: Define structured test fixtures
- Templates: Multi-line content with dynamic variables
Escape Sequences
JavaScript-Style Escape Sequences
RexxJS supports JavaScript-style escape sequences in all quoted strings. This is a modern extension that breaks from classic REXX, which doesn’t support these escape sequences.
Supported Escape Sequences:
| Sequence | Character | Unicode | Example | Output |
|---|---|---|---|---|
\n |
Newline | U+000A | "line1\nline2" |
line1 line2 |
\t |
Tab | U+0009 | "col1\tcol2" |
col1 col2 |
\r |
Carriage Return | U+000D | "before\rafter" |
after |
\b |
Backspace | U+0008 | "text\bspace" |
texspace |
\f |
Form Feed | U+000C | "page1\fpage2" |
page1\fpage2 |
\v |
Vertical Tab | U+000B | "line1\vline2" |
line1\vline2 |
\0 |
Null Character | U+0000 | "before\0after" |
before(null)after |
\' |
Single Quote | U+0027 | "It\'s" |
It’s |
\" |
Double Quote | U+0022 | "Say \"hi\"" |
Say “hi” |
\\ |
Backslash | U+005C | "C:\\path" |
C:\path |
\uXXXX |
Unicode (4-digit) | Any | "\u0041" |
A |
\uXXXXXXXX |
Unicode (8-digit) | Any | "\u0001F600" |
😀 |
Usage Examples
Basic Escape Sequences:
-- Newlines for multi-line strings
LET message = "Line 1\nLine 2\nLine 3"
SAY message
-- Output:
-- Line 1
-- Line 2
-- Line 3
-- Tabs for formatting
LET table = "Name\tAge\nAlice\t30\nBob\t25"
SAY table
-- Output:
-- Name Age
-- Alice 30
-- Bob 25
-- Escaped quotes
LET quoted = "She said \"Hello\""
SAY quoted
-- Output: She said "Hello"
Unicode Escapes:
-- 4-digit Unicode (Basic Multilingual Plane)
LET greek = "Alpha: \u03B1, Beta: \u03B2"
SAY greek
-- Output: Alpha: α, Beta: β
-- 8-digit Unicode (extended planes, for emoji)
LET emoji = "Smile: \u0001F600, Love: \u0001F60D"
SAY emoji
-- Output: Smile: 😀, Love: 😍
-- Mathematical symbols
LET math = "Plus-Minus: \u00B1, Multiply: \u00D7, Divide: \u00F7"
SAY math
-- Output: Plus-Minus: ±, Multiply: ×, Divide: ÷
Escape Sequences in Different Contexts:
-- In SAY statements
SAY "Direct SAY with Unicode: \u0041\u0042\u0043"
-- Output: Direct SAY with Unicode: ABC
-- In variable assignments
LET text = "Newline test\n\u0041\u0042"
SAY text
-- Output: Newline test
-- AB
-- In function parameters
LET length = LENGTH("hello\nworld")
-- Result: 11 (5 + 1 newline + 5)
-- In concatenation
LET result = "Part1\t" || "Part2"
SAY result
-- Output: Part1 Part2
-- In conditionals
IF "text\nhere" = "text\nhere" THEN
SAY "Match"
ENDIF
-- Output: Match
Important Notes
- Escape sequences work everywhere: assignments, SAY statements, function parameters, concatenation operators
- Both single and double quotes supported:
"string with escapes"and'string with escapes' - Invalid Unicode escapes are preserved: If hex digits are invalid (e.g.,
\uGGGG), the backslash-u is kept as-is - Incomplete Unicode escapes: If there aren’t enough hex digits, the escape remains literal (e.g.,
\u12stays as\u12) - Modern extension: This feature is not part of classic REXX and is a RexxJS-specific enhancement for modern string handling
Comments
Comment Syntax
Lines starting with -- or // are comments:
-- This is a comment (traditional REXX style)
// This is also a comment (C/JavaScript style)
LET value = 10 -- End of line comment
LET another = 20 // Also an end of line comment
-- Multi-line comments with --
-- can span multiple lines
-- for detailed explanations
// Multi-line comments with //
// are also supported
// using the same approach
Both comment styles are supported for developer convenience:
--: Traditional REXX comment syntax//: C/C++/JavaScript style comments for familiarity
Application Addressing
ADDRESS Statement
Direct function calls to specific applications:
-- Switch target application
ADDRESS calculator
add x=10 y=32
-- Switch to another service
ADDRESS kitchen
prepareDish name="Pasta" servings=4
-- Switch back to calculator
ADDRESS calculator
display message="Calculation complete"
See also: Application Addressing for detailed cross-application communication patterns.