1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
use rubble_templates_core::evaluator::{Context, Evaluator};
use rubble_templates_core::template::{EvaluableMixedContent, TemplateSlice};
use rubble_templates_core::compiler::{CompilationError, Compiler};
use rubble_templates_core::units::Position;
use crate::simple::template::{Template, EvaluableMixedContentIterator, START_PATTERN, END_PATTERN};
use crate::parser::parse_ast;
pub struct TemplateCompiler<E: Evaluator> {
engine: E
}
impl<E> TemplateCompiler<E> where E: Evaluator {
pub fn new(engine: E) -> TemplateCompiler<E> {
TemplateCompiler {
engine
}
}
}
impl<'a, E> Compiler<&'a Template> for TemplateCompiler<E> where E: Evaluator {
type Item = TemplateSlice<'a>;
type ItemIterator = EvaluableMixedContentIterator<'a, Template>;
fn compile<C>(&self, content: C, context: Context) -> Result<String, CompilationError>
where C: EvaluableMixedContent<Item=Self::Item, IntoIter=Self::ItemIterator> {
let mut result = String::new();
let mut context = context;
let context = &mut context;
for item in content {
let compiled = match item {
TemplateSlice::Text { value, .. } => value.to_string(),
TemplateSlice::Code { value, start_position, .. } => self.engine
.evaluate(&parse_ast(value, START_PATTERN, END_PATTERN), context)
.map_err(|err| CompilationError::EvaluationFailed {
error: err,
position: Position::Absolute(start_position),
source: value.to_string(),
})?,
};
result.push_str(compiled.as_str());
}
Ok(result)
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use rubble_templates_core::evaluator::{Context, SyntaxError, EvaluationError};
use rubble_templates_core::units::Position;
use crate::simple::template::Template;
use crate::simple::evaluator::SimpleEvaluationEngine;
use crate::simple::compiler::TemplateCompiler;
use rubble_templates_core::compiler::{Compiler, CompilationError};
#[test]
fn should_compile_template() {
let template = Template::from("Some simple-template. {{ variable }} - or something".to_string());
let engine = SimpleEvaluationEngine::from(HashMap::new());
let compiler = TemplateCompiler::new(engine);
let mut variables = HashMap::new();
variables.insert("variable".to_string(), "Hello world".to_string());
let result = compiler.compile(&template, Context::with_variables(variables));
assert_eq!(result, Ok("Some simple-template. Hello world - or something".to_string()));
}
#[test]
fn should_return_error_during_evaluation() {
let template = Template::from("Should fail. {{ variable }}".to_string());
let engine = SimpleEvaluationEngine::from(HashMap::new());
let compiler = TemplateCompiler::new(engine);
let result = compiler.compile(&template, Context::empty());
assert_eq!(result, Err(CompilationError::EvaluationFailed {
error: SyntaxError::at_position(Position::RelativeToCodeStart(1), EvaluationError::UnknownSymbol {
symbol: "variable".to_string()
}
),
position: Position::Absolute(13),
source: "{{ variable }}".to_string()
}));
}
}