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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
use std::ops::{Add, AddAssign, Deref};
use std::rc::Rc;
use super::Value;
use crate::exec::ExecContext;
use crate::syntax::{Expr, SyntaxTree};
use crate::util::EcoString;
/// A template value: `[*Hi* there]`.
#[derive(Debug, Default, Clone)]
pub struct Template {
nodes: Rc<Vec<TemplateNode>>,
}
impl Template {
/// Create a new template from a vector of nodes.
pub fn new(nodes: Vec<TemplateNode>) -> Self {
Self { nodes: Rc::new(nodes) }
}
/// Iterate over the contained template nodes.
pub fn iter(&self) -> impl Iterator<Item = &TemplateNode> + '_ {
self.nodes.iter()
}
}
impl From<TemplateTree> for Template {
fn from(tree: TemplateTree) -> Self {
Self::new(vec![TemplateNode::Tree(tree)])
}
}
impl From<TemplateFunc> for Template {
fn from(func: TemplateFunc) -> Self {
Self::new(vec![TemplateNode::Func(func)])
}
}
impl From<EcoString> for Template {
fn from(string: EcoString) -> Self {
Self::new(vec![TemplateNode::Str(string)])
}
}
impl PartialEq for Template {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.nodes, &other.nodes)
}
}
impl Add for Template {
type Output = Self;
fn add(mut self, rhs: Self) -> Self::Output {
self += rhs;
self
}
}
impl AddAssign for Template {
fn add_assign(&mut self, rhs: Template) {
let sink = Rc::make_mut(&mut self.nodes);
match Rc::try_unwrap(rhs.nodes) {
Ok(source) => sink.extend(source),
Err(rc) => sink.extend(rc.iter().cloned()),
}
}
}
impl Add<EcoString> for Template {
type Output = Self;
fn add(mut self, rhs: EcoString) -> Self::Output {
Rc::make_mut(&mut self.nodes).push(TemplateNode::Str(rhs));
self
}
}
impl Add<Template> for EcoString {
type Output = Template;
fn add(self, mut rhs: Template) -> Self::Output {
Rc::make_mut(&mut rhs.nodes).insert(0, TemplateNode::Str(self));
rhs
}
}
/// One node of a template.
///
/// Evaluating a template expression creates only a single node. Adding multiple
/// templates can yield multi-node templates.
#[derive(Debug, Clone)]
pub enum TemplateNode {
/// A template that was evaluated from a template expression.
Tree(TemplateTree),
/// A function template that can implement custom behaviour.
Func(TemplateFunc),
/// A template that was converted from a string.
Str(EcoString),
}
/// A template that consists of a syntax tree plus already evaluated
/// expressions.
#[derive(Debug, Clone)]
pub struct TemplateTree {
/// The syntax tree of the corresponding template expression.
pub tree: Rc<SyntaxTree>,
/// The evaluated expressions in the syntax tree.
pub map: ExprMap,
}
/// A map from expressions to the values they evaluated to.
///
/// The raw pointers point into the expressions contained in some
/// [`SyntaxTree`]. Since the lifetime is erased, the tree could go out of scope
/// while the hash map still lives. Although this could lead to lookup panics,
/// it is not unsafe since the pointers are never dereferenced.
pub type ExprMap = HashMap<*const Expr, Value>;
/// A reference-counted dynamic template node that can implement custom
/// behaviour.
#[derive(Clone)]
pub struct TemplateFunc(Rc<dyn Fn(&mut ExecContext)>);
impl TemplateFunc {
/// Create a new function template from a rust function or closure.
pub fn new<F>(f: F) -> Self
where
F: Fn(&mut ExecContext) + 'static,
{
Self(Rc::new(f))
}
}
impl Deref for TemplateFunc {
type Target = dyn Fn(&mut ExecContext);
fn deref(&self) -> &Self::Target {
self.0.as_ref()
}
}
impl Debug for TemplateFunc {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("TemplateFunc").finish()
}
}
|