summaryrefslogtreecommitdiff
path: root/src/parser.rs
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2026-06-09 10:16:19 -0700
committerMike Buland <mike@xagasoft.com>2026-06-09 10:16:19 -0700
commitf724cea337965419618d7d587015c9593a67834d (patch)
tree4dfde406f727f27f0ec77738506e5061ff648d07 /src/parser.rs
parent9c5da7c258a49d911b20629be6b4ef426d4f431e (diff)
downloadcrimtag-f724cea337965419618d7d587015c9593a67834d.tar.gz
crimtag-f724cea337965419618d7d587015c9593a67834d.tar.bz2
crimtag-f724cea337965419618d7d587015c9593a67834d.tar.xz
crimtag-f724cea337965419618d7d587015c9593a67834d.zip
Removed root, view, and output AST tokens.
They are built as their final objects during parsing now. It's no more complex and we have no useless tokens now.
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs122
1 files changed, 73 insertions, 49 deletions
diff --git a/src/parser.rs b/src/parser.rs
index c7a8abe..297230c 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -40,16 +40,18 @@ struct Context<'a> {
40 cur: [Option<Symbol<'a>>;2], 40 cur: [Option<Symbol<'a>>;2],
41 icur: usize, 41 icur: usize,
42 ll: Lexer<'a>, 42 ll: Lexer<'a>,
43 source: usize,
43} 44}
44 45
45impl<'a> Context<'a> { 46impl<'a> Context<'a> {
46 pub fn new( mut ll: Lexer<'a> ) -> Self { 47 pub fn new( mut ll: Lexer<'a>, source: usize ) -> Self {
47 let cur = [ll.next(), ll.next()]; 48 let cur = [ll.next(), ll.next()];
48 //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] ); 49 //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] );
49 Self { 50 Self {
50 cur, 51 cur,
51 icur: 0, 52 icur: 0,
52 ll 53 ll,
54 source,
53 } 55 }
54 } 56 }
55 57
@@ -75,6 +77,10 @@ impl<'a> Context<'a> {
75 Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) 77 Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol()))
76 } 78 }
77 } 79 }
80
81 pub fn source(&self) -> usize {
82 self.source
83 }
78} 84}
79 85
80trait SymbolHelper { 86trait SymbolHelper {
@@ -195,7 +201,7 @@ impl Parser {
195 } 201 }
196 } 202 }
197 203
198 fn lex_error(&self, error: &Symbol) -> ParseResult<Token> { 204 fn lex_error<T>(&self, error: &Symbol) -> ParseResult<T> {
199 if let SymbolType::Error{what} = error.symbol() { 205 if let SymbolType::Error{what} = error.symbol() {
200 Err(ParseError { 206 Err(ParseError {
201 position: error.start().clone(), 207 position: error.start().clone(),
@@ -209,15 +215,15 @@ impl Parser {
209 } 215 }
210 } 216 }
211 217
212 pub fn parse(&self, src: &str ) -> ParseResult<Token> { 218 pub fn parse(&self, src: &str, source: usize ) -> ParseResult<Vec<View>> {
213 let ll = Lexer::new( src ); 219 let ll = Lexer::new( src );
214 let mut ctx = Context::new( ll ); 220 let mut ctx = Context::new( ll, source );
215 221
216 // Parse the root of the file, the input context 222 // Parse the root of the file, the input context
217 self.p_input( &mut ctx ) 223 self.p_input( &mut ctx )
218 } 224 }
219 225
220 fn p_input(&self, ctx: &mut Context ) -> ParseResult<Token> { 226 fn p_input(&self, ctx: &mut Context ) -> ParseResult<Vec<View>> {
221 let mut children = Vec::new(); 227 let mut children = Vec::new();
222 loop { 228 loop {
223 if ctx.cur().is_none() { 229 if ctx.cur().is_none() {
@@ -229,7 +235,7 @@ impl Parser {
229 children.push( self.parse_tag_view( ctx )? ); 235 children.push( self.parse_tag_view( ctx )? );
230 } 236 }
231 SymbolType::Error{..} => { 237 SymbolType::Error{..} => {
232 return self.lex_error( &ctx.cur().unwrap() ); 238 self.lex_error( &ctx.cur().unwrap() )?;
233 } 239 }
234 _ => { 240 _ => {
235 241
@@ -237,11 +243,11 @@ impl Parser {
237 } 243 }
238 ctx.next(); 244 ctx.next();
239 } 245 }
240 Ok(Token::Root(children)) 246 Ok(children)
241 } 247 }
242 248
243 fn parse_tag_view(&self, ctx: &mut Context) -> ParseResult<Token> { 249 fn parse_tag_view(&self, ctx: &mut Context) -> ParseResult<View> {
244 let mut tb = self.parse_open_tag( ctx )?; 250 let tb = self.parse_open_tag( ctx )?;
245 if !tb.is_name( &SymbolType::View ) { 251 if !tb.is_name( &SymbolType::View ) {
246 return Err(ParseError{ 252 return Err(ParseError{
247 position: tb.start_pos(), 253 position: tb.start_pos(),
@@ -250,9 +256,10 @@ impl Parser {
250 } 256 }
251 257
252 if tb.is_unary() { 258 if tb.is_unary() {
253 return tb.build(); 259 return tb.build_view(ctx, Vec::new());
254 } 260 }
255 let mut children = Vec::new(); 261 let mut children = Vec::new();
262 let mut outputs = Vec::new();
256 263
257 //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() ); 264 //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() );
258 loop { 265 loop {
@@ -265,47 +272,37 @@ impl Parser {
265 ctx.next(); 272 ctx.next();
266 } 273 }
267 SymbolType::StartFlat => { 274 SymbolType::StartFlat => {
268 //child.is_name(SymbolType::Output) 275 let subtb = self.parse_tag_body( ctx )?;
269 children.push( self.parse_tag_body( ctx )? ); 276 if subtb.is_name(&SymbolType::Output) {
277 outputs.push(subtb.build_output(ctx)?);
278 } else {
279 children.push(subtb.build()?);
280 }
270 } 281 }
271 SymbolType::StartPoint => { 282 SymbolType::StartPoint => {
272 let end = self.parse_end_tag( ctx )?; 283 let end = self.parse_end_tag( ctx )?;
273 //println!("End tag: {:?}, open tag: {:?}", end, tb.name() ); 284 //println!("End tag: {:?}, open tag: {:?}", end, tb.name() );
274 if tb.is_name(end.symbol()) { 285 if tb.is_name(end.symbol()) {
275 // They match, time to decide what we're doing. 286 // They match, time to decide what we're doing.
276 let any_outputs = children.iter().any( 287 let any_outputs = outputs.len() > 0;
277 |t| matches!(t, Token::Output(..)) 288 let all_text = children.iter().all(
289 |t| matches!(t, Token::Text(..))
278 ); 290 );
279 if children.iter().all(|t| matches!(t, Token::Text(..)) || matches!(t, Token::Output(..))) { 291 if !any_outputs {
280 // Everything is either text or output 292 // Create an implicit output called "content"
281 if !any_outputs { 293 outputs.push(Output{
282 // Special case, if it's only text then we create an implicit output. 294 name: "content".to_string(),
283 tb.add_child(Token::Output("content".to_string(), /*Properties::new(),*/ children )); 295 code: children,
284 } 296 });
285 else {
286 // Standard case, outputs are included, text is
287 // skipped.
288 for token in children {
289 if matches!(token, Token::Output(..)) {
290 tb.add_child( token );
291 }
292 }
293 }
294 } else { 297 } else {
295 // We have another mix, now check to see if there 298 if !all_text {
296 // are any outptus, if so this is an error.
297 if any_outputs {
298 return Err(ParseError{ 299 return Err(ParseError{
299 position: *end.start(), 300 position: *end.start(),
300 what: "You cannot mix non-output and output tags in a view.".to_string() 301 what: "You cannot mix non-output and output tags in a view.".to_string()
301 }); 302 });
302 } else {
303 // No outputs at all, we create an implict output
304 tb.add_child(Token::Output("content".to_string(), /*Properties::new(), */children ));
305 } 303 }
306 } 304 }
307 305 return tb.build_view(ctx,outputs);
308 return tb.build();
309 } else { 306 } else {
310 // They don't match, complain. 307 // They don't match, complain.
311 return Err(ParseError{ 308 return Err(ParseError{
@@ -392,10 +389,10 @@ impl Parser {
392 Ok(name) 389 Ok(name)
393 } 390 }
394 391
395 fn parse_tag_body(&self, ctx: &mut Context ) -> ParseResult<Token> { 392 fn parse_tag_body<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult<TagBuilder<'a>> {
396 let mut tb = self.parse_open_tag( ctx )?; 393 let mut tb = self.parse_open_tag( ctx )?;
397 if tb.is_unary() { 394 if tb.is_unary() {
398 return tb.build(); 395 return Ok(tb);
399 } 396 }
400 397
401 loop { 398 loop {
@@ -408,13 +405,13 @@ impl Parser {
408 ctx.next(); 405 ctx.next();
409 } 406 }
410 SymbolType::StartFlat => { 407 SymbolType::StartFlat => {
411 tb.add_child( self.parse_tag_body( ctx )? ); 408 tb.add_child( self.parse_tag_body( ctx )?.build()? );
412 } 409 }
413 SymbolType::StartPoint => { 410 SymbolType::StartPoint => {
414 let end = self.parse_end_tag( ctx )?; 411 let end = self.parse_end_tag( ctx )?;
415 if tb.is_name(end.symbol()) { 412 if tb.is_name(end.symbol()) {
416 // They match, end. 413 // They match, end.
417 return tb.build(); 414 return Ok(tb);
418 } else { 415 } else {
419 // They don't match, complain. 416 // They don't match, complain.
420 return Err(ParseError{ 417 return Err(ParseError{
@@ -424,7 +421,7 @@ impl Parser {
424 } 421 }
425 } 422 }
426 SymbolType::Error{..} => { 423 SymbolType::Error{..} => {
427 self.lex_error( &ctx.cur().unwrap() )?; 424 return self.lex_error( &ctx.cur().unwrap() );
428 } 425 }
429 _ => { 426 _ => {
430 427
@@ -565,15 +562,42 @@ impl<'a> TagBuilder<'a> {
565 self.tag_type 562 self.tag_type
566 } 563 }
567 564
565 pub fn build_view(mut self, ctx: &Context, outputs: Vec<Output>) -> ParseResult<View> {
566 if let Some(sym) = self.name {
567 if *sym.symbol() == SymbolType::View {
568 Ok(View {
569 name: self.params.swap_remove(0),
570 source: ctx.source(),
571 outputs: outputs,
572 //theme: Option<String>
573 layout: self.props.get("layout").cloned(),
574 })
575 } else {
576 Err(ParseError::new(self.start_pos, &format!("Expected tag type view, found {:?}", sym.symbol())))
577 }
578 } else {
579 Err(ParseError::new(self.start_pos, "Broken Parser? No tag type found when building view."))
580 }
581 }
582
583 pub fn build_output(mut self, ctx: &Context) -> ParseResult<Output> {
584 if let Some(sym) = self.name {
585 if *sym.symbol() == SymbolType::Output {
586 Ok(Output {
587 name: self.params.swap_remove(0),
588 code: self.children,
589 })
590 } else {
591 Err(ParseError::new(self.start_pos, &format!("Expected tag type view, found {:?}", sym.symbol())))
592 }
593 } else {
594 Err(ParseError::new(self.start_pos, "Broken Parser? No tag type found when building view."))
595 }
596 }
597
568 pub fn build(mut self) -> ParseResult<Token> { 598 pub fn build(mut self) -> ParseResult<Token> {
569 if let Some(sym) = self.name { 599 if let Some(sym) = self.name {
570 match sym.symbol() { 600 match sym.symbol() {
571 SymbolType::View => {
572 Ok(Token::View(self.params.swap_remove(0), self.props, self.children))
573 }
574 SymbolType::Output => {
575 Ok(Token::Output(self.params.swap_remove(0), /*self.props,*/ self.children))
576 }
577 SymbolType::Show => { 601 SymbolType::Show => {
578 Ok(Token::Show(self.params.swap_remove(0), self.props)) 602 Ok(Token::Show(self.params.swap_remove(0), self.props))
579 } 603 }