1use dypdl::expression;
4use rustc_hash::FxHashMap;
5
6mod argument_parser;
7mod condition_parser;
8mod continuous_parser;
9mod continuous_vector_parser;
10mod element_parser;
11mod integer_parser;
12mod integer_vector_parser;
13mod numeric_table_parser;
14mod table_vector_parser;
15mod util;
16
17pub use util::ParseErr;
18
19pub fn parse_integer(
27 text: String,
28 metadata: &dypdl::StateMetadata,
29 functions: &dypdl::StateFunctions,
30 registry: &dypdl::TableRegistry,
31 parameters: &FxHashMap<String, usize>,
32) -> Result<expression::IntegerExpression, ParseErr> {
33 let tokens = tokenize(text);
34 let (expression, rest) =
35 integer_parser::parse_expression(&tokens, metadata, functions, registry, parameters)?;
36 if rest.is_empty() {
37 Ok(expression)
38 } else {
39 Err(ParseErr::new(format!(
40 "unexpected tokens: `{rest}`",
41 rest = rest.join(" ")
42 )))
43 }
44}
45
46pub fn parse_continuous(
54 text: String,
55 metadata: &dypdl::StateMetadata,
56 functions: &dypdl::StateFunctions,
57 registry: &dypdl::TableRegistry,
58 parameters: &FxHashMap<String, usize>,
59) -> Result<expression::ContinuousExpression, ParseErr> {
60 let tokens = tokenize(text);
61 let (expression, rest) =
62 continuous_parser::parse_expression(&tokens, metadata, functions, registry, parameters)?;
63 if rest.is_empty() {
64 Ok(expression)
65 } else {
66 Err(ParseErr::new(format!(
67 "unexpected tokens: `{rest}`",
68 rest = rest.join(" ")
69 )))
70 }
71}
72
73pub fn parse_element(
81 text: String,
82 metadata: &dypdl::StateMetadata,
83 functions: &dypdl::StateFunctions,
84 registry: &dypdl::TableRegistry,
85 parameters: &FxHashMap<String, usize>,
86) -> Result<expression::ElementExpression, ParseErr> {
87 let tokens = tokenize(text);
88 let (expression, rest) =
89 element_parser::parse_expression(&tokens, metadata, functions, registry, parameters)?;
90 if rest.is_empty() {
91 Ok(expression)
92 } else {
93 Err(ParseErr::new(format!(
94 "unexpected tokens: `{rest}`",
95 rest = rest.join(" ")
96 )))
97 }
98}
99
100pub fn parse_set(
108 text: String,
109 metadata: &dypdl::StateMetadata,
110 functions: &dypdl::StateFunctions,
111 registry: &dypdl::TableRegistry,
112 parameters: &FxHashMap<String, usize>,
113) -> Result<expression::SetExpression, ParseErr> {
114 let tokens = tokenize(text);
115 let (expression, rest) =
116 element_parser::parse_set_expression(&tokens, metadata, functions, registry, parameters)?;
117 if rest.is_empty() {
118 Ok(expression)
119 } else {
120 Err(ParseErr::new(format!(
121 "unexpected tokens: `{rest}`",
122 rest = rest.join(" ")
123 )))
124 }
125}
126
127pub fn parse_vector(
135 text: String,
136 metadata: &dypdl::StateMetadata,
137 functions: &dypdl::StateFunctions,
138 registry: &dypdl::TableRegistry,
139 parameters: &FxHashMap<String, usize>,
140) -> Result<expression::VectorExpression, ParseErr> {
141 let tokens = tokenize(text);
142 let (expression, rest) = element_parser::parse_vector_expression(
143 &tokens, metadata, functions, registry, parameters,
144 )?;
145 if rest.is_empty() {
146 Ok(expression)
147 } else {
148 Err(ParseErr::new(format!(
149 "unexpected tokens: `{rest}`",
150 rest = rest.join(" ")
151 )))
152 }
153}
154
155pub fn parse_condition(
163 text: String,
164 metadata: &dypdl::StateMetadata,
165 functions: &dypdl::StateFunctions,
166 registry: &dypdl::TableRegistry,
167 parameters: &FxHashMap<String, usize>,
168) -> Result<expression::Condition, ParseErr> {
169 let tokens = tokenize(text);
170 let (expression, rest) =
171 condition_parser::parse_expression(&tokens, metadata, functions, registry, parameters)?;
172 if rest.is_empty() {
173 Ok(expression)
174 } else {
175 Err(ParseErr::new(format!(
176 "unexpected tokens: `{rest}`",
177 rest = rest.join(" ")
178 )))
179 }
180}
181
182fn tokenize(text: String) -> Vec<String> {
183 text.replace('(', " ( ")
184 .replace(')', " ) ")
185 .replace('|', " | ")
186 .replace('~', " ~ ")
187 .replace('{', " { ")
188 .replace('}', " } ")
189 .replace(':', " : ")
190 .split_whitespace()
191 .map(|x| x.to_string())
192 .collect()
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 use dypdl::*;
200
201 fn generate_metadata() -> dypdl::StateMetadata {
202 let object_names = vec!["object".to_string()];
203 let object_numbers = vec![10];
204 let mut name_to_object = FxHashMap::default();
205 name_to_object.insert("object".to_string(), 0);
206
207 let set_variable_names = vec![
208 "s0".to_string(),
209 "s1".to_string(),
210 "s2".to_string(),
211 "s3".to_string(),
212 ];
213 let mut name_to_set_variable = FxHashMap::default();
214 name_to_set_variable.insert("s0".to_string(), 0);
215 name_to_set_variable.insert("s1".to_string(), 1);
216 name_to_set_variable.insert("s2".to_string(), 2);
217 name_to_set_variable.insert("s3".to_string(), 3);
218 let set_variable_to_object = vec![0, 0, 0, 0];
219
220 let vector_variable_names = vec![
221 "p0".to_string(),
222 "p1".to_string(),
223 "p2".to_string(),
224 "p3".to_string(),
225 ];
226 let mut name_to_vector_variable = FxHashMap::default();
227 name_to_vector_variable.insert("p0".to_string(), 0);
228 name_to_vector_variable.insert("p1".to_string(), 1);
229 name_to_vector_variable.insert("p2".to_string(), 2);
230 name_to_vector_variable.insert("p3".to_string(), 3);
231 let vector_variable_to_object = vec![0, 0, 0, 0];
232
233 let element_variable_names = vec![
234 "e0".to_string(),
235 "e1".to_string(),
236 "e2".to_string(),
237 "e3".to_string(),
238 ];
239 let mut name_to_element_variable = FxHashMap::default();
240 name_to_element_variable.insert("e0".to_string(), 0);
241 name_to_element_variable.insert("e1".to_string(), 1);
242 name_to_element_variable.insert("e2".to_string(), 2);
243 name_to_element_variable.insert("e3".to_string(), 3);
244 let element_variable_to_object = vec![0, 0, 0, 0];
245
246 let integer_variable_names = vec![
247 "n0".to_string(),
248 "n1".to_string(),
249 "n2".to_string(),
250 "n3".to_string(),
251 ];
252 let mut name_to_integer_variable = FxHashMap::default();
253 name_to_integer_variable.insert("n0".to_string(), 0);
254 name_to_integer_variable.insert("n1".to_string(), 1);
255 name_to_integer_variable.insert("n2".to_string(), 2);
256 name_to_integer_variable.insert("n3".to_string(), 3);
257
258 let integer_resource_variable_names = vec![
259 "r0".to_string(),
260 "r1".to_string(),
261 "r2".to_string(),
262 "r3".to_string(),
263 ];
264 let mut name_to_integer_resource_variable = FxHashMap::default();
265 name_to_integer_resource_variable.insert("r0".to_string(), 0);
266 name_to_integer_resource_variable.insert("r1".to_string(), 1);
267 name_to_integer_resource_variable.insert("r2".to_string(), 2);
268 name_to_integer_resource_variable.insert("r3".to_string(), 3);
269
270 let continuous_variable_names = vec![
271 "c0".to_string(),
272 "c1".to_string(),
273 "c2".to_string(),
274 "c3".to_string(),
275 ];
276 let mut name_to_continuous_variable = FxHashMap::default();
277 name_to_continuous_variable.insert("c0".to_string(), 0);
278 name_to_continuous_variable.insert("c1".to_string(), 1);
279 name_to_continuous_variable.insert("c2".to_string(), 2);
280 name_to_continuous_variable.insert("c3".to_string(), 3);
281
282 dypdl::StateMetadata {
283 object_type_names: object_names,
284 name_to_object_type: name_to_object,
285 object_numbers,
286 set_variable_names,
287 name_to_set_variable,
288 set_variable_to_object,
289 vector_variable_names,
290 name_to_vector_variable,
291 vector_variable_to_object,
292 element_variable_names,
293 name_to_element_variable,
294 element_variable_to_object,
295 integer_variable_names,
296 name_to_integer_variable,
297 integer_resource_variable_names,
298 name_to_integer_resource_variable,
299 integer_less_is_better: vec![false, false, true, false],
300 continuous_variable_names,
301 name_to_continuous_variable,
302 ..Default::default()
303 }
304 }
305
306 fn generate_parameters() -> FxHashMap<String, usize> {
307 let mut parameters = FxHashMap::default();
308 parameters.insert("param".to_string(), 0);
309 parameters
310 }
311
312 fn generate_registry() -> dypdl::TableRegistry {
313 let mut name_to_constant = FxHashMap::default();
314 name_to_constant.insert(String::from("f0"), 0);
315
316 let tables_1d = vec![Table1D::new(Vec::new())];
317 let mut name_to_table_1d = FxHashMap::default();
318 name_to_table_1d.insert(String::from("f1"), 0);
319
320 let tables_2d = vec![Table2D::new(Vec::new())];
321 let mut name_to_table_2d = FxHashMap::default();
322 name_to_table_2d.insert(String::from("f2"), 0);
323
324 let tables_3d = vec![Table3D::new(Vec::new())];
325 let mut name_to_table_3d = FxHashMap::default();
326 name_to_table_3d.insert(String::from("f3"), 0);
327
328 let tables = vec![Table::new(FxHashMap::default(), 0)];
329 let mut name_to_table = FxHashMap::default();
330 name_to_table.insert(String::from("f4"), 0);
331
332 dypdl::TableRegistry {
333 integer_tables: dypdl::TableData {
334 name_to_constant,
335 tables_1d,
336 name_to_table_1d,
337 tables_2d,
338 name_to_table_2d,
339 tables_3d,
340 name_to_table_3d,
341 tables,
342 name_to_table,
343 },
344 ..Default::default()
345 }
346 }
347
348 #[test]
349 fn parse_set_ok() {
350 let metadata = generate_metadata();
351 let functions = dypdl::StateFunctions::default();
352 let registry = generate_registry();
353 let parameters = generate_parameters();
354 let text = "(union (intersection s0 (difference s2 (add 2 s3))) (remove 1 s1))".to_string();
355 let result = parse_set(text, &metadata, &functions, ®istry, ¶meters);
356 assert!(result.is_ok());
357 }
358
359 #[test]
360 fn parse_set_err() {
361 let metadata = generate_metadata();
362 let functions = dypdl::StateFunctions::default();
363 let registry = generate_registry();
364 let parameters = generate_parameters();
365 let text = "s0)".to_string();
366 let result = parse_set(text, &metadata, &functions, ®istry, ¶meters);
367 assert!(result.is_err());
368 }
369
370 #[test]
371 fn parse_integer_ok() {
372 let metadata = generate_metadata();
373 let functions = dypdl::StateFunctions::default();
374 let registry = generate_registry();
375 let parameters = generate_parameters();
376 let text = "n0".to_string();
377 let result = parse_integer(text, &metadata, &functions, ®istry, ¶meters);
378 assert!(result.is_ok());
379 }
380
381 #[test]
382 fn parse_integer_err() {
383 let metadata = generate_metadata();
384 let functions = dypdl::StateFunctions::default();
385 let registry = generate_registry();
386 let parameters = generate_parameters();
387 let text = "n0)".to_string();
388 let result = parse_integer(text, &metadata, &functions, ®istry, ¶meters);
389 assert!(result.is_err());
390 }
391
392 #[test]
393 fn parse_continuous_ok() {
394 let metadata = generate_metadata();
395 let functions = dypdl::StateFunctions::default();
396 let registry = generate_registry();
397 let parameters = generate_parameters();
398 let text = "c0".to_string();
399 let result = parse_continuous(text, &metadata, &functions, ®istry, ¶meters);
400 assert!(result.is_ok());
401 }
402
403 #[test]
404 fn parse_continuous_err() {
405 let metadata = generate_metadata();
406 let functions = dypdl::StateFunctions::default();
407 let registry = generate_registry();
408 let parameters = generate_parameters();
409 let text = "c0)".to_string();
410 let result = parse_continuous(text, &metadata, &functions, ®istry, ¶meters);
411 assert!(result.is_err());
412 }
413
414 #[test]
415 fn parse_element_ok() {
416 let metadata = generate_metadata();
417 let functions = dypdl::StateFunctions::default();
418 let registry = generate_registry();
419 let parameters = generate_parameters();
420 let text = "e0".to_string();
421 let result = parse_element(text, &metadata, &functions, ®istry, ¶meters);
422 assert!(result.is_ok());
423 }
424
425 #[test]
426 fn parse_element_err() {
427 let metadata = generate_metadata();
428 let functions = dypdl::StateFunctions::default();
429 let registry = generate_registry();
430 let parameters = generate_parameters();
431 let text = "e0)".to_string();
432 let result = parse_element(text, &metadata, &functions, ®istry, ¶meters);
433 assert!(result.is_err());
434 }
435
436 #[test]
437 fn parse_condition_ok() {
438 let metadata = generate_metadata();
439 let functions = dypdl::StateFunctions::default();
440 let registry = generate_registry();
441 let parameters = generate_parameters();
442 let text = "(not (and (and (and (> n0 2) (is_subset s0 s1)) (is_empty s0)) (or (< 1 n1) (is_in 2 s0))))"
443 .to_string();
444 let result = parse_condition(text, &metadata, &functions, ®istry, ¶meters);
445 assert!(result.is_ok());
446 }
447
448 #[test]
449 fn parse_condition_err() {
450 let metadata = generate_metadata();
451 let functions = dypdl::StateFunctions::default();
452 let registry = generate_registry();
453 let parameters = generate_parameters();
454 let text = "(is_empty s[0]))".to_string();
455 let result = parse_condition(text, &metadata, &functions, ®istry, ¶meters);
456 assert!(result.is_err());
457 }
458
459 #[test]
460 fn tokenize_text() {
461 let text = "(+ (- 5 (/ (sum f4 4 ~s2 e0 3) (max (f2 2 e1) n0))) (* r1 (min 3 |(union (intersection s0 (difference s2 (add 2 s3))) (remove 1 s1))|)))".to_string();
462 assert_eq!(
463 tokenize(text),
464 [
465 "(",
466 "+",
467 "(",
468 "-",
469 "5",
470 "(",
471 "/",
472 "(",
473 "sum",
474 "f4",
475 "4",
476 "~",
477 "s2",
478 "e0",
479 "3",
480 ")",
481 "(",
482 "max",
483 "(",
484 "f2",
485 "2",
486 "e1",
487 ")",
488 "n0",
489 ")",
490 ")",
491 ")",
492 "(",
493 "*",
494 "r1",
495 "(",
496 "min",
497 "3",
498 "|",
499 "(",
500 "union",
501 "(",
502 "intersection",
503 "s0",
504 "(",
505 "difference",
506 "s2",
507 "(",
508 "add",
509 "2",
510 "s3",
511 ")",
512 ")",
513 ")",
514 "(",
515 "remove",
516 "1",
517 "s1",
518 ")",
519 ")",
520 "|",
521 ")",
522 ")",
523 ")",
524 ]
525 );
526 }
527}