Add first working pipeline of parse -> ast -> instr -> render

Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
Marcel Müller 2026-03-06 11:03:48 +01:00
parent f5050e369e
commit 1ea15f0e49
5 changed files with 234 additions and 6 deletions

View file

@ -1,7 +1,70 @@
pub struct EvalStack {
stack: Vec<Evaluation>,
use std::collections::HashMap;
use displaydoc::Display;
use thiserror::Error;
use crate::Context;
use crate::emit::Instruction;
#[derive(Debug, Error, Display)]
enum EvalError {
/// An unknown variable was encountered: .0
UnknownVariable(String),
/// An explicit abort was requested
ExplicitAbort,
}
pub enum Evaluation {
AppendContent { content: String },
fn execute(instructions: &[Instruction], global_context: &Context) -> Result<String, EvalError> {
let mut output = String::new();
let mut scopes: HashMap<crate::emit::VariableSlot, serde_json::Value> = HashMap::new();
for instr in instructions {
match instr {
Instruction::AppendContent { content } => output.push_str(content),
Instruction::LoadFromContextToSlot { name, slot } => {
let value = global_context
.values
.get(name)
.ok_or(EvalError::UnknownVariable(name.clone()))?;
scopes.insert(*slot, value.clone());
}
Instruction::EmitFromSlot { slot } => {
let value = scopes.get(slot).unwrap().as_str().unwrap();
output.push_str(value);
}
Instruction::PushScope { inherit_parent: _ } => todo!(),
Instruction::Abort => return Err(EvalError::ExplicitAbort),
}
}
Ok(output)
}
#[cfg(test)]
mod tests {
use crate::Context;
use crate::eval::execute;
#[test]
fn check_simple_variable_interpolation() {
let input = "Hello {{= world }}";
let parsed = crate::parser::parse(input).unwrap();
let ast = crate::ast::parse(parsed.tokens()).unwrap();
let emit = crate::emit::emit_machine(ast);
let mut context = Context::new();
context.insert("world", "World");
let output = execute(&emit, &context);
insta::assert_debug_snapshot!(output, @r#"
Ok(
"Hello World",
)
"#);
}
}