ADDRESS MATCHING Patterns
ADDRESS MATCHING Patterns
Comprehensive reference for ADDRESS MATCHING pattern syntax and usage in RexxJS.
Overview
ADDRESS MATCHING extends the Application Addressing system with regex-based line matching that takes precedence over normal REXX parsing. This enables natural domain-specific languages, structured test frameworks, and configuration DSLs within ADDRESS contexts.
ADDRESS Routing Methods
All ADDRESS contexts support multiple ways to send commands to target handlers:
ADDRESS MATCHING MULTILINE (New)
Syntax: ADDRESS target MATCHING MULTILINE "pattern"
Processing: Collects matching lines and sends as single multiline string
Use Case: SQL statements, Python code, shell scripts spanning multiple lines
ADDRESS Routing Methods (Complete List)
All ADDRESS contexts support multiple ways to send commands to target handlers:
| Method | Syntax | Processing | Use Case |
|---|---|---|---|
| MATCHING MULTILINE | ADDRESS target MATCHING MULTILINE("regex") |
Collect matching lines → Single handler call | Multi-line SQL, Python, scripts |
| MATCHING Pattern | ADDRESS target MATCHING("regex") |
Regex test → Handler | DSLs, Test frameworks |
| LINES Capture | ADDRESS target LINES(n) |
Capture n lines → Handler | Block commands, Scripts |
| Inline String | ADDRESS target "command"ADDRESS target 'command'ADDRESS target \command`` |
Direct → Handler | Single commands |
| Multiline String | ADDRESS target"command" (or 'command', `command`) |
Direct → Handler | Formatted commands |
| HEREDOC Block | ADDRESS target <<EOFcontentEOF |
Direct → Handler | Multi-line content |
| Function Calls | ADDRESS targetfunctionCall() |
REXX Parse → Handler | API calls |
Processing Order (Precedence)
- MATCHING MULTILINE patterns (when active) - Collect matching lines until non-match
- MATCHING patterns (when active) - Override all other parsing
- LINES capture (when active) - Capture specified number of lines
- Quoted strings - Immediate execution, bypass REXX parsing
- HEREDOC blocks - Multi-line immediate execution
- Function calls - Normal REXX parsing, routed if function call
- Other statements - Normal REXX processing (not sent to target)
Quick Reference
-- Basic syntax
ADDRESS targetName MATCHING MULTILINE("regex_pattern") -- NEW: Collect multiline blocks
ADDRESS targetName MATCHING("regex_pattern")
ADDRESS targetName LINES(number)
-- Multiline patterns (NEW)
ADDRESS sqlite3 MATCHING MULTILINE("^ (.*)") -- SQL statements
ADDRESS python MATCHING MULTILINE("^ (.*)") -- Python code
ADDRESS system MATCHING MULTILINE("^ (.*)") -- Shell scripts
-- Single-line patterns
ADDRESS EXPECTATIONS MATCHING("^[ \\t]*\\. (.*)$") -- Test assertions
ADDRESS logger MATCHING("^[ \\t]*# (.*)$") -- Comments
ADDRESS validator MATCHING("^[ \\t]*CHECK: (.*)$") -- Validation
ADDRESS processor MATCHING("^[ \\t]*> (.*)$") -- Commands
-- Lines capture examples
ADDRESS script LINES(3) -- Capture next 3 lines
ADDRESS config LINES(5) -- Capture next 5 lines
ADDRESS batch LINES(10) -- Capture next 10 lines
Detailed ADDRESS Routing Examples
1. MATCHING Pattern (Highest Precedence)
ADDRESS EXPECTATIONS MATCHING("^[ \\t]*\\. (.*)$")
. {result} should equal 42 -- Sent to EXPECTATIONS handler
LET normal = "assignment" -- Normal REXX (not sent to handler)
. {status} should be "success" -- Sent to EXPECTATIONS handler
When: Active MATCHING pattern exists
Processing: Line tested against regex first, sent to handler if matches
Handler receives: Content from first capture group (or full match)
2. LINES Capture (Block Processing)
ADDRESS script LINES(3)
LET name = "Alice" -- Captured (line 1)
SAY "Hello {name}" -- Captured (line 2)
LET count = LENGTH string=name -- Captured (line 3)
SAY "Continuing normally" -- Normal REXX execution resumes
When: LINES(n) specified with positive number
Processing: Next n raw source lines captured directly, bypassing REXX parsing
Handler receives: Combined multi-line string of raw source lines
LINES Capture Examples
Basic Variable Assignments:
LET data = "test"
ADDRESS config LINES(2)
LET server_host = "{data}.example.com"
LET server_port = 8080
SAY "Configuration sent to handler"
Handler receives: "LET server_host = \"{data}.example.com\"\nLET server_port = 8080"
Mixed Command Types:
ADDRESS batch LINES(4)
LET user = "alice"
SAY "Processing user: {user}"
LET result = UPPER string=user
LET status = "processed"
-- Normal execution continues here
Handler receives raw source lines: "LET user = \"alice\"\nSAY \"Processing user: {user}\"\nLET result = UPPER string=user\nLET status = \"processed\""
Script Generation:
LET template = "deployment"
ADDRESS generator LINES(5)
LET script_name = "{template}_deploy.sh"
SAY "#!/bin/bash"
SAY "echo 'Starting {template}'"
SAY "docker run myapp:{template}"
SAY "echo 'Deployment complete'"
Handler receives: "LET script_name = \"{template}_deploy.sh\"\nSAY \"#!/bin/bash\"\nSAY \"echo 'Starting {template}'\"\nSAY \"docker run myapp:{template}\"\nSAY \"echo 'Deployment complete'\""
LINES vs MATCHING Precedence
-- MATCHING takes precedence over LINES
ADDRESS test MATCHING("^TEST: (.*)$")
ADDRESS test LINES(2) -- LINES setting ignored, MATCHING still active
TEST: This goes to handler -- Matched by MATCHING pattern
LET x = 42 -- Normal REXX execution
-- Switch to LINES mode
ADDRESS test LINES(2)
LET first = 1 -- Captured (line 1)
LET second = 2 -- Captured (line 2)
SAY "Normal execution" -- Normal REXX execution resumes
3. Inline String (Direct Execution)
ADDRESS calculator "clear; press 5; press +; press 3; press =" -- Double quotes
ADDRESS calculator 'clear; press 5; press +; press 3; press =' -- Single quotes
ADDRESS calculator `clear; press 5; press +; press 3; press =` -- Backticks
-- All three quote types work identically, immediately executed, bypasses all REXX parsing
When: Quoted string on same line as ADDRESS (any quote type: ", ', `)
Processing: Direct execution via executeQuotedString()
Handler receives: Exact string content
3. Multiline String (Formatted Commands)
-- All three quote types work identically for multiline strings
ADDRESS api
"{\"method\": \"POST\", \"data\": {\"user\": \"alice\", \"action\": \"login\"}}"
ADDRESS api
'{"method": "GET", "endpoint": "/users"}'
ADDRESS api
`{"method": "PUT", "data": {"status": "active"}}`
When: Quoted string on line following ADDRESS (any quote type: ", ', `)
Processing: Direct execution, bypasses REXX parsing
Handler receives: Complete formatted string (JSON, XML, etc.)
4. HEREDOC Block (Multi-line Content)
ADDRESS templating <<HTML
<div class="user-card">
<h2>{user_name}</h2>
<p>Status: {user_status}</p>
<button>Contact {user_name}</button>
</div>
HTML
When: HEREDOC syntax used
Processing: Multi-line content sent as single string
Handler receives: Complete block with preserved formatting
5. Function Calls (Normal REXX Parsing)
ADDRESS calculator
clear -- Sent to calculator.clear()
press button="5" -- Sent to calculator.press("5")
LET result = getDisplay -- Sent to calculator.getDisplay(), result stored
SAY "Result: " || result -- Normal REXX (not sent to calculator)
When: No MATCHING active, normal REXX function call syntax
Processing: Standard REXX parsing, function calls routed to ADDRESS target
Handler receives: Function name and parameters
Precedence Demonstration
-- Setup: MATCHING pattern active
ADDRESS logger MATCHING("^[ \\t]*LOG: (.*)$")
LOG: System startup -- Method 1: MATCHING (highest precedence)
"Direct log entry" -- Method 3: Quoted string (bypasses MATCHING)
logMessage text="Function call" -- Method 6: Function call (normal parsing)
LET local = "not sent" -- Normal REXX (not sent to logger)
-- Clear MATCHING pattern
ADDRESS logger
"Another direct entry" -- Method 3: Quoted string
logMessage text="Function call" -- Method 6: Function call
Quote Type Support
All Three Quote Types Supported
ADDRESS string commands support double quotes ("), single quotes ('), and backticks (`) interchangeably:
-- All these are functionally identical:
ADDRESS target "command string"
ADDRESS target 'command string'
ADDRESS target `command string`
-- Multiline versions also identical:
ADDRESS target
"multiline command"
ADDRESS target
'multiline command'
ADDRESS target
`multiline command`
Quote Nesting and Escaping
Different quote types enable flexible content handling:
-- Use single quotes to contain double quotes
ADDRESS logger 'Log entry: "User login successful"'
-- Use double quotes to contain single quotes
ADDRESS logger "Error: Can't connect to database"
-- Use backticks to contain both quote types
ADDRESS formatter `Template: "Hello {name}", message: 'Welcome!'`
-- JSON content examples
ADDRESS api '{"message": "Hello world", "status": "active"}'
ADDRESS api `{"user": "alice", "action": "login", "details": "User's session"}`
Parser Implementation
- Regex pattern:
/^ADDRESS\s+(\w+)\s+(["’])(.*?)\2$/i` - Quote matching: Opening quote type must match closing quote type
- No escaping needed: Different quote types naturally handle nesting
- Identical processing: All quote types use same
executeQuotedString()path
Pattern Syntax Rules
1. Precedence over Parsing
- MATCHING patterns take precedence over all normal REXX parsing
- Lines matching the pattern bypass function call and assignment parsing
- Non-matching lines are parsed normally
2. Capture Group Processing
-- First capture group becomes processed content
MATCHING("^[ \\t]*\\. (.*)$")
. result should equal 42 -- Sends: "result should equal 42"
-- No capture groups sends full matched portion
MATCHING("^[ \\t]*\\.")
. result should equal 42 -- Sends: ". result should equal 42"
-- Multiple capture groups uses first
MATCHING("^[ \\t]*TEST\\((\\w+)\\): (.*)$")
TEST(high): Fix bug -- Sends: "high" (not "Fix bug")
3. Flexible Whitespace Handling
-- ALWAYS account for indentation
MATCHING("^[ \\t]*pattern") -- GOOD: Handles spaces/tabs
MATCHING("^pattern") -- AVOID: Fails with indentation
4. Regex Escaping
-- Escape special regex characters
MATCHING("^[ \\t]*\\. (.*)$") -- Literal dot
MATCHING("^[ \\t]*\\[TEST\\] (.*)$") -- Literal brackets
MATCHING("^[ \\t]*\\* (.*)$") -- Literal asterisk
Common Pattern Examples
Test Framework Patterns
-- Dot-prefix assertions (most common)
ADDRESS EXPECTATIONS MATCHING("^[ \\t]*\\. (.*)$")
. result should equal 42
. name should equal "John"
-- Named test patterns
ADDRESS testRunner MATCHING("^[ \\t]*TEST: (.*)$")
TEST: user login should succeed
TEST: invalid email should fail
-- Bracketed test markers
ADDRESS validator MATCHING("^[ \\t]*\\[VERIFY\\] (.*)$")
[VERIFY] password meets requirements
[VERIFY] email format is valid
Logging and Documentation
-- Hash-style comments
ADDRESS logger MATCHING("^[ \\t]*# (.*)$")
# Starting database connection
# Processing user records
# Backup completed successfully
-- Arrow-style commands
ADDRESS processor MATCHING("^[ \\t]*> (.*)$")
> initialize system
> load configuration
> start services
Configuration DSL Patterns
-- Key-value configuration
ADDRESS config MATCHING("^[ \\t]*(\\w+):\\s+(.*)$")
database: postgresql://localhost:5432/app
api_key: your-secret-key-here
debug_mode: true
-- Multi-pattern matching
ADDRESS tasks MATCHING("^[ \\t]*(?:TODO|FIXME|NOTE):\\s+(.*)$")
TODO: Implement user registration
FIXME: Handle edge case for empty input
NOTE: Consider performance optimization
Advanced Patterns
Multiple Syntax Support
-- Single pattern supporting multiple prefixes
ADDRESS EXPECTATIONS MATCHING("^[ \\t]*(?:\\.\\s+|CHECK:\\s+|VERIFY:\\s+)(.*)$")
-- All these work:
. result should equal 42
CHECK: result should equal 42
VERIFY: result should equal 42
Priority and Context Patterns
-- Capture priority and content separately
ADDRESS tasks MATCHING("^[ \\t]*TODO\\((\\w+)\\):\\s+(.*)$")
TODO(high): Critical security fix
TODO(low): Update documentation
TODO(medium): Performance optimization
-- The first capture group "high", "low", "medium" is sent to handler
Complex Validation Patterns
-- API endpoint validation
ADDRESS api_validator MATCHING("^[ \\t]*(?:GET|POST|PUT|DELETE)\\s+(.*)$")
GET /users should return 200
POST /users should create user
PUT /users/123 should update user
DELETE /users/123 should remove user
Integration Examples
Expectations Framework
REQUIRE "expectations-address"
LET user_age = 25
LET user_name = "Alice"
-- Natural test syntax with dot prefix
ADDRESS EXPECTATIONS MATCHING("^[ \\t]*\\. (.*)$")
. user_age should equal 25
. user_name should equal "Alice"
. user_age should be greater than 18
. user_name should match "^[A-Z][a-z]+$"
-- Back to normal REXX
SAY "All expectations passed"
Multi-Context Testing
-- Different patterns for different validation types
LET api_response = '{"status": "success", "data": {"id": 123}}'
LET db_query_result = "5 rows affected"
-- API validation context
ADDRESS api_validator MATCHING("^[ \\t]*API: (.*)$")
API: response should have status "success"
API: response.data.id should equal 123
-- Database validation context
ADDRESS db_validator MATCHING("^[ \\t]*DB: (.*)$")
DB: query should affect 5 rows
DB: transaction should commit successfully
Dynamic Pattern Generation
-- Build patterns dynamically
LET test_prefix = "ASSERT"
LET pattern = "^[ \\t]*" || test_prefix || ": (.*)$"
ADDRESS validator MATCHING(pattern)
ASSERT: value should be positive
ASSERT: string should not be empty
Error Handling
Invalid Regex Patterns
-- Invalid regex falls back to normal parsing
ADDRESS target MATCHING("^[invalid") -- Invalid regex
-- This line falls back to normal function call handling
. test_value should equal 42 -- Goes to ADDRESS target as function call
Pattern Debugging
-- Test patterns with simple content first
ADDRESS logger MATCHING("^[ \\t]*LOG: (.*)$")
LOG: This is a test message
-- Then add complexity gradually
LOG: User {user_name} logged in at {timestamp}
Performance Considerations
- Pattern Compilation: Regex patterns are compiled once when ADDRESS MATCHING is set
- Line Processing: Every line is tested against the active pattern
- Pattern Complexity: Simple patterns (dot-prefix) perform better than complex alternations
- Fallback Cost: Invalid patterns have minimal performance overhead
Best Practices
1. Design for Indentation
-- Always handle flexible whitespace
ADDRESS target MATCHING("^[ \\t]*prefix (.*)$") -- GOOD
ADDRESS target MATCHING("^prefix (.*)$") -- AVOID
2. Use Specific Patterns
-- Specific patterns reduce false matches
ADDRESS logger MATCHING("^[ \\t]*LOG: (.*)$") -- GOOD: Specific
ADDRESS logger MATCHING("^[ \\t]*(.*)$") -- AVOID: Too broad
3. Test Pattern Behavior
-- Test patterns with edge cases
ADDRESS target MATCHING("^[ \\t]*\\. (.*)$")
-- Test these cases:
.no space after dot
. single space
. multiple spaces
. tabs and spaces mixed
4. Document Pattern Intent
-- Clear comments explain pattern purpose
-- Match test assertions with flexible whitespace after dot
ADDRESS EXPECTATIONS MATCHING("^[ \\t]*\\. (.*)$")
-- Match TODO items with optional priority
ADDRESS tasks MATCHING("^[ \\t]*TODO(?:\\((\\w+)\\))?:\\s+(.*)$")
Integration with Other Features
INTERPRET Inheritance
-- INTERPRET inherits ADDRESS MATCHING context
ADDRESS logger MATCHING("^[ \\t]*LOG: (.*)$")
LET message = "System initialized"
LET log_command = "LOG: " || message
-- Executes in logger context with MATCHING active
INTERPRET log_command -- Sends "System initialized" to logger
Context Switching
-- Switch between different MATCHING contexts
ADDRESS validator MATCHING("^[ \\t]*\\. (.*)$")
. first_test should pass
-- Switch to different pattern
ADDRESS logger MATCHING("^[ \\t]*# (.*)$")
# Logging some information
-- Return to normal processing (both methods work)
ADDRESS DEFAULT -- Explicit reset (recommended)
ADDRESS -- Standard REXX: bare ADDRESS resets to default
SAY "Processing complete" -- Normal REXX command
Important: When you reset ADDRESS (using either ADDRESS DEFAULT or ADDRESS alone):
- The ADDRESS target is reset to ‘default’
- Any active MATCHING pattern is cleared
- Subsequent lines are parsed as normal REXX commands
- No special pattern matching occurs
-- Example: MATCHING pattern cleared on reset
ADDRESS EXPECTATIONS MATCHING("^[ \\t]*\\. (.*)$")
. value should equal 42 -- Sent to EXPECTATIONS handler
ADDRESS DEFAULT -- Clear ADDRESS and MATCHING pattern
. this is parsed as function -- Parsed as normal function call (not sent to EXPECTATIONS)
SAY "Back to normal parsing" -- Normal SAY command
ADDRESS MATCHING MULTILINE Reference
Syntax
ADDRESS <target> MATCHING MULTILINE "<pattern>"
The MULTILINE variant extends standard ADDRESS MATCHING to collect multiple matching lines and send them as a single multiline string to the ADDRESS handler.
Key Differences from Standard MATCHING
| Feature | Standard MATCHING | MULTILINE MATCHING |
|---|---|---|
| Line Processing | Each line sent individually | Lines collected until non-match |
| Handler Calls | One call per matching line | One call per collected block |
| Content Format | Single line string | Multiline string (lines joined with \n) |
| Use Case | Individual commands/assertions | Multi-line code blocks |
Pattern Design
Start Anchor Required: ^
-- ✅ CORRECT: Matches lines starting with pattern
ADDRESS sqlite3 MATCHING MULTILINE "^ (.*)"
-- ❌ INCORRECT: Matches pattern anywhere in line
ADDRESS sqlite3 MATCHING MULTILINE " (.*)"
End Anchor Not Needed: $
-- ✅ PREFERRED: Captures to end of line automatically
ADDRESS sqlite3 MATCHING MULTILINE "^ (.*)"
-- ⚠️ REDUNDANT: End anchor provides no benefit
ADDRESS sqlite3 MATCHING MULTILINE "^ (.*)$"
Common Patterns
-- SQL indentation (2+ spaces)
ADDRESS sqlite3 MATCHING MULTILINE "^ (.*)"
-- Python indentation (4+ spaces)
ADDRESS python MATCHING MULTILINE "^ (.*)"
-- Comment blocks
ADDRESS processor MATCHING MULTILINE "^# (.*)"
-- Custom prefix
ADDRESS system MATCHING MULTILINE "^>> (.*)"
Collection Algorithm
- Pattern Match: Each line tested against regex
- Match Found: Extract capture group content, add to buffer
- Non-Match Found:
- Send buffered content as single multiline string
- Clear buffer
- Process non-matching line normally
- Program End: Flush any remaining buffered content
Multiline Examples
SQL Statements
ADDRESS sqlite3 MATCHING MULTILINE "^ (.*)"
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE
)
-- Non-matching line flushes the CREATE TABLE
SAY "✓ Table created"
INSERT INTO users (name, email) VALUES
('Alice Smith', 'alice@example.com'),
('Bob Jones', 'bob@example.com')
-- ADDRESS change flushes the INSERT
ADDRESS default
Handler receives:
"CREATE TABLE users (\nid INTEGER PRIMARY KEY,\nname TEXT NOT NULL,\nemail TEXT UNIQUE\n)""INSERT INTO users (name, email) VALUES\n('Alice Smith', 'alice@example.com'),\n('Bob Jones', 'bob@example.com')"
Python Code
ADDRESS python MATCHING MULTILINE "^ (.*)"
def calculate_total(items):
total = 0
for item in items:
total += item.price
return total
ADDRESS default
Handler receives:
"def calculate_total(items):\n total = 0\n for item in items:\n total += item.price\n return total"
Shell Scripts
ADDRESS system MATCHING MULTILINE "^ (.*)"
for file in *.txt; do
echo "Processing $file"
wc -l "$file"
done
ADDRESS default
Termination Triggers
Multiline collection stops and content is sent when:
- Non-matching line encountered
- ADDRESS target changes (
ADDRESS otherorADDRESS default) - End of program/script
- New MATCHING pattern set (
ADDRESS target MATCHING "other_pattern")
Integration with ADDRESS Handlers
Handler Design
function ADDRESS_HANDLER(commandOrMethod, params) {
if (typeof commandOrMethod === 'string' && commandOrMethod.includes('\n')) {
// Multiline content detected
const lines = commandOrMethod.split('\n');
// Process as single multiline command
} else {
// Single line or method call
}
}
Context Information
Handlers can detect multiline content via:
- Newline presence:
commandOrMethod.includes('\n') - Pattern context:
params._addressMatchingPatternfield - Multiple lines:
commandOrMethod.split('\n').length > 1
Performance Considerations
- Memory Usage: Collection buffer grows with matching lines
- Regex Overhead: Pattern tested against every line
- Optimal Patterns: Simple patterns (
^ (.*)) perform better than complex alternations - Buffer Flushing: Regular flushing prevents excessive memory usage
Common Use Cases
Database Operations
-- Multi-line CREATE TABLE with constraints
-- Multi-value INSERT statements
-- Complex SELECT with JOINs and subqueries
ADDRESS sqlite3 MATCHING MULTILINE "^ (.*)"
Code Generation
-- Python functions and classes
-- JavaScript code blocks
-- Shell script generation
ADDRESS generator MATCHING MULTILINE "^ (.*)"
Configuration Files
-- JSON configuration blocks
-- YAML sections
-- INI file groups
ADDRESS config MATCHING MULTILINE "^ (.*)"
Error Handling
Invalid Patterns
-- Invalid regex falls back to normal MATCHING behavior
ADDRESS target MATCHING MULTILINE "^[invalid" -- Invalid regex
-- Subsequent lines processed as standard MATCHING (line-by-line)
Debugging Techniques
-- Test with simple content first
ADDRESS target MATCHING MULTILINE "^ (.*)"
simple test line
-- Add complexity gradually
multi-line
content block
Best Practices
✅ Do:
- Use start anchors (
^) for proper line matching - Design patterns for consistent indentation
- Flush buffers with non-matching lines regularly
- Test patterns with various content types
❌ Don’t:
- Use overly broad patterns that match unintended lines
- Create patterns without start anchors
- Forget to handle termination cases
- Mix multiline and single-line patterns unnecessarily
See Also
- Application Addressing - Core ADDRESS functionality
- Dynamic Execution - INTERPRET with ADDRESS contexts
- Testing with rexxt - Test framework integration
- Expectations Address Implementation - Reference implementation
- SQLite3 ADDRESS Examples - Real-world multiline usage
Pattern Examples Repository:
tests/dogfood/nested-loops-comprehensive.rexx- Production usagetests/address-matching-simple.spec.js- Unit teststests/address-matching.spec.js- Integration teststests/address-matching-multiline.spec.js- Multiline testsextras/addresses/sqlite3/- Multiline SQL examples