From 76af2f9a4a06140d7e00706817b59678c4468d1a Mon Sep 17 00:00:00 2001 From: littleblack111 Date: Sat, 27 Sep 2025 17:59:43 +0800 Subject: parser: preserve scope data as metadata --- src/parser.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 14 deletions(-) (limited to 'src/parser.rs') diff --git a/src/parser.rs b/src/parser.rs index 69c4856..544c296 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,7 @@ use crate::tokenizer::{self, If, Keyword::*, Loop}; +pub type SplitWithMetadata<'a> = Vec<(&'a str, Option)>; + pub const EXPRESSION_DELIMITERS: &[char] = &[ ';', '{', '}', ]; @@ -11,40 +13,87 @@ pub enum Scope { } #[derive(Debug)] -pub enum Expr<'a> { +pub enum Metadata { + StartScope, + EndScope, +} + +#[derive(Debug)] +pub enum ExprT<'a> { StartOrStop(bool), Decision((&'a str, Scope)), IO(&'a str), Process(&'a str), } -pub fn delimit(str: &str) -> Vec<&str> { - str.split(|c| EXPRESSION_DELIMITERS.contains(&c)) - .filter(|c| !c.is_empty()) - .collect() +#[derive(Debug)] +pub struct Expr<'a> { + pub expr: ExprT<'a>, + pub meta: Option, +} + +pub fn delimit(s: &str) -> SplitWithMetadata<'_> { + s.split_inclusive([ + ';', '{', '}', + ]) + .fold(Vec::new(), |mut acc, part| { + if let Some((i, ch)) = part + .char_indices() + .next_back() + { + let body = if ch == ';' || ch == '{' || ch == '}' { + part[..i].trim() + } else { + part.trim() + }; + if !body.is_empty() { + acc.push((body, None)); + } + match ch { + '{' => { + if let Some(last) = acc.last_mut() { + last.1 = Some(Metadata::StartScope); + } + } + '}' => { + if let Some(last) = acc.last_mut() { + last.1 = Some(Metadata::EndScope); + } + } + _ => {} + } + } + acc + }) } -pub fn process(strs: Vec<&str>) -> Vec> { +pub fn process(strs: SplitWithMetadata<'_>) -> Vec> { let mut exprs = Vec::new(); - for str in strs { - let mut exp: Option = None; + for (str, meta) in strs { + let mut exp: Option = None; // TODO: fix one line if else as not delimited by {} for s in str.split_whitespace() { if let Some(token) = tokenizer::parse(s) { exp = match token { - If(t) => Some(Expr::Decision((str, Scope::If(t.to_owned())))), - Loop(t) => Some(Expr::Decision((str, Scope::Loop(t.to_owned())))), - Throw => Some(Expr::IO(str)), - IO => Some(Expr::IO(str)), + If(t) => Some(ExprT::Decision((str, Scope::If(t.to_owned())))), + Loop(t) => Some(ExprT::Decision((str, Scope::Loop(t.to_owned())))), + Throw => Some(ExprT::IO(str)), + IO => Some(ExprT::IO(str)), } } } match exp { - Some(exp) => exprs.push(exp), - None => exprs.push(Expr::Process(str)), + Some(expr) => exprs.push(Expr { + expr, + meta, + }), + None => exprs.push(Expr { + expr: ExprT::Process(str), + meta: None, + }), } } -- cgit v1.2.3