summaryrefslogtreecommitdiff
path: root/src/parser.rs
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2025-09-27 17:59:43 +0800
committerlittleblack111 <littleblack11111@gmail.com>2025-09-27 17:59:52 +0800
commit76af2f9a4a06140d7e00706817b59678c4468d1a (patch)
tree80d4f3d799fa465500d5c54ff609b4ccc28b670e /src/parser.rs
parent282b9fad4db35d21618226dcd28dd041c9405930 (diff)
parser: preserve scope data as metadata
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs77
1 files changed, 63 insertions, 14 deletions
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<Metadata>)>;
+
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<Metadata>,
+}
+
+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<Expr<'_>> {
+pub fn process(strs: SplitWithMetadata<'_>) -> Vec<Expr<'_>> {
let mut exprs = Vec::new();
- for str in strs {
- let mut exp: Option<Expr> = None;
+ for (str, meta) in strs {
+ let mut exp: Option<ExprT> = 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,
+ }),
}
}