summaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs132
1 files changed, 89 insertions, 43 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 7790b9a..a2bfc37 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -38,14 +38,14 @@ struct View {
38} 38}
39 39
40impl View { 40impl View {
41 fn process(&self, input: &Value) -> Result<Value, ParseError> { 41 fn process(&self, input: &impl MappedStructure) -> Result<Context, ParseError> {
42 let mut out_vars = HashMap::new(); 42 let mut out_vars = Context::new();
43 for output in &self.outputs { 43 for output in &self.outputs {
44 let mut buf = String::new(); 44 let mut buf = String::new();
45 exec( input, &output.code, &mut buf )?; 45 exec( input, &output.code, &mut buf )?;
46 out_vars.insert( output.name.clone(), Value::String(buf) ); 46 out_vars.insert( output.name.clone(), Value::String(buf) );
47 } 47 }
48 Ok(Value::Dictionary(out_vars)) 48 Ok(out_vars)
49 } 49 }
50} 50}
51 51
@@ -59,17 +59,60 @@ type Properties = HashMap<String, String>;
59 59
60#[derive(Debug)] 60#[derive(Debug)]
61enum Token { 61enum Token {
62 Show(String,Properties), 62 Show(Identifier,Properties),
63 Text(String), 63 Text(String),
64} 64}
65 65
66#[derive(Debug)] 66#[derive(Debug,Clone)]
67pub enum Value { 67pub enum Value {
68 Dictionary(HashMap<String,Value>), 68 Dictionary(HashMap<String,Value>),
69 List(Vec<Value>), 69 List(Vec<Value>),
70 String(String), 70 String(String),
71 Int(i64), 71 Int(i64),
72 Float(f64), 72 Float(f64),
73 Identifier(Identifier),
74}
75
76#[derive(Debug,Clone)]
77pub enum IdentifierValue {
78 Name(String),
79 Index(usize),
80}
81
82pub type Identifier = Vec<IdentifierValue>;
83pub type Context = HashMap<String,Value>;
84
85pub trait MappedStructure {
86 fn get_value(&self, id: &Identifier) -> Option<Value>;
87}
88
89impl MappedStructure for Context {
90 fn get_value(&self, id: &Identifier) -> Option<Value> {
91 if id.len() == 0 {
92 return None;
93 }
94 let mut cur_val : Option<&Value> = if let IdentifierValue::Name(s) = &id[0] {
95 self.get(s)
96 } else {
97 return None;
98 };
99 if cur_val.is_none() {
100 return None;
101 }
102
103 for idx in 1..id.len() {
104 if let IdentifierValue::Name(s) = &id[idx] &&
105 let Some(Value::Dictionary(d)) = &cur_val {
106 cur_val.replace( if let Some(v) = d.get(s) {
107 v
108 } else {
109 return None;
110 });
111 }
112 }
113
114 return cur_val.cloned();
115 }
73} 116}
74 117
75impl Crimtag { 118impl Crimtag {
@@ -157,7 +200,7 @@ impl Crimtag {
157 } 200 }
158 } 201 }
159 202
160 pub fn render_partial(&self, view: &str, input: &Value ) -> Result<Value,ParseError> { 203 pub fn render_partial(&self, view: &str, input: &impl MappedStructure ) -> Result<Context,ParseError> {
161 if let Some(view) = self.views.get(view) { 204 if let Some(view) = self.views.get(view) {
162 return view.process( input ) 205 return view.process( input )
163 } else { 206 } else {
@@ -165,14 +208,13 @@ impl Crimtag {
165 } 208 }
166 } 209 }
167 210
168 pub fn render(&self, view: &str, input: &Value ) -> Result<String,ParseError> { 211 pub fn render(&self, view: &str, input: &impl MappedStructure ) -> Result<String,ParseError> {
169 if let Some(view) = self.views.get( view ) { 212 if let Some(view) = self.views.get( view ) {
170 let output = view.process( input )?; 213 let mut output = view.process( input )?;
171 if let Some(l) = &view.layout { 214 if let Some(l) = &view.layout {
172 self.render( l, &output ) 215 self.render( l, &output )
173 } else { 216 } else {
174 if let Value::Dictionary(mut d) = output && 217 if let Some(content) = output.remove("content") &&
175 let Some(content) = d.remove("content") &&
176 let Value::String(s) = content { 218 let Value::String(s) = content {
177 219
178 Ok(s) 220 Ok(s)
@@ -187,38 +229,40 @@ impl Crimtag {
187 } 229 }
188} 230}
189 231
190fn exec(input: &Value, tokens: &Vec<Token>, buf: &mut String) -> Result<(),ParseError> { 232fn exec(input: &impl MappedStructure, tokens: &Vec<Token>, buf: &mut String) -> Result<(),ParseError> {
191 for token in tokens { 233 for token in tokens {
192 match token { 234 match token {
193 Token::Show(s,p) => { 235 Token::Show(ident,p) => {
194 let format = if let Some(s) = p.get("format") { 236 let format = if let Some(s) = p.get("format") {
195 s 237 s
196 } else { 238 } else {
197 &"".to_string() 239 &"".to_string()
198 }; 240 };
199 if let Value::Dictionary(d) = input && 241 if let Some(value) = input.get_value( &ident ) {
200 let Some(value) = d.get(s) { 242 match value {
201 match value { 243 Value::Dictionary(_) => {
202 Value::Dictionary(_) => { 244 buf.push_str("<dictionary>");
203 buf.push_str("<dictionary>"); 245 }
204 } 246 Value::List(_) => {
205 Value::List(_) => { 247 buf.push_str("<list>");
206 buf.push_str("<list>"); 248 }
207 } 249 Value::String(s) => {
208 Value::String(s) => { 250 buf.push_str(s.as_str());
209 buf.push_str(s); 251 }
210 } 252 Value::Int(i) => {
211 Value::Int(i) => { 253 buf.push_str(&i.to_string());
212 buf.push_str(&i.to_string()); 254 }
213 } 255 Value::Float(f) => {
214 Value::Float(f) => { 256 if format == "" {
215 if format == "" { 257 buf.push_str(&f.to_string());
216 buf.push_str(&f.to_string()); 258 } else {
217 } else { 259 buf.push_str(&f.to_string());
218 buf.push_str(&f.to_string());
219 }
220 } 260 }
221 } 261 }
262 Value::Identifier(_) => {
263 // ???
264 }
265 }
222 } 266 }
223 } 267 }
224 Token::Text(s) => { 268 Token::Text(s) => {
@@ -254,14 +298,14 @@ mod tests {
254 let mut ct = Crimtag::new(); 298 let mut ct = Crimtag::new();
255 if let Err(e) = ct.load_static(r#"Here is a sample 299 if let Err(e) = ct.load_static(r#"Here is a sample
256[|view "index" theme="standard"|><html><body>Hi</body></html><|view|] 300[|view "index" theme="standard"|><html><body>Hi</body></html><|view|]
257That was fun! now a placeholder: [|view "placeholder"|] and now one with an implicit [|view "simple"|>Body [|show "content"|] and end<|view|] aoeu 301That was fun! now a placeholder: [|view "placeholder"|] and now one with an implicit [|view "simple"|>Body -> [|show content|] <- and end<|view|] aoeu
258 302
259[|view "index" layout="simple"|>Whatever man!<|view|] 303[|view "person" layout="simple"|>Welcome [|show person.last_name|], [|show person.first_name|]! It's lovely to see you again.<|view|]
260 304
261Now with explicit outputs: 305Now with explicit outputs:
262[|view "complex"|> 306[|view "complex"|>
263 [|output "content"|> 307 [|output "content"|>
264 Here's a [|show "name"|]. 308 Here's a [|show name|].
265 <|output|] 309 <|output|]
266 [|output "sidebar"|> 310 [|output "sidebar"|>
267 What's up world? 311 What's up world?
@@ -274,13 +318,15 @@ Now with explicit outputs:
274 } else { 318 } else {
275 println!("It finished"); 319 println!("It finished");
276 if let Ok(v) = ct.render( 320 if let Ok(v) = ct.render(
277 "index", 321 "person",
278 &Value::Dictionary( 322 &Context::from([
279 HashMap::from([ 323 ("hi".to_string(),Value::String("hi".to_string())),
280 ("hi".to_string(),Value::String("hi".to_string())) 324 ("person".to_string(),Value::Dictionary(HashMap::from([
281 ]) 325 ("first_name".to_string(), Value::String("Bob".to_string())),
282 ) 326 ("last_name".to_string(), Value::String("Smith".to_string())),
283 ) { 327 ]))),
328 ])
329 ) {
284 println!("View result: {:?}", v ); 330 println!("View result: {:?}", v );
285 } else { 331 } else {
286 println!("Error?"); 332 println!("Error?");