4.9 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
dexpr is an embeddable expression evaluator and bytecode VM written in Rust. It parses expressions and simple scripts (.dexpr files), compiles to bytecode, and executes on a register-based virtual machine. Designed to be embedded in other projects as a rule engine, formula evaluator, or expression calculator.
Common Commands
# Run tests
cargo test
# Run benchmarks
cargo bench --bench my_benchmark
# Run the main program (executes basic_long.dexpr by default)
cargo run --release
# Profile with samply
cargo build --profile profiling
samply record ./target/profiling/dexpr
Architecture
The pipeline flows: Parser → AST → Compiler → Bytecode → VM
Core Modules
parser/: PEG-based parser (grammar.rs) that produces AST nodesast/: Expression (expr.rs), statement (stmt.rs), and value (value.rs) typescompiler.rs: Transforms AST into bytecode; single-pass, globals-only, register allocationbytecode.rs:BytecodeWriterfor compilation,BytecodeReaderfor VM consumptionopcodes.rs: DefinesOpCodeByteenum andRegistertypevm/vm.rs: Register-based VM with global variable support; executes bytecode
Key Types
Value(ast/value.rs): Runtime values (Number using rust_decimal, String, Boolean, Object using indexmap, etc.)Compiler: Stateful compiler with register allocationVM<'a>: Bytecode interpreter with global variable support viaset_global/get_global
Typical Usage Pattern
use dexpr::{ast::value::Value, compiler::Compiler, parser, vm::VM};
let ast = parser::program(source_code)?;
let mut compiler = Compiler::new();
let bytecode = compiler.compile(ast)?;
let mut vm = VM::new(&bytecode);
vm.set_global("input", Value::Number(dec!(42)));
vm.register_function("getRate", |args| Ok(Value::Number(dec!(34.5))));
let result = vm.execute()?; // Returns last expression's value
// Or use globals: let output = vm.get_global("output");
Language Features
The dexpr language supports:
- If/else conditionals with
if ... then ... else ... end - String methods (e.g.,
.upper(),.lower(),.trim(),.trimStart(),.trimEnd(),.split(),.replace(),.contains(),.startsWith(),.endsWith(),.length,.charAt(),.substring()) - Arithmetic (
+,-,*,/,%,**), comparison, and logical operators inoperator for membership testing ("finans" in categories,5 in numbers,"hello" in "hello world","key" in obj)- Compound assignments (
+=,-=,*=,/=,%=) - Built-in
log()function for output andrand(min, max)for random integers - External (host) function registration via
vm.register_function() - External (host) method registration via
vm.register_method() - Expression return value:
execute()returns the last expression's value - Line comments (
//) and block comments (/* */) - Lists:
NumberListandStringListtypes with methods (sum,avg,min,max,first,last,get,join,contains,indexOf,slice,reverse,sort,isEmpty, etc.) - Objects:
Objecttype (provided externally viaset_global) with property access (obj.field), nested access (obj.a.b), property assignment (obj.field = value), and methods (keys(),values(),length(),contains(key),get(key))
Detailed Module Documentation
IMPORTANT: Before making any changes to the codebase, read the relevant documentation files in the docs/ folder to understand how that module works in detail. After making changes to any module, update the corresponding documentation file to keep it in sync.
- docs/architecture.md — Overall architecture, pipeline, design decisions, dependencies
- docs/ast.md — AST module: Expr, Stmt, Value types, Span, serialization format
- docs/parser.md — Parser: PEG grammar rules, operator precedence, reserved keywords
- docs/opcodes.md — Opcodes: full instruction set with hex values and categories
- docs/bytecode.md — Bytecode: BytecodeWriter/Reader API, data format, disassembler
- docs/compiler.md — Compiler: single-pass compilation, register allocation, label/jump system
- docs/vm.md — VM: execution loop, opcode handlers, error types, DebugInfo
- docs/language_info.md — Language Info: editor metadata generation, JSON format, host integration
- docs/editor.md — Editor: CodeMirror 6 language support, Lezer grammar, type-aware autocomplete
Rule: Any code change that modifies the behavior, API, or structure of a module MUST be accompanied by an update to the corresponding docs/ file. Documentation and code must always stay in sync.