1pub mod block;
68pub mod contained_evaluator;
69pub mod dependencies;
70pub mod evaluation_context;
71pub mod evaluator;
72pub mod evaluator_builder_error;
73
74use std::{borrow::Borrow, collections::HashMap};
75
76use hmap::hmap;
77
78use crate::{parser::expression::Expression, tokenizer::token::TokenType, value::Value};
79
80use self::{
81 block::Block,
82 dependencies::Dependencies,
83 evaluation_context::{ContextLocation, EvaluationContext},
84};
85
86pub type Variables = HashMap<String, Value>;
87pub type ValueFunction = Box<dyn Fn(&[Value]) -> Value + 'static>;
88
89pub trait Evaluate {
92 fn evaluate<'ea>(&self, context: &mut EvaluationContext<'ea, impl Evaluate>) -> String;
93
94 fn get_dependencies(&self) -> &Dependencies;
95}
96
97pub fn evaluate_expression<'c>(
99 context: &mut EvaluationContext<'c, impl Evaluate>,
100 expression: &Expression,
101) -> Value {
102 match expression {
103 Expression::Additive(add, subtract) => {
105 let mut add = add.iter();
107 let mut subtract = subtract.iter();
108
109 let mut value = match add.next() {
111 Some(expression) => evaluate_expression(context, expression.borrow()),
112 None => evaluate_expression(context, subtract.next().unwrap().borrow()),
113 };
114
115 for expression in add {
117 value = value.add(&evaluate_expression(context, expression.borrow()));
118 }
119
120 for expression in subtract {
122 value = value.sub(&evaluate_expression(context, expression.borrow()));
123 }
124
125 value
126 }
127 Expression::Multiplicative(multiply, divide) => {
128 let mut multiply = multiply.iter();
130 let mut divide = divide.iter();
131
132 let mut value = match multiply.next() {
134 Some(expression) => evaluate_expression(context, expression.borrow()),
135 None => evaluate_expression(context, divide.next().unwrap().borrow()),
136 };
137
138 for expression in multiply {
140 value = value.mul(&evaluate_expression(context, expression.borrow()));
141 }
142
143 for expression in divide {
145 value = value.div(&evaluate_expression(context, expression.borrow()));
146 }
147
148 value
149 }
150 Expression::Negate(expression) => evaluate_expression(context, expression.borrow()).neg(),
151 Expression::Or(expressions) => expressions
153 .iter()
154 .map(|expression| evaluate_expression(context, expression.borrow()))
155 .reduce(|acc, x| acc.or(&x))
156 .unwrap(),
157 Expression::And(expressions) => expressions
158 .iter()
159 .map(|expression| evaluate_expression(context, expression.borrow()))
160 .reduce(|acc, x| acc.and(&x))
161 .unwrap(),
162 Expression::Not(expression) => evaluate_expression(context, expression.borrow()).not(),
163 Expression::Comparison(lhs, op, rhs) => {
165 let lhs = evaluate_expression(context, lhs.borrow());
166 let rhs = evaluate_expression(context, rhs.borrow());
167 match op {
168 TokenType::SmallerThan => lhs.less_than(&rhs),
169 TokenType::SmallerEquals => lhs.less_equals(&rhs),
170 TokenType::GreaterThan => lhs.greater_than(&rhs),
171 TokenType::GreaterEquals => lhs.greater_than(&rhs),
172 TokenType::Equals => lhs.equals(&rhs),
173 TokenType::NotEquals => lhs.not_equals(&rhs),
174 _ => Value::None,
175 }
176 }
177 Expression::Value(value) => value.clone(),
179 Expression::Variable(name) => context.get_variable_value(*name).unwrap_or(Value::None),
180 Expression::ListValue(expressions) => Value::List(
181 expressions
182 .iter()
183 .map(|expression| evaluate_expression(context, expression))
184 .collect(),
185 ),
186 Expression::Builder(name, args) => {
187 if let Some(builder) = context.get_evaluator(name) {
188 let mut local_variables = HashMap::new();
190 for b in args {
191 let (name, expression) = b.borrow();
192 local_variables
193 .insert(name.to_string(), evaluate_expression(context, expression));
194 }
195
196 if let Ok(mut context) =
198 context.spawn_new(vec![local_variables], ContextLocation::template(name))
199 {
200 Value::Text(builder.evaluate(&mut context))
202 } else {
203 Value::text("")
206 }
207 } else {
208 Value::Text(String::new())
209 }
210 }
211 Expression::FunctionCall(name, args) => {
212 if let Some(function) = context.get_function(name) {
213 let args: Vec<Value> = args
214 .iter()
215 .map(|arg| evaluate_expression(context, arg))
216 .collect::<Vec<_>>();
217 function(&args)
218 } else {
219 Value::None
220 }
221 }
222 Expression::IndexOf(expression, index_expression) => {
223 let expression_value = evaluate_expression(context, expression);
224 let index_value = evaluate_expression(context, index_expression);
225 if let Value::List(l) = expression_value {
226 if let Value::Number(i) = index_value {
227 let i = i.round() as usize;
229 return l.into_iter().skip(i).next().unwrap();
231 }
232 }
233
234 Value::None
235 }
236 Expression::Ternary(condition, a, b) => {
238 if evaluate_expression(context, condition.borrow()).bool_or_false() {
239 evaluate_expression(context, a.borrow())
240 } else {
241 evaluate_expression(context, b.borrow())
242 }
243 }
244 }
245}
246
247pub fn evaluate_blocks<'a, 'b, 'c>(
249 context: &mut EvaluationContext<'c, impl Evaluate>,
250 blocks: &[Box<Block<'a, 'b>>],
251) -> String {
252 blocks
253 .iter()
254 .map(|block| evaluate_block(context, block.borrow()))
255 .collect::<Vec<_>>()
256 .join("")
257}
258
259pub fn evaluate_block<'a, 'b, 'c>(
261 context: &mut EvaluationContext<'c, impl Evaluate>,
262 block: &Block,
263) -> String {
264 match block {
265 Block::Source(s) => s.to_string(),
266 Block::Expression(expression) => evaluate_expression(context, *expression).to_string(),
267 Block::Assignment(name, _tt, expression) => {
268 let value = evaluate_expression(context, *expression);
269 context.assign_local_variable(name, value);
270 String::new()
271 }
272 Block::If(if_block) => {
273 let mut s = None;
274
275 for (expression, blocks) in &if_block.if_blocks {
277 if evaluate_expression(context, expression).bool_or_false() {
278 s = Some(evaluate_blocks(context, &blocks));
279 break;
280 }
281 }
282
283 if let Some(s) = s {
285 s
286 } else {
287 if let Some(else_blocks) = &if_block.else_blocks {
288 evaluate_blocks(context, &else_blocks)
290 } else {
291 String::new()
292 }
293 }
294 }
295 Block::For(for_block) => {
296 let value = evaluate_expression(context, for_block.expression);
297 let var_name = for_block.var_name;
298 if let Value::List(l) = value {
299 let mut outs = Vec::new();
301
302 for value in l {
304 context.push_variables(hmap!(
306 var_name.to_string() => value
307 ));
308
309 for block in &for_block.blocks {
311 outs.push(evaluate_block(context, block));
312 }
313
314 context.pop_variables();
316 }
317
318 outs.join("")
319 } else {
320 String::new()
321 }
322 }
323 }
324}
325
326pub fn list_dependencies_expression(expression: &Expression, dependencies: &mut Dependencies) {
329 match expression {
330 Expression::Additive(a, b) | Expression::Multiplicative(a, b) => {
331 for expression in a.iter().chain(b.iter()) {
332 list_dependencies_expression(expression.borrow(), dependencies);
333 }
334 }
335 Expression::Negate(a) | Expression::Not(a) => {
336 list_dependencies_expression(a.borrow(), dependencies);
337 }
338 Expression::Or(a) | Expression::And(a) => {
339 for expression in a {
340 list_dependencies_expression(expression.borrow(), dependencies);
341 }
342 }
343 Expression::Comparison(a, _, b) => {
344 list_dependencies_expression(a.borrow(), dependencies);
345 list_dependencies_expression(b.borrow(), dependencies);
346 }
347 Expression::Variable(name) => {
348 dependencies.add_variable(name);
349 }
350 Expression::Builder(name, args) => {
351 dependencies.add_builder(name);
352 for arg in args {
353 let (_, expression) = arg.borrow();
354 list_dependencies_expression(expression.borrow(), dependencies);
355 }
356 }
357 Expression::FunctionCall(name, args) => {
358 dependencies.add_function(name);
359 for arg in args {
360 list_dependencies_expression(arg, dependencies);
361 }
362 }
363 Expression::Ternary(a, b, c) => {
364 list_dependencies_expression(a.borrow(), dependencies);
365 list_dependencies_expression(b.borrow(), dependencies);
366 list_dependencies_expression(c.borrow(), dependencies);
367 }
368 _ => {}
369 }
370}
371
372pub fn list_dependencies_block(block: &Block, dependencies: &mut Dependencies) {
375 match block {
376 Block::Expression(expression) | Block::Assignment(.., expression) => {
377 list_dependencies_expression(expression, dependencies)
378 }
379 Block::If(if_block) => {
380 for (expression, blocks) in if_block.if_blocks.iter() {
382 list_dependencies_expression(expression, dependencies);
383 for block in blocks.iter() {
384 list_dependencies_block(block, dependencies);
385 }
386 }
387
388 if let Some(else_block) = &if_block.else_blocks {
390 for block in else_block.iter() {
391 list_dependencies_block(block.borrow(), dependencies);
392 }
393 }
394 }
395 Block::For(for_block) => {
396 for block in &for_block.blocks {
397 list_dependencies_block(&block, dependencies);
398 }
399 }
400 Block::Source(_) => {}
401 }
402}
403
404#[cfg(test)]
405mod tests_blocks {
406 use crate::{
407 evaluator::evaluator::EvaluatorBuilder,
408 parser::Parser,
409 tokenizer::{Tokenizer, TokenizerOptions},
410 };
411
412 fn test(source: &str) {
413 let tokens = Tokenizer::new(source, TokenizerOptions::default())
414 .tokenize()
415 .unwrap();
416 let nodes = Parser::new(tokens.as_slice()).parse().unwrap();
417 let mut evaluator_builder = EvaluatorBuilder::new(nodes.as_slice());
418 let blocks = evaluator_builder.build();
419 println!("{:?}", blocks);
420 }
421
422 #[test]
423 fn test_01() {
424 test("abc {{a + 1}} def");
425 }
426
427 #[test]
428 fn test_02() {
429 test("{{# if a > b}} a > b {{#}}");
430 }
431
432 #[test]
433 fn test_03() {
434 test("{{# if a > b}} a > b {{# else }} a <= b {{#}}");
435 }
436
437 #[test]
438 fn test_04() {
439 test("{{# if a > b}} a > b {{# elif a < b }} a < b {{#}}");
440 }
441
442 #[test]
443 fn test_05() {
444 test("{{# if a > b}} part 1 {{# if c > d}} c > d {{# else }} c <= d {{#}} {{# elif a < b }} a < b {{#}}");
445 }
446
447 #[test]
448 fn test_06() {
449 test("{{# if a}} {{b ? @ file1(a = a, b = b) : @ file1(a = a, b = 0)}} {{#}}");
450 }
451}
452
453#[cfg(test)]
454mod tests_evaluator {
455 use std::collections::HashMap;
456
457 use hmap::hmap;
458
459 use crate::{
460 evaluator::evaluation_context::{ContextLocation, EvaluationContextWarnings},
461 parser::Parser,
462 tokenizer::{Tokenizer, TokenizerOptions},
463 value::Value,
464 };
465
466 use super::{
467 evaluation_context::EvaluationContext,
468 evaluator::{Evaluator, EvaluatorBuilder},
469 Evaluate,
470 };
471
472 fn test(
473 source: &str,
474 global_variables: Vec<(&str, Value)>,
475 builders: HashMap<String, Evaluator>,
476 ) -> String {
477 let tokens = Tokenizer::new(source, TokenizerOptions::default())
479 .tokenize()
480 .unwrap();
481 let nodes = Parser::new(tokens.as_slice()).parse().unwrap();
482 let mut evaluator_builder = EvaluatorBuilder::new(nodes.as_slice());
483 let evaluator = evaluator_builder.build_evaluator().unwrap();
484
485 let global_variables = global_variables
487 .into_iter()
488 .map(|(k, v)| (k.to_string(), v));
489 let global_variables = HashMap::from_iter(global_variables);
490
491 let functions = HashMap::new();
492
493 let mut context = EvaluationContext::new(
495 &global_variables,
496 vec![],
497 &builders,
498 &functions,
499 Default::default(),
500 EvaluationContextWarnings::default(),
501 ContextLocation::source("main"),
502 );
503 let out = evaluator.evaluate(&mut context);
504 println!("{}", out);
505 out
506 }
507
508 #[test]
509 fn test_01() {
510 test("abc {{ 1 + 2 }} def", vec![], HashMap::new());
511 }
512
513 #[test]
514 fn test_02() {
515 test(
516 "result: {{ 1 > 2 ? 'item 1' : 'item 2' }}",
517 vec![],
518 HashMap::new(),
519 );
520 }
521
522 #[test]
523 fn test_03() {
524 test("result: {{ unknown_variable }}", vec![], HashMap::new());
525 }
526
527 #[test]
528 fn test_04() {
529 test(
530 "a > b = {{a}} > {{b}} = {{ a > b }}",
531 vec![("a", Value::Number(1.0)), ("b", Value::Number(2.0))],
532 HashMap::new(),
533 );
534 }
535
536 #[test]
537 fn test_05() {
538 test(
539 "a is {{ a > b ? 'bigger than' : a < b ? 'smaller than' : 'equal to'}} b",
540 vec![("a", Value::Number(1.0)), ("b", Value::Number(2.0))],
541 HashMap::new(),
542 );
543 }
544
545 #[test]
546 fn test_06() {
547 test(
548 "a is {{#if a > b}}bigger than{{# elif a < b}}smaller than{{#else}}equal to{{#}} b",
549 vec![("a", Value::Number(1.0)), ("b", Value::Number(1.0))],
550 HashMap::new(),
551 );
552 }
553
554 #[test]
555 fn test_07() {
556 let source = "saying hi to: {{name}}";
558 let tokens = Tokenizer::new(source, TokenizerOptions::default())
560 .tokenize()
561 .unwrap();
562 let nodes = Parser::new(tokens.as_slice()).parse().unwrap();
563 let mut evaluator_builder = EvaluatorBuilder::new(nodes.as_slice());
564 let evaluator = evaluator_builder.build_evaluator().unwrap();
565
566 test(
567 "{{a > b ? @ say_hi(name = 'name ' + a) : @ say_hi(name = 'name ' + b)}}",
568 vec![("a", Value::Number(1.0)), ("b", Value::Number(2.0))],
569 hmap!(
570 format!("say_hi") => evaluator
571 ),
572 );
573 }
574
575 #[test]
576 fn test_08() {
577 let source = "{{a != None ? a : 'default'}}";
578 assert_eq!(
579 &test(source, vec![("a", Value::text("var-a"))], HashMap::new()),
580 "var-a"
581 );
582 assert_eq!(&test(source, vec![], HashMap::new()), "default");
583 }
584}
585
586#[cfg(test)]
587mod tests_contained_evaluator {
588 use std::collections::HashMap;
589
590 use crate::evaluator::{
591 contained_evaluator::ContainedEvaluator,
592 evaluation_context::{ContextLocation, EvaluationContext, EvaluationContextWarnings},
593 Evaluate,
594 };
595
596 #[test]
597 fn test_01() {
598 let global_variables = HashMap::new();
600 let local_variables = vec![];
601 let builders = HashMap::<_, ContainedEvaluator>::new();
602 let functions = HashMap::new();
603
604 let mut context = EvaluationContext::new(
606 &global_variables,
607 local_variables,
608 &builders,
609 &functions,
610 Default::default(),
611 EvaluationContextWarnings::default(),
612 ContextLocation::source("main"),
613 );
614
615 let evaluator = ContainedEvaluator::from_string("1 + 2 = {{ 1 + 2 }}".to_string()).unwrap();
617 println!("{:?}", std::ptr::addr_of!(evaluator));
618 println!("{}", evaluator.evaluator.evaluate(&mut context));
619 let _a = 0;
620 {
621 let moved = evaluator;
622 println!("{:?}", std::ptr::addr_of!(moved));
623 println!("{}", moved.evaluator.evaluate(&mut context));
624 }
625 }
626}