From 83ab8c67beecfc05684c9400e29f7d77225d3af9 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Sun, 7 Jun 2026 16:37:28 -0700 Subject: Cleaned up a lot of parsing code. --- src/lexer.rs | 13 ++++-- src/lib.rs | 24 +++++++--- src/parser.rs | 142 +++++++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 137 insertions(+), 42 deletions(-) diff --git a/src/lexer.rs b/src/lexer.rs index 04be350..902bb64 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -1,15 +1,16 @@ use std::iter::Iterator; //use core::error::Error; use std::str::CharIndices; +use std::fmt; use crate::Position; -#[derive(Debug,Copy,Clone)] +#[derive(Debug,Copy,Clone,PartialEq)] pub enum ErrorType { UnexpectedChar(char), } -#[derive(Debug,Copy,Clone)] +#[derive(Debug,Copy,Clone,PartialEq)] pub enum SymbolType<'a> { StartFlat, StartPoint, @@ -26,13 +27,19 @@ pub enum SymbolType<'a> { EOS, } -#[derive(Debug,Copy,Clone)] +#[derive(Copy,Clone)] pub struct Symbol<'a> { symbol: SymbolType<'a>, start: Position, end: Position, } +impl<'a> fmt::Debug for Symbol<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?} @ {}:{}", self.symbol, self.start.line, self.start.column ) + } +} + impl<'a> Symbol<'a> { pub fn new( symbol: SymbolType<'a>, start: Position, end: Position ) -> Self { Self { diff --git a/src/lib.rs b/src/lib.rs index 7d0e7f2..5e912cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,6 @@ use std::path::{PathBuf,Path}; use std::collections::HashMap; use core::error::Error; use std::time::SystemTime; -use std::fs::File; -use std::io::Read; mod lexer; mod parser; @@ -57,6 +55,14 @@ enum Token { Fragment(String,Properties,Vec), Section(String,Properties,Vec), Text(String), + Literal(String), + /* + Tag{ + name: String, + params: Vec, + props: Properties, + children: Vec + },*/ } struct State { @@ -97,14 +103,14 @@ impl Crimtag { }; let mut p = parser::Parser::new(); - p.parse( self, &String::from_utf8( std::fs::read( path )? )? ); + p.parse( &String::from_utf8( std::fs::read( path )? )? ); Ok(()) } pub fn load_static(&mut self, data: &str) -> Result<(),Box::> { let mut p = parser::Parser::new(); - p.parse( self, &data ); + p.parse( &data ); Ok(()) } @@ -137,8 +143,12 @@ mod tests { #[test] fn parsing() { let mut ct = Crimtag::new(); - ct.load_static(r#"Here is a sample -[|frament "index" theme="standard"|>Hi<|fragment|] -That was fun!"#); + if let Err(e) = ct.load_static(r#"Here is a sample +[|fragment "index" theme="standard"|>Hi<|fragment|] +That was fun!"#) { + println!("Error: {:?}", e ); + } else { + println!("It finished"); + } } } diff --git a/src/parser.rs b/src/parser.rs index e5ea1f5..2d845cd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -27,6 +27,7 @@ struct Context<'a> { impl<'a> Context<'a> { pub fn new( mut ll: Lexer<'a> ) -> Self { let cur = [ll.next(), ll.next()]; + //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] ); Self { cur, icur: 0, @@ -37,7 +38,7 @@ impl<'a> Context<'a> { pub fn next(&mut self) -> Option> { self.cur[self.icur] = self.ll.next(); self.icur = (self.icur+1)%2; - println!(" - cur: {:?}, peek: {:?}", self.cur(), self.peek() ); + //println!(" - cur: {:?}, peek: {:?}", self.cur(), self.peek() ); self.cur[self.icur] } @@ -136,7 +137,7 @@ impl Parser { } } - fn lex_error(&self, error: &Symbol) -> Result<(),Box> { + fn lex_error(&self, error: &Symbol) -> Result> { if let SymbolType::Error{what} = error.symbol() { Err(Box::new(ParseError { position: error.start().clone(), @@ -150,17 +151,16 @@ impl Parser { } } - pub fn parse(&mut self, crim: &mut Crimtag, src: &str ) -> Result<(),Box> { + pub fn parse(&mut self, src: &str ) -> Result> { let mut ll = Lexer::new( src ); let mut ctx = Context::new( ll ); // Parse the root of the file, the input context - self.p_input( &mut ctx )?; - - Ok(()) + self.p_input( &mut ctx ) } - fn p_input(&mut self, ctx: &mut Context ) -> Result<(), Box> { + fn p_input(&mut self, ctx: &mut Context ) -> Result> { + let mut children = Vec::new(); loop { if ctx.cur().is_none() { break; @@ -168,7 +168,7 @@ impl Parser { match ctx.cur().unwrap().symbol() { SymbolType::Text(_) => { /* Skip top level text */ } SymbolType::StartFlat => { - self.parse_tag( ctx ); + children.push( self.parse_tag( ctx )? ); } SymbolType::Error{..} => { return self.lex_error( &ctx.cur().unwrap() ); @@ -179,28 +179,57 @@ impl Parser { } ctx.next(); } - Ok(()) + Ok(Token::Root(children)) } - fn parse_tag(&mut self, ctx: &mut Context) -> Result<(), Box> { + fn parse_tag(&mut self, ctx: &mut Context) -> Result> { let mut tb = TagBuilder::new(); + + println!("--> Begin parse_tag <--"); let start_sym = ctx.cur().unwrap(); + println!("--> Start sym: {:?}", start_sym ); + if ctx.next().is_some() { - if let SymbolType::Token(s) = ctx.next().unwrap().symbol() { - tb.set_name( s.to_string() ); - } else { - return Err(Box::new(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpecetd symbol".to_string()})); + match ctx.cur().unwrap().symbol() { + SymbolType::Fragment | SymbolType::Section | + SymbolType::Output => { + let name_sym = ctx.cur().unwrap(); + ctx.next(); + tb.set_name( name_sym ); + } + _ => { + return Err(Box::new(ParseError{position: ctx.cur().unwrap().start().clone(), what: "Unexpecetd symbol".to_string()})); + } } } else { return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()})); } + println!("--> Begin parse_tag_params <--"); self.parse_tag_params( ctx, &mut tb )?; + println!("--> End parse_tag_params <--"); + println!("--> Begin parse_tag_props <--"); self.parse_tag_props( ctx, &mut tb )?; + println!("--> End parse_tag_props <--"); - Ok(()) + println!("---> {:?}", ctx.cur() ); + if let Some(end_sym) = ctx.cur() { + match end_sym.symbol() { + SymbolType::EndPoint => { + tb.set_type( TagType::BinaryOpen ); + } + SymbolType::EndFlat => { + tb.set_type( TagType::Unary ); + } + _ => { + return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()})); + } + } + } + + tb.build() } fn parse_tag_params(&mut self, ctx: &mut Context, tb: &mut TagBuilder ) -> Result<(), Box> { @@ -209,15 +238,13 @@ impl Parser { return Err(Box::new(ParseError{position: Position::new(0,0), what: "Unexpecetd end of stream".to_string()})); } - if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { - if let Some(p) = ctx.peek() { - if p.check_type(|t| matches!(t, SymbolType::Equals)) { - break; - } - } - else { + match ctx.cur().unwrap().symbol() { + SymbolType::Literal(s) => { tb.add_param( s.to_string() ); } + _ => { + break; + } } ctx.next(); } @@ -250,6 +277,7 @@ impl Parser { } } +#[derive(PartialEq)] enum TagType { Unknown, Unary, @@ -257,36 +285,86 @@ enum TagType { BinaryClose, } -struct TagBuilder { - name: String, +struct TagBuilder<'a> { + name: Option>, params: Vec, - props: Vec<(String,String)>, + props: Properties, + children: Vec, tag_type: TagType, } -impl TagBuilder { - pub fn new() -> TagBuilder { +impl<'a> TagBuilder<'a> { + pub fn new() -> TagBuilder<'a> { TagBuilder { - name: String::new(), + name: None, params: Vec::new(), - props: Vec::new(), + props: Properties::new(), + children: Vec::new(), tag_type: TagType::Unknown, } } - pub fn set_name(&mut self, name: String) { - self.name = name; + pub fn has_children(&self) -> bool { + if self.tag_type == TagType::BinaryOpen { + true + } else { + false + } + } + + pub fn is_same_name(&self, name: Symbol<'a>) -> bool { + if let Some(a) = self.name { + a.symbol() == name.symbol() + } else { + false + } + } + + pub fn set_name(&mut self, name: Symbol<'a>) { + self.name = Some(name); + println!("Tag name: {:?}", self.name ); } pub fn add_param(&mut self, param: String) { + println!("Add param: {:?}", param ); self.params.push( param ); } pub fn add_prop(&mut self, key: String, value: String) { - self.props.push( (key, value) ); + println!("Add prop: {:?} = {:?}", key, value ); + self.props.insert( key, value ); + } + + pub fn add_child(&mut self, token: Token) { + self.children.push( token ); } pub fn set_type(&mut self, tag_type: TagType) { self.tag_type = tag_type; } + + pub fn build(mut self) -> Result> { + if let Some(sym) = self.name { + match sym.symbol() { + SymbolType::Fragment => { + Ok(Token::Fragment(self.params.swap_remove(0), self.props, self.children)) + } + SymbolType::Output => { + Ok(Token::Section(self.params.swap_remove(0), self.props, self.children)) + } + _ => { + println!("Unkown tag type"); + Err(Box::new(ParseError { + position: Position::new(0,0), + what: "Bad tag type".to_string(), + })) + } + } + } else { + Err(Box::new(ParseError { + position: Position::new(0,0), + what: "Bad tag type".to_string(), + })) + } + } } -- cgit v1.2.3