From f724cea337965419618d7d587015c9593a67834d Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 9 Jun 2026 10:16:19 -0700 Subject: 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. --- src/lexer.rs | 4 +- src/lib.rs | 98 ++++++++++++++-------------------------------- src/parser.rs | 122 +++++++++++++++++++++++++++++++++++----------------------- 3 files changed, 103 insertions(+), 121 deletions(-) diff --git a/src/lexer.rs b/src/lexer.rs index c7249b7..0724df2 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -5,12 +5,12 @@ use std::fmt; use crate::Position; -#[derive(Debug,Copy,Clone,PartialEq)] +#[derive(Debug,Copy,Clone,PartialEq,Eq)] pub enum ErrorType { UnexpectedChar(char), } -#[derive(Debug,Copy,Clone,PartialEq)] +#[derive(Debug,Copy,Clone,PartialEq,Eq)] pub enum SymbolType<'a> { StartFlat, StartPoint, diff --git a/src/lib.rs b/src/lib.rs index 4ebb643..7790b9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ pub enum ViewSource { #[derive(Debug)] struct View { + name: String, source: usize, outputs: Vec, // theme: Option @@ -40,11 +41,9 @@ impl View { fn process(&self, input: &Value) -> Result { let mut out_vars = HashMap::new(); for output in &self.outputs { - if let Token::Output(_,/*_,*/tokens) = &output.ast_root { - let mut buf = String::new(); - exec( input, tokens, &mut buf )?; - out_vars.insert( output.name.clone(), Value::String(buf) ); - } + let mut buf = String::new(); + exec( input, &output.code, &mut buf )?; + out_vars.insert( output.name.clone(), Value::String(buf) ); } Ok(Value::Dictionary(out_vars)) } @@ -53,16 +52,13 @@ impl View { #[derive(Debug)] struct Output { name: String, - ast_root: Token, + code: Vec, } type Properties = HashMap; #[derive(Debug)] enum Token { - Root(Vec), - View(String,Properties,Vec), - Output(String,/*Properties,*/ Vec), Show(String,Properties), Text(String), } @@ -109,78 +105,44 @@ impl Crimtag { } else { SystemTime::now() }; - + let source_id = self.id_source( + &ViewSource::File { + path: path.to_path_buf(), + loaded: time, + } + ); let p = parser::Parser::new(); self.register_views( - p.parse( &String::from_utf8( std::fs::read( path )? )? )?, - ViewSource::File { - path: path.to_path_buf(), - loaded: time, - })?; + p.parse( + &String::from_utf8( std::fs::read( path )? )?, + source_id + )?, + )?; Ok(()) } pub fn load_static(&mut self, data: &str) -> Result<(),ParseError> { + let source_id = self.id_source( &ViewSource::Static ); let p = parser::Parser::new(); - self.register_views( p.parse( &data )?, ViewSource::Static ) + self.register_views( p.parse( &data, source_id )? ) } pub fn load_external(&mut self, key: &str, data: &str) -> Result<(),ParseError> { - let p = parser::Parser::new(); + let source_id = self.id_source( + &ViewSource::External{ key: key.to_string()} + ); + + let p = parser::Parser::new(); self.register_views( - p.parse( &data )?, - ViewSource::External{ key: key.to_string()} + p.parse( &data, source_id )?, ) } - fn register_views(&mut self, token: Token, source: ViewSource) -> Result<(),ParseError> { - let source_id = self.id_source( &source ); - if let Token::Root(views) = token { - for token in views { - if let Token::View(name,props,output_tokens) = token { - let mut outputs = Vec::new(); - for ot in output_tokens { - let output_name = if let Token::Output(on,..) = &ot { - on.clone() - } else { - return Err(ParseError::new( - Position::new(0,0), - "Broken parser? Item in view is not an output." - )); - }; - outputs.push( - Output { - name: output_name, - ast_root: ot, - } - ); - } - - let layout = if let Some(l) = props.get("layout") { - Some(l.clone()) - } else { - None - }; - - self.views.insert( name, View { - source: source_id, - outputs: outputs, - layout: layout, - }); - } else { - return Err(ParseError::new( - Position::new(0,0), - "Broken parser? Item in root is not a view." - )); - } - } - Ok(()) - } else { - Err(ParseError::new( - Position::new(0,0), - "Broken parser? Root is not a root token." - )) + fn register_views(&mut self, views: Vec) -> Result<(),ParseError> { + for view in views { + self.views.insert( view.name.clone(), view ); } + Ok(()) } pub fn get_view_source(&self, view: &str) -> Option { @@ -228,10 +190,6 @@ impl Crimtag { fn exec(input: &Value, tokens: &Vec, buf: &mut String) -> Result<(),ParseError> { for token in tokens { match token { - Token::Root(..) | Token::View(..) | Token::Output(..) => { - println!("Too high!?"); - // Error? - } Token::Show(s,p) => { let format = if let Some(s) = p.get("format") { s 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> { cur: [Option>;2], icur: usize, ll: Lexer<'a>, + source: usize, } impl<'a> Context<'a> { - pub fn new( mut ll: Lexer<'a> ) -> Self { + pub fn new( mut ll: Lexer<'a>, source: usize ) -> Self { let cur = [ll.next(), ll.next()]; //println!(" - cur: {:?}, peek: {:?}", cur[0], cur[1] ); Self { cur, icur: 0, - ll + ll, + source, } } @@ -75,6 +77,10 @@ impl<'a> Context<'a> { Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) } } + + pub fn source(&self) -> usize { + self.source + } } trait SymbolHelper { @@ -195,7 +201,7 @@ impl Parser { } } - fn lex_error(&self, error: &Symbol) -> ParseResult { + fn lex_error(&self, error: &Symbol) -> ParseResult { if let SymbolType::Error{what} = error.symbol() { Err(ParseError { position: error.start().clone(), @@ -209,15 +215,15 @@ impl Parser { } } - pub fn parse(&self, src: &str ) -> ParseResult { + pub fn parse(&self, src: &str, source: usize ) -> ParseResult> { let ll = Lexer::new( src ); - let mut ctx = Context::new( ll ); + let mut ctx = Context::new( ll, source ); // Parse the root of the file, the input context self.p_input( &mut ctx ) } - fn p_input(&self, ctx: &mut Context ) -> ParseResult { + fn p_input(&self, ctx: &mut Context ) -> ParseResult> { let mut children = Vec::new(); loop { if ctx.cur().is_none() { @@ -229,7 +235,7 @@ impl Parser { children.push( self.parse_tag_view( ctx )? ); } SymbolType::Error{..} => { - return self.lex_error( &ctx.cur().unwrap() ); + self.lex_error( &ctx.cur().unwrap() )?; } _ => { @@ -237,11 +243,11 @@ impl Parser { } ctx.next(); } - Ok(Token::Root(children)) + Ok(children) } - fn parse_tag_view(&self, ctx: &mut Context) -> ParseResult { - let mut tb = self.parse_open_tag( ctx )?; + fn parse_tag_view(&self, ctx: &mut Context) -> ParseResult { + let tb = self.parse_open_tag( ctx )?; if !tb.is_name( &SymbolType::View ) { return Err(ParseError{ position: tb.start_pos(), @@ -250,9 +256,10 @@ impl Parser { } if tb.is_unary() { - return tb.build(); + return tb.build_view(ctx, Vec::new()); } let mut children = Vec::new(); + let mut outputs = Vec::new(); //println!("--parse-tag-view-- tag parsed, next token: {:?}", ctx.cur() ); loop { @@ -265,47 +272,37 @@ impl Parser { ctx.next(); } SymbolType::StartFlat => { - //child.is_name(SymbolType::Output) - children.push( self.parse_tag_body( ctx )? ); + let subtb = self.parse_tag_body( ctx )?; + if subtb.is_name(&SymbolType::Output) { + outputs.push(subtb.build_output(ctx)?); + } else { + children.push(subtb.build()?); + } } SymbolType::StartPoint => { let end = self.parse_end_tag( ctx )?; //println!("End tag: {:?}, open tag: {:?}", end, tb.name() ); if tb.is_name(end.symbol()) { // They match, time to decide what we're doing. - let any_outputs = children.iter().any( - |t| matches!(t, Token::Output(..)) + let any_outputs = outputs.len() > 0; + let all_text = children.iter().all( + |t| matches!(t, Token::Text(..)) ); - if children.iter().all(|t| matches!(t, Token::Text(..)) || matches!(t, Token::Output(..))) { - // Everything is either text or output - if !any_outputs { - // Special case, if it's only text then we create an implicit output. - tb.add_child(Token::Output("content".to_string(), /*Properties::new(),*/ children )); - } - else { - // Standard case, outputs are included, text is - // skipped. - for token in children { - if matches!(token, Token::Output(..)) { - tb.add_child( token ); - } - } - } + if !any_outputs { + // Create an implicit output called "content" + outputs.push(Output{ + name: "content".to_string(), + code: children, + }); } else { - // We have another mix, now check to see if there - // are any outptus, if so this is an error. - if any_outputs { + if !all_text { return Err(ParseError{ position: *end.start(), what: "You cannot mix non-output and output tags in a view.".to_string() }); - } else { - // No outputs at all, we create an implict output - tb.add_child(Token::Output("content".to_string(), /*Properties::new(), */children )); } } - - return tb.build(); + return tb.build_view(ctx,outputs); } else { // They don't match, complain. return Err(ParseError{ @@ -392,10 +389,10 @@ impl Parser { Ok(name) } - fn parse_tag_body(&self, ctx: &mut Context ) -> ParseResult { + fn parse_tag_body<'a>(&self, ctx: &mut Context<'a> ) -> ParseResult> { let mut tb = self.parse_open_tag( ctx )?; if tb.is_unary() { - return tb.build(); + return Ok(tb); } loop { @@ -408,13 +405,13 @@ impl Parser { ctx.next(); } SymbolType::StartFlat => { - tb.add_child( self.parse_tag_body( ctx )? ); + tb.add_child( self.parse_tag_body( ctx )?.build()? ); } SymbolType::StartPoint => { let end = self.parse_end_tag( ctx )?; if tb.is_name(end.symbol()) { // They match, end. - return tb.build(); + return Ok(tb); } else { // They don't match, complain. return Err(ParseError{ @@ -424,7 +421,7 @@ impl Parser { } } SymbolType::Error{..} => { - self.lex_error( &ctx.cur().unwrap() )?; + return self.lex_error( &ctx.cur().unwrap() ); } _ => { @@ -565,15 +562,42 @@ impl<'a> TagBuilder<'a> { self.tag_type } + pub fn build_view(mut self, ctx: &Context, outputs: Vec) -> ParseResult { + if let Some(sym) = self.name { + if *sym.symbol() == SymbolType::View { + Ok(View { + name: self.params.swap_remove(0), + source: ctx.source(), + outputs: outputs, + //theme: Option + layout: self.props.get("layout").cloned(), + }) + } else { + Err(ParseError::new(self.start_pos, &format!("Expected tag type view, found {:?}", sym.symbol()))) + } + } else { + Err(ParseError::new(self.start_pos, "Broken Parser? No tag type found when building view.")) + } + } + + pub fn build_output(mut self, ctx: &Context) -> ParseResult { + if let Some(sym) = self.name { + if *sym.symbol() == SymbolType::Output { + Ok(Output { + name: self.params.swap_remove(0), + code: self.children, + }) + } else { + Err(ParseError::new(self.start_pos, &format!("Expected tag type view, found {:?}", sym.symbol()))) + } + } else { + Err(ParseError::new(self.start_pos, "Broken Parser? No tag type found when building view.")) + } + } + pub fn build(mut self) -> ParseResult { if let Some(sym) = self.name { match sym.symbol() { - SymbolType::View => { - Ok(Token::View(self.params.swap_remove(0), self.props, self.children)) - } - SymbolType::Output => { - Ok(Token::Output(self.params.swap_remove(0), /*self.props,*/ self.children)) - } SymbolType::Show => { Ok(Token::Show(self.params.swap_remove(0), self.props)) } -- cgit v1.2.3