1use std::collections::{BTreeMap, HashSet};
2use std::fmt;
3
4use serde::Serialize;
5
6use crate::compiler::ast;
7use crate::compiler::instructions::Instructions;
8use crate::compiler::meta::find_undeclared;
9use crate::compiler::parser::parse_expr;
10use crate::environment::Environment;
11use crate::error::Error;
12use crate::output::Output;
13use crate::value::Value;
14use crate::vm::Vm;
15
16pub struct Expression<'env, 'source> {
37 env: &'env Environment<'source>,
38 instr: ExpressionBacking<'source>,
39}
40
41enum ExpressionBacking<'source> {
42 Borrowed(Instructions<'source>),
43 #[cfg(feature = "loader")]
44 Owned(crate::loader::OwnedInstructions),
45}
46
47impl fmt::Debug for Expression<'_, '_> {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 f.debug_struct("Expression")
50 .field("env", &self.env)
51 .finish()
52 }
53}
54
55impl<'env, 'source> Expression<'env, 'source> {
56 pub(crate) fn new(
57 env: &'env Environment<'source>,
58 instructions: Instructions<'source>,
59 ) -> Expression<'env, 'source> {
60 Expression {
61 env,
62 instr: ExpressionBacking::Borrowed(instructions),
63 }
64 }
65
66 #[cfg(feature = "loader")]
67 pub(crate) fn new_owned(
68 env: &'env Environment<'source>,
69 instructions: crate::loader::OwnedInstructions,
70 ) -> Expression<'env, 'source> {
71 Expression {
72 env,
73 instr: ExpressionBacking::Owned(instructions),
74 }
75 }
76
77 fn instructions(&self) -> &Instructions<'_> {
78 match self.instr {
79 ExpressionBacking::Borrowed(ref x) => x,
80 #[cfg(feature = "loader")]
81 ExpressionBacking::Owned(ref x) => x.borrow_dependent(),
82 }
83 }
84
85 pub fn eval<S: Serialize>(&self, ctx: S) -> Result<Value, Error> {
89 self._eval(Value::from_serialize(&ctx))
92 }
93
94 pub fn undeclared_variables(&self, nested: bool) -> HashSet<String> {
99 match parse_expr(self.instructions().source()) {
100 Ok(expr) => find_undeclared(
101 &ast::Stmt::EmitExpr(ast::Spanned::new(
102 ast::EmitExpr { expr },
103 Default::default(),
104 )),
105 nested,
106 ),
107 Err(_) => HashSet::new(),
108 }
109 }
110
111 fn _eval(&self, root: Value) -> Result<Value, Error> {
112 Ok(ok!(Vm::new(self.env).eval(
113 self.instructions(),
114 root,
115 &BTreeMap::new(),
116 &mut Output::null(),
117 crate::AutoEscape::None,
118 ))
119 .0
120 .expect("expression evaluation did not leave value on stack"))
121 }
122}