online-dsl-forge
online-dsl-forge is a Rust library for parsing, canonicalizing, compiling,
semantically validating, and evaluating a small bounded DSL expression language
in memory.
The crate exists for host applications that need a canonical runtime and
operator interface for DSL expressions without adopting a general-purpose
scripting language. It contains the parser, semantic compile validation, a
dynamic runtime registry, and CLI tooling in one publishable package.
Capabilities
- Handwritten lexer, recursive-descent expression parser, span-carrying AST,
diagnostics, and formatter.
- Semantic analyzer, runtime schemas, security profiles, and verified IR.
- In-memory rulepack rendering for schema v2 manifests, variable pinning,
local overrides, local exceptions, provenance stamping, and resolver-backed
referenced rule/group files.
- Compile-time validation against host-provided runtime schemas and security
profiles.
- Bounded in-memory evaluation with a dynamic variable, function, method, and
operator registry that executes sema-verified programs.
online-dsl-forgectl commands for check, ast, fmt, and eval.
The language intentionally excludes loops, assignment, imports, callbacks,
external I/O, mutation, async execution, and general-purpose scripting.
Quick Start
Add the crate to a Rust project:
cargo add online-dsl-forge
Parse, format, compile, and evaluate an expression:
use std::collections::BTreeMap;
use online_dsl_forge::{
CompileOptions, EvalLimits, MapRuntime, Value, compile_expression, evaluate,
format_expression, parse_expression,
};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let ast = parse_expression("score + 1 >= 10 && name.starts_with('pi')")?;
assert_eq!(
format_expression(&ast),
"score + 1 >= 10 && name.starts_with(\"pi\")"
);
let mut variables = BTreeMap::new();
variables.insert("score".to_string(), Value::Int(9));
variables.insert("name".to_string(), Value::String("piquark".to_string()));
let runtime = MapRuntime::new(variables, online_dsl_forge::default_registry());
let compiled = compile_expression(&ast, &runtime.schema(), CompileOptions::default())?;
let value = evaluate(&compiled, &runtime, EvalLimits::default())?;
assert_eq!(value, Value::Bool(true));
Ok(())
}
Render a rulepack bundle without granting the library filesystem or network
access:
use std::collections::BTreeMap;
use online_dsl_forge::{
MemoryFileResolver, RulepackRenderOptions, render_rulepack_bundle,
};
fn render() -> Result<(), Box<dyn std::error::Error>> {
let manifest = r#"[rulepack]
schema_version = 2
name = "demo"
version = "0.1.0"
[[variables]]
name = "route_name"
type = "string"
required = true
[[rules]]
name = "login"
phase = "request"
priority = 100
path = "rules/login.oxirule.toml"
"#;
let resolver = MemoryFileResolver::new().with_file(
"rules/login.oxirule.toml",
"when = \"Context.RouteName == '{{route_name}}'\"\n",
);
let bundle = render_rulepack_bundle(
manifest,
"example rulepack",
RulepackRenderOptions {
variables: BTreeMap::from([("route_name".to_string(), "app-root".to_string())]),
pin_variables: true,
..RulepackRenderOptions::default()
},
&resolver,
)?;
assert!(bundle.manifest.contains("default = \"app-root\""));
assert!(bundle.files[0].content.contains("app-root"));
Ok(())
}
CLI
Format an expression from the repository root:
cargo run --manifest-path source/Cargo.toml --bin online-dsl-forgectl -- \
fmt "Request.Path.starts_with('/admin') && user_score >= 10"
Evaluate an expression against JSON bindings:
cargo run --manifest-path source/Cargo.toml --bin online-dsl-forgectl -- \
eval "score + 1 >= 10 && name.starts_with('pi')" \
--bindings '{"score":9,"name":"piquark"}'
Documentation