1use crate::compiling::failing::failure::Failure;
2use colored::Colorize;
3
4use super::Metadata;
5
6#[macro_export]
7macro_rules! syntax_name {
21 ($expr:expr) => {
22 fn name() -> &'static str {
23 $expr
24 }
25 };
26}
27
28pub type SyntaxResult = Result<(), Failure>;
30
31pub trait SyntaxModule<M: Metadata> {
60 fn new() -> Self;
62 fn name() -> &'static str;
64 fn parse(&mut self, meta: &mut M) -> SyntaxResult;
69 fn parse_debug(&mut self, meta: &mut M) -> SyntaxResult {
71 match meta.get_debug() {
72 Some(debug) => {
73 let padding = " ".repeat(debug);
74 println!("{padding}[Entered] {}", Self::name());
75 meta.set_debug(debug + 1);
76 let time = std::time::Instant::now();
77 let result = self.parse(meta);
78 match result {
79 Ok(()) => println!("{padding}{} {} ({}ms)", "[Left]".green(), Self::name(), time.elapsed().as_millis()),
80 Err(_) => println!("{padding}{} {} ({}ms)", "[Failed]".red(), Self::name(), time.elapsed().as_millis())
81 }
82 meta.set_debug(debug);
83 result
84 }
85 None => {
86 meta.set_debug(0);
87 self.parse_debug(meta)
88 }
89 }
90 }
91}
92
93#[cfg(test)]
94mod test {
95 use super::*;
96 use crate::compiling::parser::pattern::*;
97 use crate::compiling::parser::preset::*;
98 use crate::compiling::{ Token, DefaultMetadata, Metadata };
99
100 struct Expression {}
101 impl SyntaxModule<DefaultMetadata> for Expression {
102 syntax_name!("Expression");
103
104 fn new() -> Self {
105 Expression { }
106 }
107 fn parse(&mut self, meta: &mut DefaultMetadata) -> SyntaxResult {
108 token(meta, "let")?;
109 Ok(())
110 }
111 }
112
113 #[test]
114 fn test_token_match() {
115 let mut exp = Expression {};
116 let dataset1 = vec![
117 Token {
118 word: format!("let"),
119 pos: (0, 0),
120 start: 0
121 }
122 ];
123 let dataset2 = vec![
124 Token {
125 word: format!("tell"),
126 pos: (0, 0),
127 start: 0
128 }
129 ];
130 let path = Some(format!("path/to/file"));
131 let result1 = exp.parse(&mut DefaultMetadata::new(dataset1, path.clone(), None));
132 let result2 = exp.parse(&mut DefaultMetadata::new(dataset2, path.clone(), None));
133 assert!(result1.is_ok());
134 assert!(result2.is_err());
135 }
136
137 struct Preset {}
138 impl SyntaxModule<DefaultMetadata> for Preset {
139 syntax_name!("Preset");
140 fn new() -> Self {
141 Preset { }
142 }
143 fn parse(&mut self, meta: &mut DefaultMetadata) -> SyntaxResult {
144 variable(meta, vec!['_'])?;
145 numeric(meta, vec![])?;
146 number(meta, vec![])?;
147 integer(meta, vec![])?;
148 float(meta, vec![])?;
149 Ok(())
150 }
151 }
152
153 #[test]
154 fn test_preset_match() {
155 let mut exp = Preset {};
156 let dataset = vec![
157 Token { word: format!("_text"), pos: (0, 0), start: 0 },
159 Token { word: format!("12321"), pos: (0, 0), start: 0 },
161 Token { word: format!("-123.12"), pos: (0, 0), start: 0 },
163 Token { word: format!("-12"), pos: (0, 0), start: 0 },
165 Token { word: format!("-.681"), pos: (0, 0), start: 0 }
167 ];
168 let path = Some(format!("path/to/file"));
169 let result = exp.parse(&mut DefaultMetadata::new(dataset, path, None));
170 assert!(result.is_ok());
171 }
172
173 struct PatternModule {}
174 impl SyntaxModule<DefaultMetadata> for PatternModule {
175 syntax_name!("Pattern Module");
176 fn new() -> Self {
177 PatternModule { }
178 }
179 #[allow(unused_must_use)]
180 fn parse(&mut self, meta: &mut DefaultMetadata) -> SyntaxResult {
181 if let Ok(_) = token(meta, "apple") {}
183 else if let Ok(_) = token(meta, "orange") {}
184 else if let Ok(_) = token(meta, "banana") {}
185 else {
186 if let Err(details) = token(meta, "banana") {
187 return Err(details);
188 }
189 }
190 token(meta, "optional");
192 syntax(meta, &mut Expression::new())?;
194 loop {
196 if let Err(_) = token(meta, "test") {
197 break;
198 }
199 if let Err(_) = token(meta, ",") {
200 break;
201 }
202 }
203 token(meta, "end");
205 Ok(())
206 }
207 }
208
209 #[test]
210 fn rest_match() {
211 let mut exp = PatternModule {};
212 let dataset1 = vec![
214 Token { word: format!("orange"), pos: (0, 0), start: 0 },
215 Token { word: format!("optional"), pos: (0, 0), start: 0 },
216 Token { word: format!("let"), pos: (0, 0), start: 0 },
217 Token { word: format!("this"), pos: (0, 0), start: 0 },
218 Token { word: format!(","), pos: (0, 0), start: 0 },
219 Token { word: format!("this"), pos: (0, 0), start: 0 },
220 Token { word: format!("end"), pos: (0, 0), start: 0 }
221 ];
222 let dataset2 = vec![
224 Token { word: format!("kiwi"), pos: (0, 0), start: 0 },
225 Token { word: format!("optional"), pos: (0, 0), start: 0 },
226 Token { word: format!("let"), pos: (0, 0), start: 0 },
227 Token { word: format!("this"), pos: (0, 0), start: 0 },
228 Token { word: format!(","), pos: (0, 0), start: 0 },
229 Token { word: format!("this"), pos: (0, 0), start: 0 },
230 Token { word: format!("end"), pos: (0, 0), start: 0 }
231 ];
232 let dataset3 = vec![
234 Token { word: format!("orange"), pos: (0, 0), start: 0 },
235 Token { word: format!("tell"), pos: (0, 0), start: 0 },
236 Token { word: format!("this"), pos: (0, 0), start: 0 },
237 Token { word: format!(","), pos: (0, 0), start: 0 },
238 Token { word: format!("this"), pos: (0, 0), start: 0 },
239 Token { word: format!("end"), pos: (0, 0), start: 0 }
240 ];
241 let dataset4 = vec![
243 Token { word: format!("orange"), pos: (0, 0), start: 0 },
244 Token { word: format!("tell"), pos: (0, 0), start: 0 },
245 Token { word: format!("this"), pos: (0, 0), start: 0 },
246 Token { word: format!(","), pos: (0, 0), start: 0 },
247 Token { word: format!("this"), pos: (0, 0), start: 0 },
248 Token { word: format!("this"), pos: (0, 0), start: 0 },
249 Token { word: format!("end"), pos: (0, 0), start: 0 }
250 ];
251 let path = Some(format!("path/to/file"));
252 let result1 = exp.parse(&mut DefaultMetadata::new(dataset1, path.clone(), None));
253 let result2 = exp.parse(&mut DefaultMetadata::new(dataset2, path.clone(), None));
254 let result3 = exp.parse(&mut DefaultMetadata::new(dataset3, path.clone(), None));
255 let result4 = exp.parse(&mut DefaultMetadata::new(dataset4, path.clone(), None));
256 assert!(result1.is_ok());
257 assert!(result2.is_err());
258 assert!(result3.is_err());
259 assert!(result4.is_err());
260 }
261
262}