From 062048ef6e3e060bcf841ea2ec92e026f09d8da0 Mon Sep 17 00:00:00 2001 From: eichlan Date: Tue, 23 Jun 2026 15:31:51 -0700 Subject: Roorganized into workspace and packages. This is to accomidate a new proc_macro package, which can't have anything else in it. --- src/parser.rs | 785 ---------------------------------------------------------- 1 file changed, 785 deletions(-) delete mode 100644 src/parser.rs (limited to 'src/parser.rs') diff --git a/src/parser.rs b/src/parser.rs deleted file mode 100644 index 4f7ff6a..0000000 --- a/src/parser.rs +++ /dev/null @@ -1,785 +0,0 @@ -use crate::lexer::*; -use crate::*; - -struct Context<'a> { - cur: [Option>;2], - icur: usize, - ll: Lexer<'a>, - source: usize, -} - -impl<'a> Context<'a> { - 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, - source, - } - } - - 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() ); - self.cur[self.icur] - } - - pub fn cur(&self) -> Option> { - self.cur[self.icur] - } - - pub fn peek(&self) -> Option> { - self.cur[(self.icur+1)%2] - } - - /* - pub fn check_unwrapped bool>(&self, context: &str, f: T) -> CrimResult { - if self.cur().is_none() || self.peek().is_none() { - Err(CrimError::eos( context )) - } else { - Ok(f( self.cur().unwrap().symbol(), self.peek().unwrap().symbol())) - } - } - */ - - pub fn source(&self) -> usize { - self.source - } -} - -trait SymbolHelper { - fn is bool>(&self, context: &str, f: T ) -> CrimResult; - #[allow(dead_code)] - fn is_valid_tag_name(&self) -> CrimResult; -} - -impl<'a> SymbolHelper for Option> { - fn is bool>(&self, context: &str, f: T ) -> CrimResult { - if let Some(st) = self { - Ok(f( &st.symbol() )) - } else { - Err(CrimError::eos( context )) - } - } - - fn is_valid_tag_name(&self) -> CrimResult { - if let Some(st) = self { - Ok(match st.symbol() { - SymbolType::Token(_) | - SymbolType::View | - SymbolType::Output | - SymbolType::Loop | - SymbolType::If | - SymbolType::ElIf | - SymbolType::Else | - SymbolType::Show => true, - _ => false - }) - } else { - Err(CrimError::parse( - Position::none(), - "Unexpeceted end of stream.".to_string() - )) - } - } -} - -pub struct Parser { -} - -/** - * input: input complete_tag - * | input text - * | - * ; - * - * tag: unary_tag - * | multinary_open_tag - * | multinary_mid_tag - * | multinary_close_tag - * ; - * - * unary_tag: '[|' tag_guts '|]' - * ; - * - * | '[|' tag_guts '|>' - * | '<|' tag_guts '|>' - * | '<|' tag_guts '|]' - * ; - * - * tag_pair: open_tag tag_body close_tag - * ; - * - * tag_body: tag_body tag - * | tag_body tag_pair - * | tag_body text - * | - * ; - * - * open_tag: '[|' tag_guts '|>' - * ; - * - * close_tag: '<|' token '|]' - * ; - * - * tag_guts: 'view' literal props - * | 'section' literal - * | 'output' literal - * ; - * - * literal: '"' [^"]* '"' - * ; - * - * props: props token '=' literal - * | - * ; - * - * disambiguate (tm): - * - * input: input tag - * | input text - * | - * ; - * - * tag: open_tag_base unary_tag - * | open_tag_base binary_tag - * ; - * - * open_tag_base: '[|' tag_guts - * ; - * - * unary_tag: '|]' - * ; - * - * binary_tag: '|>' tag_body close_tag - * ; - * - * tag_body: tag_body tag - * | tag_body text - * | - * ; - * - * close_tag: '<|' token '|]' - * ; - * - * tag_guts: 'view' literal props - * | 'section' literal - * | 'output' literal - * ; - * - * literal: '"' [^"]* '"' - * ; - * - * props: props token '=' literal - * | - * ; - */ -impl Parser { - pub fn new() -> Self { - Self { - } - } - - fn lex_error(&self, error: &Symbol) -> CrimResult { - if let SymbolType::Error{what} = error.symbol() { - Err(CrimError::parse( *error.start(), - format!("What: {:?}", *what) - )) - } else { - Err(CrimError::parse( Position::none(), "Not an error?".into())) - } - } - - pub fn parse(&self, src: &str, source: usize ) -> CrimResult> { - let ll = Lexer::new( src ); - 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 ) -> CrimResult> { - let mut tags = Vec::new(); - loop { - if ctx.cur().is_none() { - break; - } - match ctx.cur().unwrap().symbol() { - SymbolType::Text(_) => { /* Skip top level text */ } - SymbolType::StartFlat => { - let tb = self.parse_tag( ctx )?; - let tb = self.parse_tag_set( ctx, tb )?; - tags.push( tb ); - } - SymbolType::Error{..} => { - self.lex_error( &ctx.cur().unwrap() )?; - } - _ => { - return Err(CrimError::parse( - *ctx.cur().unwrap().start(), - format!("Unexpected symbol {:?} found looking for tags.", ctx.cur().unwrap().symbol() ) - )); - } - } - ctx.next(); - } - - let mut views = Vec::new(); - for tag in tags { - let start_pos = tag.start_pos(); - let name = tag.name().clone(); - if tag.is_name(&SymbolType::View) && - let BuildResult::View(view) = tag.build( ctx )? { - views.push( view ); - } else { - return Err(CrimError::parse( - start_pos, - format!("Expected view at root, found {:?}", name ) - )); - } - } - Ok(views) - } - - fn parse_tag<'a>(&self, ctx: &mut Context<'a>) -> CrimResult> { - let start_sym = ctx.cur().unwrap(); - let mut tb = TagBuilder::new(&start_sym); - - if ctx.next().is_some() { - match ctx.cur().unwrap().symbol() { - SymbolType::View | SymbolType::Show | SymbolType::Loop | - SymbolType::If | SymbolType::ElIf | SymbolType::Else | - SymbolType::Output => { - let name_sym = ctx.cur().unwrap(); - ctx.next(); - tb.set_name( name_sym ); - } - _ => { - return Err(CrimError::parse( - *ctx.cur().unwrap().start(), - "Unexpected symbol".to_string() - )); - } - } - } else { - return Err(CrimError::eos("tag type")); - } - - if tb.can_have_params() || tb.can_have_expr() { - self.parse_tag_params( ctx, &mut tb )?; - } - if tb.can_have_props() { - self.parse_tag_props( ctx, &mut tb )?; - } - - if let Some(end_sym) = ctx.cur() { - match end_sym.symbol() { - SymbolType::EndPoint | SymbolType::EndFlat => { - tb.set_end( &end_sym )?; - } - _ => { - return Err(CrimError::parse( - *end_sym.start(), - format!("Unexpected symbol {:?} looking for end of tag.", end_sym.symbol()) - )); - } - } - } - - ctx.next(); - - Ok(tb) - } - - fn parse_tag_set<'a>(&self, ctx: &mut Context<'a>, mut base: TagBuilder<'a>) -> CrimResult> { - if base.is_unary() { - return Ok(base); - } - - loop { - if ctx.cur().is_none() { - return Err(CrimError::eos(format!("close tag for {:?}", base.name()).as_str())); - } - match ctx.cur().unwrap().symbol() { - SymbolType::Text(s) => { - base.add_child(Entry::Token(Token::Text(s.to_string()))); - ctx.next(); - } - SymbolType::StartFlat | SymbolType::StartPoint => { - let tb = self.parse_tag( ctx )?; - - match tb.tag_type() { - TagType::MultinaryOpen => { - base.add_child(Entry::TagBuilder(self.parse_tag_set( ctx, tb )?)); - } - TagType::MultinaryMid => { - base.add_chain(Entry::TagBuilder(self.parse_tag_set( ctx, tb )?)); - return Ok(base); - } - TagType::MultinaryClose => { - if (tb.is_name(&SymbolType::If) && - (base.is_name(&SymbolType::ElIf) || - base.is_name(&SymbolType::Else))) || - tb.is_name(base.name().unwrap().symbol()) { - return Ok(base); - } else { - return Err(CrimError::parse( - *tb.name().unwrap().start(), - format!("Found {:?} looking for close of {:?}", tb.name().unwrap().symbol(), base.name().unwrap().symbol()) - )); - } - } - TagType::Unary => { - base.add_child(Entry::TagBuilder(tb)); - } - TagType::Unknown => { - return Err(CrimError::broken(base.start_pos(), "Found unknown tag when looking for something else.")); - } - } - } - SymbolType::Error{..} => { - return self.lex_error( &ctx.cur().unwrap() ); - } - _ => { - return Err(CrimError::parse( - *ctx.cur().unwrap().start(), - format!("Unexpected token: {:?}", ctx.cur().unwrap().symbol()), - )); - } - } - } - } - - fn parse_tag_params(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> CrimResult<()> { - loop { - if ctx.cur().is_none() { - return Err(CrimError::eos("tag parameters")); - } - match ctx.cur().unwrap().symbol() { - SymbolType::Literal(s) => { - tb.add_param( ParamValue::Literal(s.to_string()) ); - ctx.next(); - } - SymbolType::Token(_) | SymbolType::Sharp => { - if ctx.peek().is("tag data", |s| *s == SymbolType::Equals)? { - break; - } - tb.add_param( self.parse_identifier( ctx )? ); - } - _ => { - break; - } - } - } - Ok(()) - } - - fn parse_identifier(&self, ctx: &mut Context ) -> CrimResult { - let mut id = Identifier::new(); - - if ctx.cur().is("identifier",|s| matches!( s, SymbolType::Sharp))? { - id.push( IdentifierValue::Root ); - ctx.next(); - } - loop { - if ctx.cur().is("identifier",|s| matches!( s, SymbolType::Token(_) ))? { - if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { - id.push( IdentifierValue::Name(s.to_string()) ); - } - } else { - return Err(CrimError::parse( ctx.cur().unwrap().start().clone(), format!("Expeceted identifier, found {:?}", ctx.cur().unwrap().symbol() ) ) ); - } - - if !ctx.next().is("identifier seperator",|s| *s == SymbolType::Period )? { - break; - } - ctx.next(); - } - - Ok(ParamValue::Identifier(id)) - } - - fn parse_tag_props(&self, ctx: &mut Context, tb: &mut TagBuilder ) -> CrimResult<()> { - loop { - if ctx.cur().is_none() { - return Err(CrimError::eos("tag properties")); - } - if let SymbolType::Token(s) = ctx.cur().unwrap().symbol() { - if ctx.peek().is_some_and(|s|s.check_type(|t| matches!(t,SymbolType::Equals))) { - ctx.next(); - if let Some(sym) = ctx.next() && - let SymbolType::Literal(lv) = sym.symbol() { - tb.add_prop( s.to_string(), lv.to_string() ); - } else { - return Err(CrimError::parse(Position::none(),"Expected quoted literal string".to_string())); - } - } else { - break; - } - } else { - break; - } - ctx.next(); - } - Ok(()) - } -} - -#[derive(PartialEq,Copy,Clone,Debug)] -enum TagType { - Unknown, - Unary, - MultinaryOpen, - MultinaryMid, - MultinaryClose, -} - -#[derive(Debug)] -enum Entry<'a>{ - Token(Token), - TagBuilder(TagBuilder<'a>), -} - -type EntryList<'a> = Vec>; - -trait EntryListConverter { - fn has_outputs(&self) -> bool; - fn to_outputs(&mut self, ctx: &mut Context ) -> CrimResult>; - fn to_tokens(&mut self, ctx: &mut Context) -> CrimResult>; -} - -impl<'a> EntryListConverter for EntryList<'a> { - fn has_outputs(&self) -> bool { - self.iter().any(|e| - if let Entry::TagBuilder(tb) = e - && tb.is_name(&SymbolType::Output) { - true - } else { - false - } - ) - } - - fn to_outputs(&mut self, ctx: &mut Context) -> CrimResult> { - let mut outputs = Vec::new(); - - if self.has_outputs() { - // We have an explicit output, we cant have anything else - for e in self.drain(..) { - let tb = if let Entry::TagBuilder(tb) = e { - tb - } else { - continue; - }; - if let BuildResult::Output(out) = tb.build(ctx)? { - outputs.push( out ); - } - } - } else { - // No outputs, so we create one implicit output - outputs.push(Output { - name: "content".into(), - code: self.to_tokens(ctx)? - }); - } - - Ok(outputs) - } - - fn to_tokens(&mut self, ctx: &mut Context) -> CrimResult> { - let mut tokens : Vec = Vec::new(); - for e in self.drain(..) { - match e { - Entry::Token(token) => { - tokens.push( token ); - } - Entry::TagBuilder(tb) => { - if let BuildResult::Token(token) = tb.build(ctx)? { - tokens.push( token ); - } else { - return Err(CrimError::broken( Position::none(), "Non-token result built.")); - } - } - } - } - Ok(tokens) - } -} - -#[derive(Debug)] -struct TagBuilder<'a> { - name: Option>, - params: Vec, - props: Properties, - children: Vec>, - tag_type: TagType, - start: Symbol<'a>, - chain: Vec>, -} - -#[derive(Debug)] -enum ParamValue { - Literal(String), - Identifier(Identifier), -} - -enum BuildResult { - View(View), - Output(Output), - Token(Token), -} - -impl<'a> TagBuilder<'a> { - pub fn new(start: &Symbol<'a>) -> TagBuilder<'a> { - TagBuilder { - name: None, - params: Vec::new(), - props: Properties::new(), - children: Vec::new(), - tag_type: TagType::Unknown, - start: start.clone(), - chain: Vec::new(), - } - } - - pub fn set_end(&mut self, end: &Symbol) -> CrimResult<()> { - if *self.start.symbol() == SymbolType::StartFlat { - if *end.symbol() == SymbolType::EndFlat { - self.tag_type = TagType::Unary; - } else if *end.symbol() == SymbolType::EndPoint { - self.tag_type = TagType::MultinaryOpen; - } else { - return Err(CrimError::broken( *end.start(), "Invalid bracket token type.")); - } - } else if *self.start.symbol() == SymbolType::StartPoint { - if *end.symbol() == SymbolType::EndFlat { - self.tag_type = TagType::MultinaryClose; - } else if *end.symbol() == SymbolType::EndPoint { - self.tag_type = TagType::MultinaryMid; - } else { - return Err(CrimError::broken( *end.start(), "Invalid bracket token type.")); - } - } else { - return Err(CrimError::broken( *self.start.start(), "Invalid bracket token type.")); - } - Ok(()) - } - - pub fn start_pos(&self) -> Position { - *self.start.start() - } - - pub fn is_unary(&self) -> bool { - self.tag_type == TagType::Unary - } -/* - pub fn is_multinary_open(&self) -> bool { - self.tag_type == TagType::MultinaryOpen - } -*/ - pub fn can_have_params(&self) -> bool { - match self.name.unwrap().symbol() { - SymbolType::View | SymbolType::Output | SymbolType::Loop => true, - SymbolType::Show | SymbolType::If | SymbolType::ElIf | - SymbolType::Else => false, - _ => false, - } - } - - pub fn can_have_expr(&self) -> bool { - match self.name.unwrap().symbol() { - SymbolType::View | SymbolType::Output | SymbolType::Loop => false, - SymbolType::Show | SymbolType::If | SymbolType::ElIf | - SymbolType::Else => true, - _ => false, - } - } - - pub fn can_have_props(&self) -> bool { - true - } -/* - pub fn can_have_children(&self) -> bool { - if self.tag_type == TagType::MultinaryOpen || - self.tag_type == TagType::MultinaryMid { - true - } else { - false - } - } -*/ - pub fn is_name(&self, name: &SymbolType<'a>) -> bool { - if let Some(a) = self.name { - a.symbol() == name - } else { - false - } - } - - pub fn name(&self) -> Option> { - self.name - } -/* - pub fn params(&self) -> &Vec { - &self.params - } -*/ - pub fn set_name(&mut self, name: Symbol<'a>) { - self.name = Some(name); - } - - pub fn add_param(&mut self, param: ParamValue) { - self.params.push( param ); - } - - pub fn add_prop(&mut self, key: String, value: String) { - self.props.insert( key, value ); - } - - pub fn add_child(&mut self, tb: Entry<'a>) { - self.children.push( tb ); - } -/* - pub fn append_children(&mut self, children: &mut Vec::>) { - self.children.append( children ); - } -*/ - pub fn add_chain(&mut self, tb: Entry<'a>) { - self.chain.push( tb ); - } -/* - pub fn set_type(&mut self, tag_type: TagType) { - self.tag_type = tag_type; - } -*/ - pub fn tag_type(&self) -> TagType { - self.tag_type - } - - pub fn build(mut self, ctx: &mut Context ) -> CrimResult { - if let Some(sym) = self.name { - match sym.symbol() { - SymbolType::View => { - let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { - s.to_string() - } else { - return Err(CrimError::parse(Position::none(), "Expected string literal for view name.".to_string())); - }; - Ok(BuildResult::View(View { - name: name, - source: ctx.source(), - outputs: self.children.to_outputs(ctx)?, - //theme: Option - layout: self.props.get("layout").cloned(), - })) - } - SymbolType::Output => { - let name = if let ParamValue::Literal(s) = self.params.swap_remove(0) { - s.to_string() - } else { - return Err(CrimError::parse(Position::none(), "Expected string literal for output name.".into())); - }; - Ok(BuildResult::Output(Output { - name: name, - code: self.children.to_tokens(ctx)?, - })) - } - SymbolType::Loop => { - let id = if let ParamValue::Identifier(id) - = self.params.swap_remove(0) { - id - } else { - return Err(CrimError::parse( - Position::none(), - "Identifier for loop variable name.".into()) - ); - }; - Ok(BuildResult::Token( - Token::Loop(id, self.children.to_tokens(ctx)?) - )) - } - SymbolType::Show => { - let id = if let ParamValue::Identifier(id) - = self.params.swap_remove(0) { - id - } else { - return Err(CrimError::parse( - Position::none(), - "Identifier for show variable name.".into()) - ); - }; - Ok(BuildResult::Token(Token::Show(id, self.props))) - } - SymbolType::If => { - let id = if let ParamValue::Identifier(id) - = self.params.swap_remove(0) { - id - } else { - return Err(CrimError::parse( - Position::none(), - "Identifier for if variable name.".into()) - ); - }; - - let is_else = if self.chain.len() == 1 && - let Entry::TagBuilder(tb) = &self.chain[0] && - tb.is_name(&SymbolType::Else) && - tb.params.len() == 0 { - true - } else { - false - }; - - if is_else && - let Entry::TagBuilder(mut tb) = self.chain.swap_remove(0) { - self.chain.clear(); - self.chain.append(&mut tb.children); - } - Ok(BuildResult::Token(Token::If(id, self.children.to_tokens(ctx)?, self.chain.to_tokens(ctx)?))) - } - SymbolType::ElIf => { - let id = if let ParamValue::Identifier(id) = self.params.swap_remove(0) { - id - } else { - return Err(CrimError::parse( - Position::none(), - "Identifier for elif variable name.".into()) - ); - }; - - // this is copied from if, since they're the same this - // should be encapsulated and moved into a function... - // ...but I can't do that right now. - let is_else = if self.chain.len() == 1 && - let Entry::TagBuilder(tb) = &self.chain[0] && - tb.is_name(&SymbolType::Else) && - tb.params.len() == 0 { - true - } else { - false - }; - - if is_else && - let Entry::TagBuilder(mut tb) = self.chain.swap_remove(0) { - self.chain.clear(); - self.chain.append(&mut tb.children); - } - - - Ok(BuildResult::Token(Token::If(id, self.children.to_tokens(ctx)?, self.chain.to_tokens(ctx)?))) - } - SymbolType::Else => { - Ok(BuildResult::Token(Token::If(Identifier::new(), self.children.to_tokens(ctx)?, self.chain.to_tokens(ctx)?))) - } - _ => { - Err(CrimError::parse( self.start_pos(), "Bad tag type".into())) - } - } - } else { - Err(CrimError::parse(self.start_pos(), "Bad tag type".into())) - } - } -} -- cgit v1.2.3