1use crate::{Delimiter, ParseError, Result, visitor::Visitor};
2
3pub struct Parser<'a,V> {
7 source: &'a [u8],
8
9 index: usize,
11 state: ParseState,
12 visitor: V,
13}
14
15impl<'a, V> Parser<'a, V> {
16 pub fn new(source: &'a str, visitor: V) -> Self {
22 Self {
23 source: source.as_bytes(),
24 index: 0,
25 state: ParseState::Static { start: 0 },
26 visitor,
27 }
28 }
29}
30
31enum ParseState {
32 Static { start: usize },
33 Expr { start: usize, open_delim: Delimiter },
34 OpenExpr { start: usize, brace: usize, },
35 CloseExpr { start: usize, brace: usize, open_delim: Delimiter, close_delim: Delimiter, },
36}
37
38impl<'a,V> Parser<'a,V>
39where
40 V: Visitor<'a>,
41{
42 pub fn parse(mut self) -> Result<V> {
44 loop {
45 let current = self.index;
46 let Some(byte) = self.source.get(current) else {
47 break self.parse_leftover()?;
48 };
49
50 match self.state {
51 ParseState::Static { start } => {
52 self.index += 1;
53 if matches!(byte,b'{') {
54 self.state = ParseState::OpenExpr { start, brace: current }
55 }
56 }
57 ParseState::Expr { start, open_delim } => {
58 self.index += 1;
59 if let Some(close_delim) = Delimiter::match_close(*byte) {
60 self.state = ParseState::CloseExpr {
61 start, brace: current, open_delim, close_delim,
62 }
63 }
64 }
65 ParseState::OpenExpr { start, brace } => {
66 match Delimiter::match_open(*byte) {
67 Some(open_delim) => {
68 self.index += 1;
69 self.state = ParseState::Expr { start: current + 1, open_delim };
70 let statics = Self::parse_str(&self.source[start..brace]);
71 if !statics.is_empty() {
72 self.visitor.visit_static(statics)?;
73 }
74 }
75 None => self.state = ParseState::Static { start }
76 }
77 }
78 ParseState::CloseExpr { start, brace, open_delim, close_delim } => {
79 match byte {
80 b'}' => {
81 if open_delim != close_delim {
82 return Err(ParseError::Generic(format!(
83 "delimiter shold be same, open `{}` closed with `{}`",
84 open_delim,close_delim,
85 )));
86 }
87
88 self.index += 1;
89 self.state = ParseState::Static { start: current + 1 };
90 self.visitor.visit_expr(Self::parse_str(&self.source[start..brace]), open_delim)?;
91 }
92 _ => self.state = ParseState::Expr { start, open_delim }
93 }
94 }
95 }
96 }
97
98 self.visitor.finish()
99 }
100
101 fn parse_leftover(&mut self) -> Result<()> {
102 match self.state {
103 ParseState::Static { start } | ParseState::OpenExpr { start, .. } => {
104 let statics = Self::parse_str(&self.source[start..]);
105 if statics.is_empty() {
106 Ok(())
107 } else {
108 self.visitor.visit_static(statics)
109 }
110 },
111 ParseState::Expr { .. } | ParseState::CloseExpr { .. } => {
112 Err(ParseError::Generic("unclosed expression".to_owned()))
114 },
115 }
116 }
117
118 fn parse_str(source: &[u8]) -> &str {
119 std::str::from_utf8(source)
120 .expect("the input is string and we only check using byte char")
121 }
122}
123