diff --git a/pdl-live-react/src-tauri/src/pdl/ast.rs b/pdl-live-react/src-tauri/src/pdl/ast.rs index 599304208..32666ddee 100644 --- a/pdl-live-react/src-tauri/src/pdl/ast.rs +++ b/pdl-live-react/src-tauri/src/pdl/ast.rs @@ -519,6 +519,23 @@ pub enum StringOrBoolean { Boolean(bool), } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Expr { + #[serde(rename = "pdl__expr")] + pub pdl_expr: S, + + #[serde(rename = "pdl__result", skip_serializing_if = "Option::is_none")] + pub pdl_result: Option, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum EvalsTo { + Const(T), + Jinja(String), + Expr(Expr), +} + /// Conditional control structure. /// /// Example: @@ -535,7 +552,7 @@ pub enum StringOrBoolean { pub struct IfBlock { /// The condition to check #[serde(rename = "if")] - pub condition: StringOrBoolean, + pub condition: EvalsTo, /// Branch to execute if the condition is true pub then: Box, diff --git a/pdl-live-react/src-tauri/src/pdl/interpreter.rs b/pdl-live-react/src-tauri/src/pdl/interpreter.rs index ba834127e..5d7a5120d 100644 --- a/pdl-live-react/src-tauri/src/pdl/interpreter.rs +++ b/pdl-live-react/src-tauri/src/pdl/interpreter.rs @@ -21,10 +21,10 @@ use serde_json::{from_str, json, to_string, Value}; use serde_norway::{from_reader, from_str as from_yaml_str}; use crate::pdl::ast::{ - ArrayBlock, CallBlock, Closure, DataBlock, EmptyBlock, FunctionBlock, IfBlock, ImportBlock, - IncludeBlock, ListOrString, MessageBlock, ModelBlock, ObjectBlock, PdlBlock, PdlParser, - PdlResult, PdlUsage, PythonCodeBlock, ReadBlock, RepeatBlock, Role, Scope, SequencingBlock, - StringOrBoolean, StringOrNull, + ArrayBlock, CallBlock, Closure, DataBlock, EmptyBlock, EvalsTo, Expr, FunctionBlock, IfBlock, + ImportBlock, IncludeBlock, ListOrString, MessageBlock, ModelBlock, ObjectBlock, PdlBlock, + PdlParser, PdlResult, PdlUsage, PythonCodeBlock, ReadBlock, RepeatBlock, Role, Scope, + SequencingBlock, StringOrBoolean, StringOrNull, }; type Messages = Vec; @@ -207,6 +207,33 @@ impl<'a> Interpreter<'a> { })) } + /// Evaluate an Expr to a bool + fn eval_to_bool( + &self, + expr: &EvalsTo, + state: &State, + ) -> Result { + match expr { + EvalsTo::Const(b) + | EvalsTo::Expr(Expr { + pdl_expr: StringOrBoolean::Boolean(b), + .. + }) => Ok(b.clone()), + + EvalsTo::Jinja(s) + | EvalsTo::Expr(Expr { + pdl_expr: StringOrBoolean::String(s), + .. + }) => match self.eval(s, state)? { + PdlResult::Bool(b) => Ok(b.clone()), + x => Err(Box::from(format!( + "Expression {s} evaluated to non-boolean {:?}", + x + ))), + }, + } + } + /// Evaluate String as a Jinja2 expression, expecting a string in response fn eval_to_string(&self, expr: &String, state: &State) -> Result { match self.eval(expr, state)? { @@ -432,21 +459,13 @@ impl<'a> Interpreter<'a> { self.process_defs(&meta.defs, state).await?; } - let cond = match &block.condition { - StringOrBoolean::Boolean(b) => PdlResult::Bool(*b), - StringOrBoolean::String(s) => self.eval(s, state)?, - }; - - match cond { - PdlResult::Bool(true) => self.run_quiet(&block.then, state).await, - PdlResult::Bool(false) => match &block.else_ { + if self.eval_to_bool(&block.condition, state)? { + self.run_quiet(&block.then, state).await + } else { + match &block.else_ { Some(else_block) => self.run_quiet(&else_block, state).await, None => Ok(("".into(), vec![], PdlBlock::If(block.clone()))), - }, - x => Err(Box::from(format!( - "if block condition evaluated to non-boolean value: {:?}", - x - ))), + } } }