Strada Interpreter

A tree-walking interpreter that executes Strada programs directly from the AST, without generating C code.

No C compiler needed at runtime The interpreter evaluates Strada code by walking the AST directly. This makes it ideal for interactive use, quick scripts, and environments where gcc or tcc are not available.

Overview

Strada offers two execution paths for your code:

Compiled (stradac) Interpreter (strada-interp)
How it works Generates C code, compiles to native binary Walks the AST directly at runtime
Requires C compiler Yes (gcc) No
Startup time Slow (compilation step) Fast (parse and run)
Runtime speed Fastest (native code) Slower (interpreted)
Best for Production, performance REPL, scripting, prototyping

Both paths share the same Lexer and Parser front-end, so valid Strada code works with either.

Running Programs

# Build the interpreter
make interpreter

# Run a Strada program
./strada-interp program.strada

# With library search paths
./strada-interp -L lib program.strada

# Start the interactive REPL
./strada-interp

Interactive REPL

When run without arguments, the interpreter starts an interactive REPL with readline support (line editing, history):

strada> my int $x = 42;
strada> $x * 2
=> 84

strada> func square(int $n) int {
...        return $n * $n;
...    }
strada> square(7)
=> 49

Variables and function definitions persist across evaluations. Multi-line input is detected automatically when braces, parentheses, or brackets are unbalanced.

See REPL & Scripting for REPL commands, scripting, and profiling features.

Embedded Eval

The interpreter can be embedded inside compiled Strada programs using the Strada::Interpreter library. This enables runtime code evaluation without needing a C compiler at runtime:

use lib "lib";
use Strada::Interpreter;

# Initialize the interpreter engine
Strada::Interpreter::init();

# Evaluate expressions
my scalar $result = Strada::Interpreter::eval_string("1 + 2");
say($result);  # 3

# Variables persist across calls
Strada::Interpreter::eval_string("my int \$x = 10;");
my scalar $val = Strada::Interpreter::eval_string("\$x * 5");
say($val);  # 50

# Function definitions persist
Strada::Interpreter::eval_string("func double(int \$n) int { return \$n * 2; }");
say(Strada::Interpreter::eval_string("double(21)"));  # 42

# Reset all state
Strada::Interpreter::reset();

Eval API

Function Description
Strada::Interpreter::init() Initialize the shared interpreter instance (auto-called by eval_string if needed)
Strada::Interpreter::eval_string($code) Evaluate Strada code, return the result (undef for void statements)
Strada::Interpreter::reset() Clear all persisted state (variables, functions, enums, constants)

Interpreter vs JIT

Strada also provides Strada::JIT, which evaluates code by compiling to a shared library at runtime. The two approaches serve different needs:

Strada::Interpreter Strada::JIT
Execution Tree-walking AST eval Compile to .so, dlopen, execute
Requires C compiler No Yes (gcc or tcc)
__C__ blocks Skipped Supported
Async/await No Yes
Per-eval overhead Low (parse + walk) Higher (compile + link + load)
Execution speed Slower (interpreted) Fast (native code)
Best for REPL, scripting, no-compiler envs Plugin systems, perf-sensitive eval

Architecture

The interpreter reuses the compiler's Lexer and Parser, then walks the resulting AST to execute programs:

Component Source Purpose
Lexer compiler/Lexer.strada Tokenizes source (shared with compiler)
Parser compiler/Parser.strada Builds AST (shared with compiler)
Interpreter lib/Strada/Interpreter.strada Tree-walking AST evaluator
Driver interpreter/Main.strada File execution and REPL

Scoping

The interpreter maintains a chain of environment hashes for lexical scoping. Each scope has a vars hash and a parent pointer. Variable lookup walks from innermost to outermost scope. my creates in the current scope; assignments update the nearest scope containing the variable.

Control Flow

Loop control (next, last, redo) and return are implemented as exception-based signals caught by the enclosing loop or function call handler. Labeled loops match signals by label name.

Supported Features

The interpreter supports the full Strada language:

Limitations

Not supported in the interpreter
  • __C__ blocks are skipped (programs relying on inline C won't work)
  • Async/await (requires compiled thread pool runtime)
  • c:: namespace functions (c::alloc, c::free, etc.)

Native shared libraries loaded via import_lib still work — they are called through dlopen/dlsym regardless of execution mode.

Building

# Build the interpreter
make interpreter

# The interpreter binary
./strada-interp --help

# Usage
Strada Interpreter v0.2
Usage:
  strada-interp                          Interactive REPL
  strada-interp [OPTIONS] <file.strada>  Execute file

Options:
  -L PATH       Add library search path
  -h, --help    Show this help message