summaryrefslogtreecommitdiff
path: root/src/parser.rs
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-08 12:32:06 -0700
committerMike Buland <mike@xagasoft.com>2026-06-08 12:32:06 -0700
commit3e60b2746bb95cfcd9b7fa4b7ed9e1c72259fb23 (patch)
tree3034717e3bcaeb4f93b03dc89ce81f77feda9bc7 /src/parser.rs
parent55750a223008b256fddd8636ff4d474f959c8a23 (diff)
downloadcrimtag-3e60b2746bb95cfcd9b7fa4b7ed9e1c72259fb23.tar.gz
crimtag-3e60b2746bb95cfcd9b7fa4b7ed9e1c72259fb23.tar.bz2
crimtag-3e60b2746bb95cfcd9b7fa4b7ed9e1c72259fb23.tar.xz
crimtag-3e60b2746bb95cfcd9b7fa4b7ed9e1c72259fb23.zip
It parses correctly for everything defined.
I think I'll change fragment to view, it's nicer and shorter.
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs236
1 files changed, 206 insertions, 30 deletions
diff --git a/src/parser.rs b/src/parser.rs
index 368a246..1591c8b 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -51,12 +51,45 @@ impl<'a> Context<'a> {
51 pub fn peek(&self) -> Option<Symbol<'a>> { 51 pub fn peek(&self) -> Option<Symbol<'a>> {
52 self.cur[(self.icur+1)%2] 52 self.cur[(self.icur+1)%2]
53 } 53 }
54
55 pub fn check_unwrapped<T: Fn( &SymbolType, &SymbolType ) -> bool>(&self, f: T) -> ParseResult<bool> {
56 if self.cur().is_none() || self.peek().is_none() {
57 Err(ParseError{
58 position: Position::new(0,0),
59 what: "Unexpected end of stream.".to_string()
60 })
61 } else {
62 Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol()))
63 }
64 }
65}
66
67trait SymbolHelper {
68 fn is<T: Fn( &SymbolType ) -> bool>(&self, f: T ) -> ParseResult<bool>;
69 fn is_valid_tag_name(&self) -> ParseResult<bool>;
54} 70}
55 71
56impl Option<Symbol> { 72impl<'a> SymbolHelper for Option<Symbol<'a>> {
57 pub fn is<T: Fn( &SymbolType ) -> bool>(&self, f: T ) -> ParseError<bool> { 73 fn is<T: Fn( &SymbolType ) -> bool>(&self, f: T ) -> ParseResult<bool> {
74 if let Some(st) = self {
75 Ok(f( &st.symbol() ))
76 } else {
77 Err(ParseError{
78 position: Position::new(0,0),
79 what: "Unexpected end of stream.".to_string()
80 })
81 }
82 }
83
84 fn is_valid_tag_name(&self) -> ParseResult<bool> {
58 if let Some(st) = self { 85 if let Some(st) = self {
59 Ok(f( &self.symbol )) 86 Ok(match st.symbol() {
87 SymbolType::Token(_) |
88 SymbolType::Fragment |
89 SymbolType::Output |
90 SymbolType::Show => true,
91 _ => false
92 })
60 } else { 93 } else {
61 Err(ParseError{ 94 Err(ParseError{
62 position: Position::new(0,0), 95 position: Position::new(0,0),
@@ -166,15 +199,15 @@ impl Parser {
166 } 199 }
167 } 200 }
168 201
169 pub fn parse(&mut self, src: &str ) -> ParseResult<Token> { 202 pub fn parse(&self, src: &str ) -> ParseResult<Token> {
170 let mut ll = Lexer::new( src ); 203 let ll = Lexer::new( src );
171 let mut ctx = Context::new( ll ); 204 let mut ctx = Context::new( ll );
172 205
173 // Parse the root of the file, the input context 206 // Parse the root of the file, the input context
174 self.p_input( &mut ctx ) 207 self.p_input( &mut ctx )
175 } 208 }
176 209
177 fn p_input(&mut self, ctx: &mut Context ) -> ParseResult<Token> { 210 fn p_input(&self, ctx: &mut Context ) -> ParseResult<Token> {
178 let mut children = Vec::new(); 211 let mut children = Vec::new();
179 loop { 212 loop {
180 if ctx.cur().is_none() { 213 if ctx.cur().is_none() {
@@ -183,7 +216,7 @@ impl Parser {
183 match ctx.cur().unwrap().symbol() { 216 match ctx.cur().unwrap().symbol() {
184 SymbolType::Text(_) => { /* Skip top level text */ } 217 SymbolType::Text(_) => { /* Skip top level text */ }
185 SymbolType::StartFlat => { 218 SymbolType::StartFlat => {
186 children.push( self.parse_tag( ctx )? ); 219 children.push( self.parse_tag_fragment( ctx )? );
187 } 220 }
188 SymbolType::Error{..} => { 221 SymbolType::Error{..} => {
189 return self.lex_error( &ctx.cur().unwrap() ); 222 return self.lex_error( &ctx.cur().unwrap() );
@@ -197,12 +230,99 @@ impl Parser {
197 Ok(Token::Root(children)) 230 Ok(Token::Root(children))
198 } 231 }
199 232
200 fn parse_tag(&mut self, ctx: &mut Context) -> ParseResult<TagBuilder> { 233 fn parse_tag_fragment(&self, ctx: &mut Context) -> ParseResult<Token> {
201 let mut tb = TagBuilder::new(); 234 let mut tb = self.parse_open_tag( ctx )?;
235 if !tb.is_name( &SymbolType::Fragment ) {
236 return Err(ParseError{
237 position: tb.start_pos(),
238 what: "Unexpected tag type, only frament allowed at root".to_string(),
239 });
240 }
241
242 if tb.is_unary() {
243 return tb.build();
244 }
245 let mut children = Vec::new();
246
247 println!("--parse-tag-fragment-- tag parsed, next token: {:?}", ctx.cur() );
248 loop {
249 if ctx.cur().is_none() {
250 return Err(ParseError{
251 position: Position::new(0,0),
252 what: "Unexpected end of stream.".to_string()
253 });
254 }
255 match ctx.cur().unwrap().symbol() {
256 SymbolType::Text(s) => {
257 children.push( Token::Text(s.to_string()) );
258 ctx.next();
259 }
260 SymbolType::StartFlat => {
261 //child.is_name(SymbolType::Output)
262 children.push( self.parse_tag_body( ctx )? );
263 }
264 SymbolType::StartPoint => {
265 let end = self.parse_end_tag( ctx )?;
266 println!("End tag: {:?}, open tag: {:?}", end, tb.name() );
267 if tb.is_name(end.symbol()) {
268 // They match, time to decide what we're doing.
269 let any_outputs = children.iter().any(
270 |t| matches!(t, Token::Output(..))
271 );
272 if children.iter().all(|t| matches!(t, Token::Text(..)) || matches!(t, Token::Output(..))) {
273 // Everything is either text or output
274 if !any_outputs {
275 // Special case, if it's only text then we create an implicit output.
276 tb.add_child(Token::Output("content".to_string(), Properties::new(), children ));
277 }
278 else {
279 // Standard case, outputs are included, text is
280 // skipped.
281 for token in children {
282 if matches!(token, Token::Output(..)) {
283 tb.add_child( token );
284 }
285 }
286 }
287 } else {
288 // We have another mix, now check to see if there
289 // are any outptus, if so this is an error.
290 if any_outputs {
291 return Err(ParseError{
292 position: *end.start(),
293 what: "You cannot mix non-output and output tags in a view.".to_string()
294 });
295 } else {
296 // No outputs at all, we create an implict output
297 tb.add_child(Token::Output("content".to_string(), Properties::new(), children ));
298 }
299 }
300
301 return tb.build();
302 } else {
303 // They don't match, complain.
304 return Err(ParseError{
305 position: *end.start(),
306 what: "Mismatched open and closing tags.".to_string()
307 });
308 }
309 }
310 SymbolType::Error{..} => {
311 return self.lex_error( &ctx.cur().unwrap() );
312 }
313 _ => {
314 ctx.next();
315 }
316 }
317 }
318 }
319
320 fn parse_open_tag<'a>(&self, ctx: &mut Context<'a>) -> ParseResult<TagBuilder<'a>> {
202 321
203 println!("--> Begin parse_tag <--"); 322 println!("--> Begin parse_tag <--");
204 323
205 let start_sym = ctx.cur().unwrap(); 324 let start_sym = ctx.cur().unwrap();
325 let mut tb = TagBuilder::new(&start_sym);
206 326
207 println!("--> Start sym: {:?}", start_sym ); 327 println!("--> Start sym: {:?}", start_sym );
208 328
@@ -239,19 +359,40 @@ impl Parser {
239 } 359 }
240 } 360 }
241 361
362 ctx.next();
363
242 Ok(tb) 364 Ok(tb)
243 } 365 }
244 366
245 fn parse_end_tag(&mut self, ctx: &mut Context ) -> &'a str { 367 fn parse_end_tag<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult<Symbol<'a>> {
246 if !ctx.cur().is(|s| matches!(s, Symbol::StartPoint))? { 368 if !ctx.cur().is(|s| *s == SymbolType::StartPoint )? {
369 return Err(ParseError{
370 position: *ctx.cur().unwrap().start(),
371 what: "Invalid end tag?".to_string(),
372 });
373 }
374 if !ctx.next().is_valid_tag_name()? {
375 return Err(ParseError{
376 position: *ctx.cur().unwrap().start(),
377 what: "Invalid tag name".to_string(),
378 });
379 }
380 let name = ctx.cur().unwrap();
381 if !ctx.next().is(|s| *s == SymbolType::EndFlat )? {
247 return Err(ParseError{ 382 return Err(ParseError{
248 position: ctx.cur(). 383 position: *ctx.cur().unwrap().start(),
384 what: "Tag should be <| |] style end tag.".to_string(),
249 }); 385 });
250 } 386 }
251 ctx.next() 387 Ok(name)
252 } 388 }
253 389
254 fn parse_tag_body(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { 390 fn parse_tag_body(&self, ctx: &mut Context ) -> ParseResult<Token> {
391 let mut tb = self.parse_open_tag( ctx )?;
392 if tb.is_unary() {
393 return tb.build();
394 }
395
255 loop { 396 loop {
256 if ctx.cur().is_none() { 397 if ctx.cur().is_none() {
257 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); 398 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()});
@@ -259,28 +400,37 @@ impl Parser {
259 match ctx.cur().unwrap().symbol() { 400 match ctx.cur().unwrap().symbol() {
260 SymbolType::Text(s) => { 401 SymbolType::Text(s) => {
261 tb.add_child(Token:: Text(s.to_string())); 402 tb.add_child(Token:: Text(s.to_string()));
403 ctx.next();
262 } 404 }
263 SymbolType::StartFlat => { 405 SymbolType::StartFlat => {
264 tb.add_child( self.parse_tag( ctx )? ); 406 tb.add_child( self.parse_tag_body( ctx )? );
407 println!("Following tag body: {:?} {:?}", ctx.cur(), ctx.peek() );
265 } 408 }
266 SymbolType::StartPoint => { 409 SymbolType::StartPoint => {
267 let end_tag = self.parse_end_tag( ctx )?; 410 let end = self.parse_end_tag( ctx )?;
268 411 println!("End tag: {:?}, open tag: {:?}", end, tb.name() );
412 if tb.is_name(end.symbol()) {
413 // They match, end.
414 return tb.build();
415 } else {
416 // They don't match, complain.
417 return Err(ParseError{
418 position: *end.start(),
419 what: "Mismatched open and closing tags.".to_string()
420 });
421 }
269 } 422 }
270 SymbolType::Error{..} => { 423 SymbolType::Error{..} => {
271 return self.lex_error( &ctx.cur().unwrap() ); 424 self.lex_error( &ctx.cur().unwrap() )?;
272 } 425 }
273 _ => { 426 _ => {
274 427
275 } 428 }
276 } 429 }
277 ctx.next();
278 } 430 }
279 Ok(Token::Root(children))
280 Ok(())
281 } 431 }
282 432
283 fn parse_tag_params(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { 433 fn parse_tag_params(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> {
284 loop { 434 loop {
285 if ctx.cur().is_none() { 435 if ctx.cur().is_none() {
286 436
@@ -299,7 +449,7 @@ impl Parser {
299 Ok(()) 449 Ok(())
300 } 450 }
301 451
302 fn parse_tag_props(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> { 452 fn parse_tag_props(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> ParseResult<()> {
303 loop { 453 loop {
304 if ctx.cur().is_none() { 454 if ctx.cur().is_none() {
305 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()}); 455 return Err(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()});
@@ -325,7 +475,7 @@ impl Parser {
325 } 475 }
326} 476}
327 477
328#[derive(PartialEq)] 478#[derive(PartialEq,Copy,Clone,Debug)]
329enum TagType { 479enum TagType {
330 Unknown, 480 Unknown,
331 Unary, 481 Unary,
@@ -339,20 +489,34 @@ struct TagBuilder<'a> {
339 props: Properties, 489 props: Properties,
340 children: Vec<Token>, 490 children: Vec<Token>,
341 tag_type: TagType, 491 tag_type: TagType,
492 start_pos: Position,
342} 493}
343 494
344impl<'a> TagBuilder<'a> { 495impl<'a> TagBuilder<'a> {
345 pub fn new() -> TagBuilder<'a> { 496 pub fn new(start: &Symbol) -> TagBuilder<'a> {
346 TagBuilder { 497 TagBuilder {
347 name: None, 498 name: None,
348 params: Vec::new(), 499 params: Vec::new(),
349 props: Properties::new(), 500 props: Properties::new(),
350 children: Vec::new(), 501 children: Vec::new(),
351 tag_type: TagType::Unknown, 502 tag_type: TagType::Unknown,
503 start_pos: *start.start(),
352 } 504 }
353 } 505 }
354 506
355 pub fn has_children(&self) -> bool { 507 pub fn start_pos(&self) -> Position {
508 self.start_pos
509 }
510
511 pub fn is_unary(&self) -> bool {
512 if self.tag_type == TagType::Unary {
513 true
514 } else {
515 false
516 }
517 }
518
519 pub fn can_have_children(&self) -> bool {
356 if self.tag_type == TagType::BinaryOpen { 520 if self.tag_type == TagType::BinaryOpen {
357 true 521 true
358 } else { 522 } else {
@@ -360,14 +524,18 @@ impl<'a> TagBuilder<'a> {
360 } 524 }
361 } 525 }
362 526
363 pub fn is_same_name(&self, name: Symbol<'a>) -> bool { 527 pub fn is_name(&self, name: &SymbolType<'a>) -> bool {
364 if let Some(a) = self.name { 528 if let Some(a) = self.name {
365 a.symbol() == name.symbol() 529 a.symbol() == name
366 } else { 530 } else {
367 false 531 false
368 } 532 }
369 } 533 }
370 534
535 pub fn name(&self) -> Option<Symbol> {
536 self.name
537 }
538
371 pub fn set_name(&mut self, name: Symbol<'a>) { 539 pub fn set_name(&mut self, name: Symbol<'a>) {
372 self.name = Some(name); 540 self.name = Some(name);
373 println!("Tag name: {:?}", self.name ); 541 println!("Tag name: {:?}", self.name );
@@ -387,10 +555,18 @@ impl<'a> TagBuilder<'a> {
387 self.children.push( token ); 555 self.children.push( token );
388 } 556 }
389 557
558 pub fn append_children(&mut self, children: &mut Vec::<Token>) {
559 self.children.append( children );
560 }
561
390 pub fn set_type(&mut self, tag_type: TagType) { 562 pub fn set_type(&mut self, tag_type: TagType) {
391 self.tag_type = tag_type; 563 self.tag_type = tag_type;
392 } 564 }
393 565
566 pub fn tag_type(&self) -> TagType {
567 self.tag_type
568 }
569
394 pub fn build(mut self) -> ParseResult<Token> { 570 pub fn build(mut self) -> ParseResult<Token> {
395 if let Some(sym) = self.name { 571 if let Some(sym) = self.name {
396 match sym.symbol() { 572 match sym.symbol() {
@@ -406,14 +582,14 @@ impl<'a> TagBuilder<'a> {
406 _ => { 582 _ => {
407 println!("Unkown tag type"); 583 println!("Unkown tag type");
408 Err(ParseError { 584 Err(ParseError {
409 position: Position::new(0,0), 585 position: self.start_pos,
410 what: "Bad tag type".to_string(), 586 what: "Bad tag type".to_string(),
411 }) 587 })
412 } 588 }
413 } 589 }
414 } else { 590 } else {
415 Err(ParseError { 591 Err(ParseError {
416 position: Position::new(0,0), 592 position: self.start_pos,
417 what: "Bad tag type".to_string(), 593 what: "Bad tag type".to_string(),
418 }) 594 })
419 } 595 }