pdk_script/
script.rs

1// Copyright (c) 2025, Salesforce, Inc.,
2// All rights reserved.
3// For full license text, see the LICENSE.txt file
4
5use crate::context::input::InputContext;
6use crate::context::StreamSolver;
7use crate::evaluator::Evaluator;
8use crate::expression::Expression;
9use crate::input::Input;
10use pel::expression::Expression as PelExpression;
11use pel::runtime::value::Value as PelValue;
12use pel::runtime::{Evaluation, Runtime, RuntimeError};
13use thiserror::Error;
14
15/// A builder for [`ScriptParser`]s.
16pub struct ScriptingEngine {}
17
18impl ScriptingEngine {
19    /// Creates a new [`ScriptParser`].
20    pub fn script(expression: &Expression) -> ScriptParser {
21        ScriptParser::new(expression)
22    }
23}
24
25/// Parser for script [`Expression`]s.
26pub struct ScriptParser<'a> {
27    expression: &'a Expression,
28    input_context: InputContext,
29}
30
31impl<'a> ScriptParser<'a> {
32    pub(crate) fn new(expression: &'a Expression) -> Self {
33        Self {
34            expression,
35            input_context: InputContext::default(),
36        }
37    }
38
39    /// Sets an `input`.
40    pub fn input(mut self, input: Input) -> Self {
41        match input {
42            Input::Payload(fmt) => self.input_context.set_payload_input(fmt),
43            Input::Vars(vars) => {
44                self.input_context.push_var_input(vars);
45            }
46            Input::Attributes => {
47                self.input_context.set_attributes_input();
48            }
49            Input::Authentication => self.input_context.set_authentication_input(),
50        }
51        self
52    }
53
54    /// Compiles the inputs and returns a new [`Script`].
55    pub fn compile(self) -> Result<Script, ScriptError> {
56        let result = Runtime::new()
57            .eval_with_context(&self.expression.expression, &self.input_context)
58            .map_err(ScriptError::Error)?;
59
60        match result {
61            Evaluation::Complete(_, v) => Ok(Script::new(None, None, Some(v), self.input_context)),
62            Evaluation::Partial(e) => Ok(Script::new(
63                self.expression.source.as_deref(),
64                Some(e),
65                None,
66                self.input_context,
67            )),
68        }
69    }
70}
71
72/// Represents the [`ScriptParser::compile`] error.
73#[derive(Error, Debug)]
74pub enum ScriptError {
75    /// Represents a compiler error.
76    #[error("Error compiling expression: {0}")]
77    Error(RuntimeError),
78}
79
80/// An script relating an [`Expression`] with their [`Input`]s.
81#[derive(Debug, Clone)]
82pub struct Script {
83    stream_solver: StreamSolver,
84    evaluation: Option<PelExpression>,
85    result: Option<PelValue>,
86    context: InputContext,
87}
88
89impl Script {
90    pub(crate) fn new(
91        source: Option<&str>,
92        evaluation: Option<PelExpression>,
93        result: Option<PelValue>,
94        context: InputContext,
95    ) -> Self {
96        Self {
97            stream_solver: StreamSolver::for_source(source),
98            evaluation,
99            result,
100            context,
101        }
102    }
103
104    /// Creates an [`Evaluator`] for the script.
105    pub fn evaluator(&self) -> Evaluator {
106        Evaluator::new(
107            self.stream_solver.clone(),
108            self.evaluation.clone(),
109            self.result.clone(),
110            &self.context,
111        )
112    }
113}