-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathdocument.rs
More file actions
100 lines (85 loc) · 3.23 KB
/
document.rs
File metadata and controls
100 lines (85 loc) · 3.23 KB
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
93
94
95
96
97
98
99
100
use std::fs::read_to_string;
use std::path::PathBuf;
use anathema_store::smallmap::SmallMap;
use crate::blueprints::Blueprint;
use crate::components::{ComponentTemplates, SourceKind, TemplateSource};
use crate::error::{Error, ErrorKind, Result};
use crate::expressions::Expressions;
use crate::statements::eval::Scope;
use crate::statements::parser::Parser;
use crate::statements::{Context, Statements};
use crate::strings::Strings;
use crate::token::Tokens;
use crate::{ComponentBlueprintId, Lexer, Variables};
/// A document containing templates and components
/// ```
/// # use anathema_templates::Document;
/// let mut doc = Document::new("text 'I am a widget'");
/// ```
pub struct Document {
template: TemplateSource,
pub strings: Strings,
pub expressions: Expressions,
components: ComponentTemplates,
pub hot_reload: bool,
}
impl Document {
pub fn new(template: impl Into<TemplateSource>) -> Self {
let template = template.into();
Self {
template,
strings: Strings::new(),
expressions: Expressions::empty(),
components: ComponentTemplates::new(),
hot_reload: true,
}
}
#[allow(private_bounds)]
pub fn add_component(&mut self, name: impl Into<String>, src: SourceKind) -> Result<ComponentBlueprintId> {
let name = name.into();
let name = self.strings.push(name);
let component_src = match src {
SourceKind::Str(s) => TemplateSource::InMemory(s),
SourceKind::Path(path) => {
let template = match read_to_string(&path) {
Err(e) => return Err(Error::new(Some(path), e)),
Ok(t) => t,
};
TemplateSource::File { path, template }
}
};
let id = self.components.insert(name, component_src);
Ok(id)
}
pub fn compile(&mut self, globals: &mut Variables) -> Result<Blueprint> {
globals.reset_globals();
self.expressions.clear();
let tokens = Lexer::new(&self.template, &mut self.strings).collect::<Result<Vec<_>>>()?;
let tokens = Tokens::new(tokens, self.template.len());
let parser = Parser::new(tokens, &mut self.strings, &self.template, &mut self.components);
let statements = parser.collect::<Result<Statements>>()?;
let mut context = Context {
template: &self.template,
variables: globals,
strings: &mut self.strings,
expressions: &mut self.expressions,
components: &mut self.components,
slots: SmallMap::empty(),
current_component_parent: None,
};
let mut blueprints = Scope::new(statements).eval(&mut context)?;
match blueprints.is_empty() {
true => Err(Error::no_template(ErrorKind::EmptyTemplate)),
false => Ok(blueprints.remove(0)),
}
}
pub fn template_paths(&self) -> impl Iterator<Item = &PathBuf> {
self.components.file_paths()
}
pub fn reload_templates(&mut self) -> Result<()> {
self.components.reload()
}
pub fn get_component_source(&self, component_id: ComponentBlueprintId) -> Option<PathBuf> {
self.components.path(component_id)
}
}