summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lexer.rs5
-rw-r--r--src/lib.rs80
-rw-r--r--src/parser.rs57
-rw-r--r--src/position.rs96
4 files changed, 173 insertions, 65 deletions
diff --git a/src/lexer.rs b/src/lexer.rs
index 5ce7929..c7249b7 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -24,7 +24,6 @@ pub enum SymbolType<'a> {
24 Literal(&'a str), 24 Literal(&'a str),
25 Text(&'a str), 25 Text(&'a str),
26 Error{ what: ErrorType }, 26 Error{ what: ErrorType },
27 EOS,
28} 27}
29 28
30#[derive(Copy,Clone)] 29#[derive(Copy,Clone)]
@@ -36,7 +35,7 @@ pub struct Symbol<'a> {
36 35
37impl<'a> fmt::Debug for Symbol<'a> { 36impl<'a> fmt::Debug for Symbol<'a> {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "{:?} @ {}:{}", self.symbol, self.start.line, self.start.column ) 38 write!(f, "{:?} @ {:?}-{:?}", self.symbol, self.start, self.end )
40 } 39 }
41} 40}
42 41
@@ -64,6 +63,7 @@ impl<'a> Symbol<'a> {
64 } 63 }
65} 64}
66 65
66#[derive(Debug)]
67enum Mode { 67enum Mode {
68 Text, 68 Text,
69 InTag, 69 InTag,
@@ -300,6 +300,7 @@ impl<'a> Lexer<'a> {
300 } 300 }
301 301
302 fn parse_end_tag(&mut self) -> Option<Symbol<'a>> { 302 fn parse_end_tag(&mut self) -> Option<Symbol<'a>> {
303 self.skip_ws();
303 let start_pos = self.pos.clone(); 304 let start_pos = self.pos.clone();
304 if let Some(chr) = self.cur() && chr == '|' { 305 if let Some(chr) = self.cur() && chr == '|' {
305 match self.peek() { 306 match self.peek() {
diff --git a/src/lib.rs b/src/lib.rs
index 5dbb379..208cea1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,22 +5,10 @@ use std::time::SystemTime;
5 5
6mod lexer; 6mod lexer;
7mod parser; 7mod parser;
8mod position;
8 9
9pub use parser::ParseError; 10pub use parser::ParseError;
10 11pub use position::*;
11#[derive(Debug,Copy,Clone)]
12pub struct Position {
13 pub line: u32,
14 pub column: u32,
15}
16
17impl Position {
18 pub fn new( line: u32, column: u32 ) -> Self {
19 Self {
20 line, column,
21 }
22 }
23}
24 12
25#[derive(Debug)] 13#[derive(Debug)]
26pub struct Crimtag { 14pub struct Crimtag {
@@ -29,7 +17,7 @@ pub struct Crimtag {
29} 17}
30 18
31#[derive(PartialEq,Eq,Debug,Clone)] 19#[derive(PartialEq,Eq,Debug,Clone)]
32enum ViewSource { 20pub enum ViewSource {
33 File { 21 File {
34 path: PathBuf, 22 path: PathBuf,
35 loaded: SystemTime, 23 loaded: SystemTime,
@@ -52,7 +40,7 @@ impl View {
52 fn process(&self, input: &Value) -> Result<Value, ParseError> { 40 fn process(&self, input: &Value) -> Result<Value, ParseError> {
53 let mut out_vars = HashMap::new(); 41 let mut out_vars = HashMap::new();
54 for output in &self.outputs { 42 for output in &self.outputs {
55 if let Token::Output(_,_,tokens) = &output.ast_root { 43 if let Token::Output(_,/*_,*/tokens) = &output.ast_root {
56 let mut buf = String::new(); 44 let mut buf = String::new();
57 exec( input, tokens, &mut buf )?; 45 exec( input, tokens, &mut buf )?;
58 out_vars.insert( output.name.clone(), Value::String(buf) ); 46 out_vars.insert( output.name.clone(), Value::String(buf) );
@@ -74,17 +62,9 @@ type Properties = HashMap<String, String>;
74enum Token { 62enum Token {
75 Root(Vec<Token>), 63 Root(Vec<Token>),
76 View(String,Properties,Vec<Token>), 64 View(String,Properties,Vec<Token>),
77 Output(String,Properties,Vec<Token>), 65 Output(String,/*Properties,*/ Vec<Token>),
78 Show(String,Properties), 66 Show(String,Properties),
79 Text(String), 67 Text(String),
80 Literal(String),
81 /*
82 Tag{
83 name: String,
84 params: Vec<String>,
85 props: Properties,
86 children: Vec<Token>
87 },*/
88} 68}
89 69
90#[derive(Debug)] 70#[derive(Debug)]
@@ -203,6 +183,18 @@ impl Crimtag {
203 } 183 }
204 } 184 }
205 185
186 pub fn get_view_source(&self, view: &str) -> Option<ViewSource> {
187 if let Some(view) = self.views.get(view) {
188 if view.source < self.sources.len() {
189 Some(self.sources[view.source].clone())
190 } else {
191 None
192 }
193 } else {
194 None
195 }
196 }
197
206 pub fn view_partial(&self, view: &str, input: &Value ) -> Result<Value,ParseError> { 198 pub fn view_partial(&self, view: &str, input: &Value ) -> Result<Value,ParseError> {
207 if let Some(view) = self.views.get(view) { 199 if let Some(view) = self.views.get(view) {
208 return view.process( input ) 200 return view.process( input )
@@ -213,12 +205,10 @@ impl Crimtag {
213 205
214 pub fn view(&self, view: &str, input: &Value ) -> Result<String,ParseError> { 206 pub fn view(&self, view: &str, input: &Value ) -> Result<String,ParseError> {
215 if let Some(view) = self.views.get( view ) { 207 if let Some(view) = self.views.get( view ) {
216 let mut output = view.process( input )?; 208 let output = view.process( input )?;
217 if let Some(l) = &view.layout { 209 if let Some(l) = &view.layout {
218 println!("Layout: {}", l );
219 self.view( l, &output ) 210 self.view( l, &output )
220 } else { 211 } else {
221 println!("No layout, at the top");
222 if let Value::Dictionary(mut d) = output && 212 if let Value::Dictionary(mut d) = output &&
223 let Some(content) = d.remove("content") && 213 let Some(content) = d.remove("content") &&
224 let Value::String(s) = content { 214 let Value::String(s) = content {
@@ -242,18 +232,40 @@ fn exec(input: &Value, tokens: &Vec<Token>, buf: &mut String) -> Result<(),Parse
242 println!("Too high!?"); 232 println!("Too high!?");
243 // Error? 233 // Error?
244 } 234 }
245 Token::Show(s,_) => { 235 Token::Show(s,p) => {
236 let format = if let Some(s) = p.get("format") {
237 s
238 } else {
239 &"".to_string()
240 };
246 if let Value::Dictionary(d) = input && 241 if let Value::Dictionary(d) = input &&
247 let Some(Value::String(s)) = d.get(s) { 242 let Some(value) = d.get(s) {
248 buf.push_str(s); 243 match value {
244 Value::Dictionary(_) => {
245 buf.push_str("<dictionary>");
246 }
247 Value::List(_) => {
248 buf.push_str("<list>");
249 }
250 Value::String(s) => {
251 buf.push_str(s);
252 }
253 Value::Int(i) => {
254 buf.push_str(&i.to_string());
255 }
256 Value::Float(f) => {
257 if format == "" {
258 buf.push_str(&f.to_string());
259 } else {
260 buf.push_str(&f.to_string());
261 }
262 }
263 }
249 } 264 }
250 } 265 }
251 Token::Text(s) => { 266 Token::Text(s) => {
252 buf.push_str( s ); 267 buf.push_str( s );
253 } 268 }
254 Token::Literal(..) => {
255 println!("Literal!?");
256 }
257 } 269 }
258 } 270 }
259 Ok(()) 271 Ok(())
diff --git a/src/parser.rs b/src/parser.rs
index 13e89aa..c7a8abe 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -17,6 +17,13 @@ impl ParseError {
17 what: what.to_string(), 17 what: what.to_string(),
18 } 18 }
19 } 19 }
20
21 pub fn eos( context: &str ) -> Self {
22 ParseError {
23 position: Position::none(),
24 what: format!("Premature end of stream while looking for {}", context),
25 }
26 }
20} 27}
21 28
22impl fmt::Display for ParseError { 29impl fmt::Display for ParseError {
@@ -61,12 +68,9 @@ impl<'a> Context<'a> {
61 self.cur[(self.icur+1)%2] 68 self.cur[(self.icur+1)%2]
62 } 69 }
63 70
64 pub fn check_unwrapped<T: Fn( &SymbolType, &SymbolType ) -> bool>(&self, f: T) -> ParseResult<bool> { 71 pub fn check_unwrapped<T: Fn( &SymbolType, &SymbolType ) -> bool>(&self, context: &str, f: T) -> ParseResult<bool> {
65 if self.cur().is_none() || self.peek().is_none() { 72 if self.cur().is_none() || self.peek().is_none() {
66 Err(ParseError{ 73 Err(ParseError::eos( context ))
67 position: Position::new(0,0),
68 what: "Unexpected end of stream.".to_string()
69 })
70 } else { 74 } else {
71 Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) 75 Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol()))
72 } 76 }
@@ -74,19 +78,16 @@ impl<'a> Context<'a> {
74} 78}
75 79
76trait SymbolHelper { 80trait SymbolHelper {
77 fn is<T: Fn( &SymbolType ) -> bool>(&self, f: T ) -> ParseResult<bool>; 81 fn is<T: Fn( &SymbolType ) -> bool>(&self, context: &str, f: T ) -> ParseResult<bool>;
78 fn is_valid_tag_name(&self) -> ParseResult<bool>; 82 fn is_valid_tag_name(&self) -> ParseResult<bool>;
79} 83}
80 84
81impl<'a> SymbolHelper for Option<Symbol<'a>> { 85impl<'a> SymbolHelper for Option<Symbol<'a>> {
82 fn is<T: Fn( &SymbolType ) -> bool>(&self, f: T ) -> ParseResult<bool> { 86 fn is<T: Fn( &SymbolType ) -> bool>(&self, context: &str, f: T ) -> ParseResult<bool> {
83 if let Some(st) = self { 87 if let Some(st) = self {
84 Ok(f( &st.symbol() )) 88 Ok(f( &st.symbol() ))
85 } else { 89 } else {
86 Err(ParseError{ 90 Err(ParseError::eos( context ))
87 position: Position::new(0,0),
88 what: "Unexpected end of stream.".to_string()
89 })
90 } 91 }
91 } 92 }
92 93
@@ -256,10 +257,7 @@ impl Parser {
256 //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() ); 257 //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() );
257 loop { 258 loop {
258 if ctx.cur().is_none() { 259 if ctx.cur().is_none() {
259 return Err(ParseError{ 260 return Err(ParseError::eos(format!("close tag for {:?}", tb.name()).as_str()))
260 position: Position::new(0,0),
261 what: "Unexpected end of stream.".to_string()
262 });
263 } 261 }
264 match ctx.cur().unwrap().symbol() { 262 match ctx.cur().unwrap().symbol() {
265 SymbolType::Text(s) => { 263 SymbolType::Text(s) => {
@@ -282,7 +280,7 @@ impl Parser {
282 // Everything is either text or output 280 // Everything is either text or output
283 if !any_outputs { 281 if !any_outputs {
284 // Special case, if it's only text then we create an implicit output. 282 // Special case, if it's only text then we create an implicit output.
285 tb.add_child(Token::Output("content".to_string(), Properties::new(), children )); 283 tb.add_child(Token::Output("content".to_string(), /*Properties::new(),*/ children ));
286 } 284 }
287 else { 285 else {
288 // Standard case, outputs are included, text is 286 // Standard case, outputs are included, text is
@@ -303,7 +301,7 @@ impl Parser {
303 }); 301 });
304 } else { 302 } else {
305 // No outputs at all, we create an implict output 303 // No outputs at all, we create an implict output
306 tb.add_child(Token::Output("content".to_string(), Properties::new(), children )); 304 tb.add_child(Token::Output("content".to_string(), /*Properties::new(), */children ));
307 } 305 }
308 } 306 }
309 307
@@ -339,11 +337,11 @@ impl Parser {
339 tb.set_name( name_sym ); 337 tb.set_name( name_sym );
340 } 338 }
341 _ => { 339 _ => {
342 return Err(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpecetd symbol".to_string()}); 340 return Err(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpected symbol".to_string()});
343 } 341 }
344 } 342 }
345 } else { 343 } else {
346 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); 344 return Err(ParseError::eos("tag type"));
347 } 345 }
348 346
349 self.parse_tag_params( ctx, &mut tb )?; 347 self.parse_tag_params( ctx, &mut tb )?;
@@ -358,7 +356,10 @@ impl Parser {
358 tb.set_type( TagType::Unary ); 356 tb.set_type( TagType::Unary );
359 } 357 }
360 _ => { 358 _ => {
361 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); 359 return Err(ParseError::new(
360 end_sym.start().clone(),
361 format!("Unexpected symbol {:?} looking for end of tag.", end_sym.symbol()).as_str()
362 ));
362 } 363 }
363 } 364 }
364 } 365 }
@@ -369,7 +370,7 @@ impl Parser {
369 } 370 }
370 371
371 fn parse_end_tag<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult<Symbol<'a>> { 372 fn parse_end_tag<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult<Symbol<'a>> {
372 if !ctx.cur().is(|s| *s == SymbolType::StartPoint )? { 373 if !ctx.cur().is("end tag",|s| *s == SymbolType::StartPoint )? {
373 return Err(ParseError{ 374 return Err(ParseError{
374 position: *ctx.cur().unwrap().start(), 375 position: *ctx.cur().unwrap().start(),
375 what: "Invalid end tag?".to_string(), 376 what: "Invalid end tag?".to_string(),
@@ -382,7 +383,7 @@ impl Parser {
382 }); 383 });
383 } 384 }
384 let name = ctx.cur().unwrap(); 385 let name = ctx.cur().unwrap();
385 if !ctx.next().is(|s| *s == SymbolType::EndFlat )? { 386 if !ctx.next().is("end of end tag", |s| *s == SymbolType::EndFlat )? {
386 return Err(ParseError{ 387 return Err(ParseError{
387 position: *ctx.cur().unwrap().start(), 388 position: *ctx.cur().unwrap().start(),
388 what: "Tag should be <| |] style end tag.".to_string(), 389 what: "Tag should be <| |] style end tag.".to_string(),
@@ -399,7 +400,7 @@ impl Parser {
399 400
400 loop { 401 loop {
401 if ctx.cur().is_none() { 402 if ctx.cur().is_none() {
402 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); 403 return Err(ParseError::eos(format!("close tag for {:?}", tb.name()).as_str()));
403 } 404 }
404 match ctx.cur().unwrap().symbol() { 405 match ctx.cur().unwrap().symbol() {
405 SymbolType::Text(s) => { 406 SymbolType::Text(s) => {
@@ -435,8 +436,7 @@ impl Parser {
435 fn parse_tag_params(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { 436 fn parse_tag_params(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> {
436 loop { 437 loop {
437 if ctx.cur().is_none() { 438 if ctx.cur().is_none() {
438 439 return Err(ParseError::eos("tag parameters"));
439 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()});
440 } 440 }
441 match ctx.cur().unwrap().symbol() { 441 match ctx.cur().unwrap().symbol() {
442 SymbolType::Literal(s) => { 442 SymbolType::Literal(s) => {
@@ -454,7 +454,7 @@ impl Parser {
454 fn parse_tag_props(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { 454 fn parse_tag_props(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> {
455 loop { 455 loop {
456 if ctx.cur().is_none() { 456 if ctx.cur().is_none() {
457 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); 457 return Err(ParseError::eos("tag properties"));
458 } 458 }
459 if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { 459 if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() {
460 if ctx.peek().is_some_and(|s|s.check_type(|t| matches!(t,SymbolType::Equals))) { 460 if ctx.peek().is_some_and(|s|s.check_type(|t| matches!(t,SymbolType::Equals))) {
@@ -466,7 +466,7 @@ impl Parser {
466 return Err(ParseError{position: Position::new(0,0), what: "Expected quoted literal string".to_string()}); 466 return Err(ParseError{position: Position::new(0,0), what: "Expected quoted literal string".to_string()});
467 } 467 }
468 } else { 468 } else {
469 return Err(ParseError{position:Position::new(0,0), what: "Expected = ".to_string()}); 469 break;
470 } 470 }
471 } else { 471 } else {
472 break; 472 break;
@@ -482,7 +482,6 @@ enum TagType {
482 Unknown, 482 Unknown,
483 Unary, 483 Unary,
484 BinaryOpen, 484 BinaryOpen,
485 BinaryClose,
486} 485}
487 486
488struct TagBuilder<'a> { 487struct TagBuilder<'a> {
@@ -573,7 +572,7 @@ impl<'a> TagBuilder<'a> {
573 Ok(Token::View(self.params.swap_remove(0), self.props, self.children)) 572 Ok(Token::View(self.params.swap_remove(0), self.props, self.children))
574 } 573 }
575 SymbolType::Output => { 574 SymbolType::Output => {
576 Ok(Token::Output(self.params.swap_remove(0), self.props, self.children)) 575 Ok(Token::Output(self.params.swap_remove(0), /*self.props,*/ self.children))
577 } 576 }
578 SymbolType::Show => { 577 SymbolType::Show => {
579 Ok(Token::Show(self.params.swap_remove(0), self.props)) 578 Ok(Token::Show(self.params.swap_remove(0), self.props))
diff --git a/src/position.rs b/src/position.rs
new file mode 100644
index 0000000..24f5309
--- /dev/null
+++ b/src/position.rs
@@ -0,0 +1,96 @@
1use std::fmt;
2use std::cmp::Ordering;
3
4#[derive(Copy,Clone)]
5pub struct Position {
6 pub line: u32,
7 pub column: u32,
8}
9
10impl Position {
11 pub fn new( line: u32, column: u32 ) -> Self {
12 Self {
13 line, column,
14 }
15 }
16
17 pub fn none() -> Self {
18 Self {
19 line: 0,
20 column: 0,
21 }
22 }
23
24 pub fn is_none(&self) -> bool {
25 self.line == 0 || self.column == 0
26 }
27}
28
29impl fmt::Debug for Position {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 if self.is_none() {
32 write!(f, "none")
33 } else {
34 write!(f, "{}:{}", self.line, self.column )
35 }
36 }
37}
38
39impl PartialOrd for Position {
40 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
41 let ord = self.line.partial_cmp( &other.line );
42 if Some(Ordering::Equal) == ord {
43 self.column.partial_cmp( &other.column )
44 } else {
45 ord
46 }
47 }
48}
49
50impl Ord for Position {
51 fn cmp(&self, other: &Self) -> Ordering {
52 let ord = self.line.cmp( &other.line );
53 if Ordering::Equal == ord {
54 self.column.cmp( &other.column )
55 } else {
56 ord
57 }
58 }
59}
60
61impl PartialEq for Position {
62 fn eq(&self, other: &Self) -> bool {
63 self.line == other.line && self.column == other.column
64 }
65}
66
67impl Eq for Position {}
68
69#[derive(Copy,Clone)]
70pub struct Range {
71 start: Position,
72 end: Position,
73}
74
75impl Range {
76 pub fn new( start: Position, end: Position ) -> Self {
77 Self {
78 start, end,
79 }
80 }
81
82 pub fn include(&mut self, pos: &Position ) {
83 if *pos < self.start {
84 self.start = pos.clone();
85 }
86 if *pos > self.end {
87 self.end = pos.clone();
88 }
89 }
90}
91
92impl fmt::Debug for Range {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 write!(f, "{:?}-{:?}", self.start, self.end )
95 }
96}