Skip to main content

josie_core/
lib.rs

1//! # josie-core
2//!
3//! Core runtime and execution planner for **JOSIE**
4//! (JSON Omni Safe Interactive Expressions).
5//!
6//! ## Module Roles
7//!
8//! | Module | Responsibility | Public Entry Points |
9//! |---|---|---|
10//! | `runtime` | Tree evaluator + operator registry | [`evaluate`], [`Operators`], [`State`] |
11//! | `program` | Program envelope validation, compile planning, pipeline execution | `parse_program`, `compile_program`, `execute_program*` |
12//! | `compiler` | `serde_json::Value` expression -> typed IR | [`Expr`] and `compile_expr` |
13//! | `vm` | Fast typed IR evaluator | [`eval_expr`], [`IterLocals`] |
14//! | `jval` | Internal value representation for VM execution | [`JVal`] |
15//!
16//! ## Execution Contract
17//!
18//! 1. Parse/validate once.
19//! 2. Compile once into best available strategy.
20//! 3. Execute many times.
21//!
22//! Optimization tiers in `program`:
23//!
24//! 1. Specialized internal fast plans.
25//! 2. Specialized typed host-call fast plans.
26//! 3. Compiled pipeline IR path.
27//! 4. Generic tree/pipeline fallback.
28//!
29//! **Rule:** all optimized paths must preserve the same observable semantics
30//! as the generic evaluator.
31//!
32//! ## Hello World (Simple API)
33//!
34//! ```no_run
35//! use josie_core::eval;
36//! use serde_json::json;
37//!
38//! let out = eval(&json!(["util.concat", "Hello", ", ", "World"])).expect("eval");
39//! assert_eq!(out, json!("Hello, World"));
40//! ```
41//!
42//! ## Inject Custom `x.*` Operator
43//!
44//! ```no_run
45//! use josie_core::{Context, EvalResult, Operator, Operators, State, evaluate};
46//! use serde_json::{json, Value};
47//!
48//! fn op_x_echo(args: &[Value], _ctx: &mut Context) -> EvalResult {
49//!     Ok(args.first().cloned().unwrap_or(Value::Null))
50//! }
51//!
52//! let mut operators = Operators::new();
53//! operators.register("x.echo", op_x_echo as Operator);
54//!
55//! let mut state = State::new();
56//! let expr = json!(["x.echo", {"ok": true}]);
57//! let mut ctx = Context { state: &mut state, operators: &operators, event: None };
58//! let out = evaluate(&expr, &mut ctx).expect("x.echo");
59//! assert_eq!(out, json!({"ok": true}));
60//! ```
61
62use serde_json::Value;
63
64pub mod compiler;
65pub mod engine;
66pub mod jval;
67pub mod program;
68pub mod reader;
69pub mod runtime;
70pub mod vm;
71
72pub use compiler::Expr;
73pub use engine::Engine;
74pub use jval::JVal;
75pub use reader::{ReaderError, read, read_program};
76pub use runtime::{
77    Context, EvalError, EvalResult, EventContext, FunctionDef, JsonNode, Operator, Operators,
78    State, evaluate, get_path, set_path,
79};
80pub use vm::{IterLocals, eval_expr};
81
82/// Evaluate an expression with default runtime components:
83/// - empty [`State`]
84/// - default [`Operators`]
85/// - no [`EventContext`]
86pub fn eval(node: &Value) -> EvalResult {
87    let mut state = State::new();
88    let operators = Operators::new();
89    let mut ctx = Context {
90        state: &mut state,
91        operators: &operators,
92        event: None,
93    };
94    evaluate(node, &mut ctx)
95}
96
97/// Evaluate an expression with caller-provided state and default operators.
98pub fn eval_with_state(node: &Value, state: &mut State) -> EvalResult {
99    let operators = Operators::new();
100    let mut ctx = Context {
101        state,
102        operators: &operators,
103        event: None,
104    };
105    evaluate(node, &mut ctx)
106}
107
108/// Evaluate an expression with caller-provided operators and empty state.
109pub fn eval_with_operators(node: &Value, operators: &Operators) -> EvalResult {
110    let mut state = State::new();
111    let mut ctx = Context {
112        state: &mut state,
113        operators,
114        event: None,
115    };
116    evaluate(node, &mut ctx)
117}