Dynamic Code Execution - INTERPRET

Powerful dynamic code execution capabilities with multiple security and scoping models for meta-programming, code generation, and flexible automation workflows.

//TODO In many languages eval is considered potentially harmful

INTERPRET Modes Overview

Syntax Variable Access Use Cases
INTERPRET "code" Full bidirectional sharing Quick scripting, template processing, legacy code
INTERPRET "code" WITH ISOLATED No variable access Secure execution, untrusted code, sandboxing
INTERPRET "code" WITH ISOLATED (var1 var2) Controlled input only Data processing with specific inputs
INTERPRET "code" WITH ISOLATED EXPORT(result) Controlled output only Computed results without input access
INTERPRET "code" WITH ISOLATED (inputs...) EXPORT(outputs...) Full control of I/O Complex data processing with security
NO-INTERPRET / NO_INTERPRET Blocks all INTERPRET High-security environments

Classic INTERPRET (Full Variable Sharing)

Traditional Rexx-style INTERPRET with complete variable sharing between parent and child scopes.

Basic Usage

-- Simple dynamic execution
LET baseValue = 100
INTERPRET "LET result = baseValue * 2"
SAY "Result: " || result              
-- "Result: 200"

Multi-line Execution

LET script = "LET a = 10\\nLET b = 20\\nLET sum = a + b"
INTERPRET script
SAY "Sum: " || sum                    
-- "Sum: 30"

Bidirectional Variable Sharing

LET original = "start"
INTERPRET "LET modified = original || \" processed\"\\nLET new_var = \"created\""
SAY modified                          
-- "start processed"
SAY new_var                          
-- "created"

Complex Processing Example

-- Dynamic data processing
LET processingScript = "
  LET rawData = '[{\\\"name\\\":\\\"john\\\",\\\"score\\\":85},{\\\"name\\\":\\\"jane\\\",\\\"score\\\":92}]'
  LET parsed = JSON_PARSE text=rawData
  LET count = ARRAY_LENGTH array=parsed
  LET firstUser = ARRAY_GET array=parsed index=1
  LET firstName = UPPER string=ARRAY_GET(array=firstUser key=\\\"name\\\")
  LET timestamp = NOW
"

INTERPRET processingScript
SAY "Processed " || count || " users at " || timestamp
SAY "First user: " || firstName

Isolated INTERPRET (Sandboxed Execution)

Sandboxed execution with no variable sharing by default, providing complete security isolation.

Basic Isolation

-- Variables remain isolated
LET secret = "confidential"
INTERPRET "LET isolated_var = \"safe\"\\nLET leaked = secret" WITH ISOLATED

-- isolated_var and leaked are not accessible in parent scope
-- secret remains protected from the isolated code

Security Benefits

  • No access to parent scope variables
  • Cannot modify external state
  • Perfect for untrusted code execution
  • Prevents information leakage

Isolated INTERPRET with Import/Export

Control exactly which variables flow in and out of isolated scope for precise data processing.

Import Variables (Controlled Input)

-- Import specific variables for processing
LET price = 100
LET tax_rate = 0.08
LET discount = 10

INTERPRET "LET total = (price - discount) * (1 + tax_rate)" WITH ISOLATED (price tax_rate discount) EXPORT(total)
SAY "Total: " || total               
-- "Total: 97.2"

Multiple Import and Export

LET base = 10
LET multiplier = 3
LET offset = 5

LET processing = "
  LET result1 = base * multiplier
  LET result2 = result1 + offset
  LET debug = base || \" * \" || multiplier || \" + \" || offset || \" = \" || result2
"

INTERPRET processing WITH ISOLATED (base multiplier offset) EXPORT(result1 result2 debug)

SAY "Result1: " || result1           
-- "Result1: 30"  
SAY "Result2: " || result2           
-- "Result2: 35"
SAY "Debug: " || debug               
-- "Debug: 10 * 3 + 5 = 35"

Complex Data Processing

-- Secure data filtering
LET users = JSON_PARSE text='[{"name":"John","age":30},{"name":"Jane","age":25}]'
LET min_age = 26

LET filter_code = "
  LET filtered = []
  LET count = ARRAY_LENGTH array=users
  DO i = 1 TO count
    LET user = ARRAY_GET array=users index=i
    IF ARRAY_GET(array=user key=\"age\") >= min_age THEN
      LET filtered = ARRAY_PUSH array=filtered item=user
    ENDIF
  END
  LET result_count = ARRAY_LENGTH array=filtered
"

INTERPRET filter_code WITH ISOLATED (users min_age) EXPORT(filtered result_count)
SAY "Filtered: " || result_count || " users"

Security Controls

NO-INTERPRET - Disable Dynamic Execution

-- Normal operation
LET result1 = INTERPRET string="LET safe = 42"
SAY "Before: " || safe                
-- "Before: 42"

-- Block all INTERPRET operations
NO-INTERPRET

-- Both function and statement forms are blocked
LET result2 = INTERPRET string="LET blocked = 1"  -- Throws error
INTERPRET "LET also_blocked = 2"                  -- Throws error

-- NO_INTERPRET (underscore variant) also supported
NO_INTERPRET

Use cases for NO-INTERPRET:

  • Secure execution environments
  • Code sandboxing
  • Preventing dynamic code injection
  • Compliance with security policies
  • Template systems with restricted capabilities

Meta-Programming and Code Generation

Dynamic Code Generation

-- Generate validation code for form fields
LET requiredFields = "[\"name\", \"email\", \"phone\", \"address\"]"
LET fields = JSON_PARSE text=requiredFields
LET fieldCount = ARRAY_LENGTH array=fields

LET validationCode = ""
DO i = 1 TO fieldCount
  LET fieldName = ARRAY_GET array=fields index=i
  LET validation = "IF " || fieldName || " = \"\" THEN\\n"
  LET validation = validation || "  SAY \"Error: " || fieldName || " is required\"\\n" 
  LET validation = validation || "  LET validationFailed = true\\n"
  LET validation = validation || "ENDIF\\n"
  LET validationCode = validationCode || validation
END

-- Set up test data
LET name = "John"
LET email = ""        -- This will trigger validation
LET phone = "555-1234"
LET address = "123 Main St"
LET validationFailed = false

-- Execute the generated validation code
INTERPRET validationCode

IF validationFailed THEN
  SAY "Form validation failed"
ELSE
  SAY "Form validation passed"
ENDIF

Configuration-Driven Logic

-- Execute different workflows based on configuration
LET config = JSON_PARSE text='{"workflow": "premium", "features": ["analytics", "reporting"]}'
LET workflowType = ARRAY_GET array=config key="workflow"

SELECT
  WHEN workflowType = "premium" THEN
    LET premiumScript = "LET analytics = true\\nLET reporting = true\\nLET priority = \"high\""
    INTERPRET premiumScript
  WHEN workflowType = "standard" THEN  
    INTERPRET "LET analytics = true\\nLET reporting = false\\nLET priority = \"normal\""
  OTHERWISE
    INTERPRET "LET analytics = false\\nLET reporting = false\\nLET priority = \"low\""
END

SAY "Workflow configured: priority=" || priority || ", analytics=" || analytics

Template Processing

-- Process templates with dynamic content
LET templateVars = '{"customerName": "John Smith", "orderTotal": 125.50, "itemCount": 3}'
LET vars = JSON_PARSE text=templateVars

LET template = "
  LET customerName = ARRAY_GET array=vars key=\"customerName\"
  LET orderTotal = ARRAY_GET array=vars key=\"orderTotal\"
  LET itemCount = ARRAY_GET array=vars key=\"itemCount\"
  
  LET message = \"Dear \" || customerName || \", your order of \" || itemCount || \" items totaling $\" || orderTotal || \" has been processed.\"
"

INTERPRET template WITH ISOLATED (vars) EXPORT(message)
SAY "Generated message: " || message

Application Addressing Integration

INTERPRET inherits the current ADDRESS context, enabling cross-application automation:

-- Calculator automation with dynamic operations
ADDRESS calculator

-- Generate calculator operations dynamically
LET operations = "[\"clear\", \"5\", \"+\", \"3\", \"*\", \"2\", \"=\"]"
LET ops = JSON_PARSE text=operations
LET opCount = ARRAY_LENGTH array=ops

LET calculatorScript = ""
DO i = 1 TO opCount
  LET op = ARRAY_GET array=ops index=i
  LET command = "press button=\"" || op || "\"\\n"
  LET calculatorScript = calculatorScript || command
END

LET calculatorScript = calculatorScript || "LET finalResult = getDisplay"

-- Execute the generated calculator script
INTERPRET calculatorScript

SAY "Calculator result: " || finalResult

Error Handling

INTERPRET Error Handling

SIGNAL ON ERROR NAME InterpretError

-- This will fail and trigger error handler
INTERPRET "LET invalid = NONEXISTENT_FUNCTION()"

SAY "This won't execute"
EXIT

InterpretError:
SAY "INTERPRET failed: " || ERROR_MESSAGE
SAY "Error in function: " || ERROR_FUNCTION
SAY "Error context: " || ERROR_VARIABLES

Graceful Error Recovery

-- Safe dynamic execution with error handling
LET userCode = "LET result = 10 / 0"  -- This will cause an error

SIGNAL ON ERROR NAME HandleMathError
INTERPRET userCode
SIGNAL OFF ERROR

SAY "Execution completed successfully"
EXIT

HandleMathError:
SAY "Math error in dynamic code: " || ERROR_MESSAGE
SAY "Continuing with default values..."
LET result = 0
SIGNAL OFF ERROR

Performance Considerations

  • INTERPRET instances: Each call creates a new interpreter instance
  • Variable sharing: Classic INTERPRET has fastest variable sharing
  • Isolated execution: Minimal performance cost for security benefits
  • Large code blocks: Supported with good performance
  • Error handling: Minimal overhead when no errors occur

Best Practices

When to Use Each Mode

Classic INTERPRET:

  • Template processing with trusted code
  • Quick calculations and data transformations
  • Legacy system integration
  • Development and debugging

Isolated INTERPRET:

  • Processing untrusted user input
  • Plugin systems
  • Configuration file processing
  • Sandbox environments

Import/Export INTERPRET:

  • Data processing pipelines
  • Complex calculations with controlled I/O
  • Secure computation services
  • API request processing

Code Organization

-- Good: Organize complex INTERPRET code
LET dataProcessing = "
  -- Data validation phase
  LET validRecords = []
  
  -- Processing phase  
  DO i = 1 TO inputCount
    LET record = ARRAY_GET array=inputData index=i
    -- Processing logic here
  END
  
  -- Results compilation
  LET summary = createSummary records=validRecords
"

INTERPRET dataProcessing WITH ISOLATED (inputData inputCount) EXPORT(validRecords summary)

Security Guidelines

  • Use isolated mode for untrusted code
  • Minimize exported variables to only what’s needed
  • Use NO-INTERPRET in high-security contexts
  • Validate all dynamic code before execution
  • Log dynamic code execution for audit trails

API Reference

Statement Forms

-- Classic INTERPRET (full sharing)
INTERPRET codeString

-- Isolated INTERPRET (no sharing)  
INTERPRET codeString WITH ISOLATED

-- Isolated with controlled I/O
INTERPRET codeString WITH ISOLATED (input1 input2) EXPORT(output1 output2)

-- Security control
NO-INTERPRET        -- Hyphen form
NO_INTERPRET        -- Underscore form

Legacy Function Form (deprecated but supported)

LET result = INTERPRET string=codeString options='{"shareVars": true}'

JavaScript Execution - INTERPRET_JS

Execute JavaScript code directly within Rexx scripts for browser automation, DOM manipulation, and cross-language integration.

Basic JavaScript Execution

-- Execute JavaScript expressions
LET result = INTERPRET_JS("5 + 3 * 2")
SAY "Math result: " || result                    
-- "Math result: 11"

-- Execute JavaScript statements  
INTERPRET_JS("globalThis.testVar = 'Hello from JS'")
LET message = INTERPRET_JS("globalThis.testVar")
SAY message                                      
-- "Hello from JS"

Type Parameter Control

-- Force expression mode (with return)
LET mathResult = INTERPRET_JS("Math.max(10, 20, 5)", "expression")
-- mathResult = 20

-- Force statement mode (no return)
INTERPRET_JS("console.log('Debug message')", "statement")

-- Auto mode (default) - tries expression first, falls back to statement
LET autoResult = INTERPRET_JS("document.title")  -- Reads page title
INTERPRET_JS("alert('Hello World')")             -- Shows alert dialog

Browser DOM Integration

-- Read DOM element properties
LET pageTitle = INTERPRET_JS("document.title")
LET displayValue = INTERPRET_JS("document.getElementById('display').textContent")

-- Manipulate DOM elements
INTERPRET_JS("document.getElementById('button').click()")
INTERPRET_JS("document.body.style.backgroundColor = 'lightblue'")

-- Call JavaScript functions
INTERPRET_JS("button_number(5)")
INTERPRET_JS("calculate()")
LET result = INTERPRET_JS("getDisplayValue()")

Calculator Automation Example

-- Automate calculator operations via JavaScript
SAY "Automating calculator: 5 + 3 = ?"

INTERPRET_JS("button_clear()")
INTERPRET_JS("button_number(5)")
INTERPRET_JS("button_number('+')")  
INTERPRET_JS("button_number(3)")
INTERPRET_JS("button_number('=')")

LET calculationResult = INTERPRET_JS("document.getElementById('display').textContent")
SAY "Calculator result: " || calculationResult
-- "Calculator result: 8"

Cross-Frame Communication

-- Execute JavaScript in iframe contexts  
ADDRESS iframe
INTERPRET_JS("parent.postMessage({type: 'result', value: 42}, '*')")

-- Access iframe-specific functions
INTERPRET_JS("calculatorApp.pressButton('=')")
LET iframeResult = INTERPRET_JS("calculatorApp.getDisplay()")

JavaScript Object Manipulation

-- Create and manipulate JavaScript objects
INTERPRET_JS("globalThis.config = {theme: 'dark', lang: 'en'}")
LET theme = INTERPRET_JS("globalThis.config.theme")

-- Work with arrays
INTERPRET_JS("globalThis.items = [1, 2, 3, 4, 5]")
LET arrayLength = INTERPRET_JS("globalThis.items.length")
LET firstItem = INTERPRET_JS("globalThis.items[0]")

-- Call JavaScript methods
LET joinedItems = INTERPRET_JS("globalThis.items.join('-')")
SAY "Joined array: " || joinedItems
-- "Joined array: 1-2-3-4-5"

Security Integration with NO-INTERPRET

-- INTERPRET_JS respects NO-INTERPRET directive
NO-INTERPRET

-- This will throw an error
INTERPRET_JS("alert('Blocked!')")  -- Error: "INTERPRET_JS is blocked by NO-INTERPRET directive"

Error Handling

-- Handle JavaScript errors gracefully
SIGNAL ON ERROR NAME JSError

INTERPRET_JS("nonExistentFunction()")
SAY "JavaScript executed successfully"
EXIT

JSError:
SAY "JavaScript execution failed: " || ERROR_MESSAGE
SAY "Continuing with fallback logic..."
SIGNAL OFF ERROR

Type Parameter Reference

Type Behavior Use Case
"auto" (default) Try expression first, fall back to statement General purpose, backward compatible
"expression" Force expression mode with return (...) Reading values, calculations, DOM queries
"statement" Force statement mode, execute as-is Function calls, assignments, side effects

Advanced Integration Examples

-- Dynamic JavaScript generation
LET buttonId = "calculate-btn"
LET jsCode = "document.getElementById('" || buttonId || "').click()"
INTERPRET_JS(jsCode)

-- Conditional JavaScript execution
IF INTERPRET_JS("typeof jQuery !== 'undefined'") = "true" THEN
  INTERPRET_JS("jQuery('#modal').show()")
ELSE  
  INTERPRET_JS("document.getElementById('modal').style.display = 'block'")
ENDIF

-- JavaScript template processing
LET userName = "John"
LET template = "document.querySelector('.welcome').textContent = 'Hello, " || userName || "'"
INTERPRET_JS(template)

Browser Environment Detection

-- INTERPRET_JS only works in browser environments
SIGNAL ON ERROR NAME NotBrowser

LET result = INTERPRET_JS("window.location.href")
SAY "Current page: " || result
SIGNAL OFF ERROR
EXIT

NotBrowser:
SAY "INTERPRET_JS requires browser environment"
SAY "Error: " || ERROR_MESSAGE

Performance Considerations

  • JavaScript parsing: Each call validates syntax before execution
  • Context sharing: JavaScript executes in shared global context
  • Error isolation: JavaScript errors are caught and converted to Rexx errors
  • Type conversion: Automatic conversion between JavaScript and Rexx types
  • DOM access: Direct access to browser DOM without serialization overhead

Best Practices

  • Use "expression" type for reading values and calculations
  • Use "statement" type for actions and side effects
  • Use "auto" for mixed operations and backward compatibility
  • Handle errors with SIGNAL ON ERROR for robust automation
  • Validate JavaScript syntax before dynamic execution
  • Use NO-INTERPRET in secure contexts to disable all dynamic execution

See also: