summaryrefslogtreecommitdiff
path: root/src/parser.rs
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-08 21:45:30 -0700
committerMike Buland <mike@xagasoft.com>2026-06-08 21:45:30 -0700
commit0f2bd09d269862105e603a9865201f521f49490b (patch)
tree5326c452c41b5bd4a521ad5fa216dd999f31b5f8 /src/parser.rs
parent0736240f54ac90ded4d96b3ac35fc8571b141d1a (diff)
downloadcrimtag-0f2bd09d269862105e603a9865201f521f49490b.tar.gz
crimtag-0f2bd09d269862105e603a9865201f521f49490b.tar.bz2
crimtag-0f2bd09d269862105e603a9865201f521f49490b.tar.xz
crimtag-0f2bd09d269862105e603a9865201f521f49490b.zip
It works again! and more!
About to change a few things: - symbols and errors will have a range not a position - remove view/output token type, those should just be View and Output structs - Figure out some formatting stuff? (add a dep? I dunno) - Move to non-quoted dot-delimeted variable references. - Add loops. - Add conditionals? - Add more!
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs57
1 files changed, 28 insertions, 29 deletions
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))