1use crate::util::INTERNAL_SYMBOL_PREFIX;
4use crate::*;
5use egglog_ast::generic_ast::*;
6use egglog_ast::span::{EgglogSpan, Span, SrcFile};
7use ordered_float::OrderedFloat;
8
9#[macro_export]
10macro_rules! span {
11 () => {{
12 use $crate::ast::{RustSpan, Span};
13 Span::Rust(std::sync::Arc::new(RustSpan {
14 file: file!(),
15 line: line!(),
16 column: column!(),
17 }))
18 }};
19}
20
21#[derive(Debug, Error)]
27pub struct ParseError(pub Span, pub String);
28
29impl std::fmt::Display for ParseError {
30 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
31 write!(f, "{}\nparse error: {}", self.0, self.1)
32 }
33}
34
35macro_rules! error {
36 ($span:expr, $($fmt:tt)*) => {
37 Err(ParseError($span, format!($($fmt)*)))
38 };
39}
40
41pub enum Sexp {
42 Literal(Literal, Span),
45 Atom(String, Span),
46 List(Vec<Sexp>, Span),
47}
48
49impl Sexp {
50 pub fn span(&self) -> Span {
51 match self {
52 Sexp::Literal(_, span) => span.clone(),
53 Sexp::Atom(_, span) => span.clone(),
54 Sexp::List(_, span) => span.clone(),
55 }
56 }
57
58 pub fn expect_uint<UInt: TryFrom<u64>>(&self, e: &'static str) -> Result<UInt, ParseError> {
59 if let Sexp::Literal(Literal::Int(x), _) = self
60 && *x >= 0
61 && let Ok(v) = (*x as u64).try_into()
62 {
63 return Ok(v);
64 }
65 error!(
66 self.span(),
67 "expected {e} to be a nonnegative integer literal"
68 )
69 }
70
71 pub fn expect_string(&self, e: &'static str) -> Result<String, ParseError> {
72 if let Sexp::Literal(Literal::String(x), _) = self {
73 return Ok(x.to_string());
74 }
75 error!(self.span(), "expected {e} to be a string literal")
76 }
77
78 pub fn expect_atom(&self, e: &'static str) -> Result<String, ParseError> {
79 if let Sexp::Atom(symbol, _) = self {
80 return Ok(symbol.clone());
81 }
82 error!(self.span(), "expected {e}")
83 }
84
85 pub fn expect_list(&self, e: &'static str) -> Result<&[Sexp], ParseError> {
86 if let Sexp::List(sexps, _) = self {
87 return Ok(sexps);
88 }
89 error!(self.span(), "expected {e}")
90 }
91
92 pub fn expect_call(&self, e: &'static str) -> Result<(String, &[Sexp], Span), ParseError> {
93 if let Sexp::List(sexps, span) = self
94 && let [Sexp::Atom(func, _), args @ ..] = sexps.as_slice()
95 {
96 return Ok((func.clone(), args, span.clone()));
97 }
98 error!(self.span(), "expected {e}")
99 }
100}
101
102fn map_fallible<T>(
104 slice: &[Sexp],
105 parser: &mut Parser,
106 func: impl Fn(&mut Parser, &Sexp) -> Result<T, ParseError>,
107) -> Result<Vec<T>, ParseError> {
108 slice
109 .iter()
110 .map(|sexp| func(parser, sexp))
111 .collect::<Result<_, _>>()
112}
113
114fn parse_container_rebuild_spec(sexp: &Sexp) -> Result<ContainerRebuildSpec, ParseError> {
117 let (head, items, span) = sexp.expect_call("container-rebuild spec")?;
118 if head != "container-rebuild-spec" {
119 return error!(span, "expected (container-rebuild-spec ...)");
120 }
121 let (prim, proof_prim) = match items {
122 [prim] => (prim, None),
123 [prim, proof_prim] => (
124 prim,
125 Some(proof_prim.expect_atom("container rebuild proof primitive name")?),
126 ),
127 _ => {
128 return error!(
129 span,
130 "container-rebuild-spec needs a primitive name and an optional proof primitive name"
131 );
132 }
133 };
134 Ok(ContainerRebuildSpec {
135 internal_rebuild_prim: prim.expect_atom("container rebuild primitive name")?,
136 internal_rebuild_proof_prim: proof_prim,
137 })
138}
139
140pub trait Macro<T>: Send + Sync {
141 fn name(&self) -> &str;
142 fn parse(&self, args: &[Sexp], span: Span, parser: &mut Parser) -> Result<T, ParseError>;
143}
144
145pub struct SimpleMacro<T, F: Fn(&[Sexp], Span, &mut Parser) -> Result<T, ParseError> + Send + Sync>(
146 String,
147 F,
148);
149
150impl<T, F> SimpleMacro<T, F>
151where
152 F: Fn(&[Sexp], Span, &mut Parser) -> Result<T, ParseError> + Send + Sync,
153{
154 pub fn new(head: &str, f: F) -> Self {
155 Self(head.to_owned(), f)
156 }
157}
158
159impl<T, F> Macro<T> for SimpleMacro<T, F>
160where
161 F: Fn(&[Sexp], Span, &mut Parser) -> Result<T, ParseError> + Send + Sync,
162{
163 fn name(&self) -> &str {
164 &self.0
165 }
166
167 fn parse(&self, args: &[Sexp], span: Span, parser: &mut Parser) -> Result<T, ParseError> {
168 self.1(args, span, parser)
169 }
170}
171
172#[derive(Clone)]
173pub struct Parser {
174 commands: HashMap<String, Arc<dyn Macro<Vec<Command>>>>,
175 actions: HashMap<String, Arc<dyn Macro<Vec<Action>>>>,
176 exprs: HashMap<String, Arc<dyn Macro<Expr>>>,
177 user_defined: HashSet<String>,
178 pub symbol_gen: SymbolGen,
179 pub ensure_no_reserved_symbols: bool,
180}
181
182impl Default for Parser {
183 fn default() -> Self {
184 Self {
185 commands: Default::default(),
186 actions: Default::default(),
187 exprs: Default::default(),
188 user_defined: Default::default(),
189 symbol_gen: SymbolGen::new(INTERNAL_SYMBOL_PREFIX.to_string()),
190 ensure_no_reserved_symbols: true,
191 }
192 }
193}
194
195impl Parser {
196 fn ensure_symbol_not_reserved(&self, symbol: &str, span: &Span) -> Result<(), ParseError> {
197 if self.symbol_gen.is_reserved(symbol) && self.ensure_no_reserved_symbols {
198 return error!(
199 span.clone(),
200 "symbols starting with '{}' are reserved for egglog internals",
201 self.symbol_gen.reserved_prefix()
202 );
203 }
204 Ok(())
205 }
206
207 pub fn get_program_from_string(
208 &mut self,
209 filename: Option<String>,
210 input: &str,
211 ) -> Result<Vec<Command>, ParseError> {
212 let sexps = all_sexps(SexpParser::new(filename, input))?;
213 let nested: Vec<Vec<_>> = map_fallible(&sexps, self, Self::parse_command)?;
214 Ok(nested.into_iter().flatten().collect())
215 }
216
217 pub fn get_expr_from_string(
219 &mut self,
220 filename: Option<String>,
221 input: &str,
222 ) -> Result<Expr, ParseError> {
223 let sexp = sexp(&mut SexpParser::new(filename, input))?;
224 self.parse_expr(&sexp)
225 }
226
227 pub fn get_schedule_from_string(
228 &mut self,
229 filename: Option<String>,
230 input: &str,
231 ) -> Result<Schedule, ParseError> {
232 let sexp = sexp(&mut SexpParser::new(filename, input))?;
233 self.parse_schedule(&sexp)
234 }
235
236 pub fn get_fact_from_string(
238 &mut self,
239 filename: Option<String>,
240 input: &str,
241 ) -> Result<Fact, ParseError> {
242 let sexp = sexp(&mut SexpParser::new(filename, input))?;
243 self.parse_fact(&sexp)
244 }
245
246 pub fn add_command_macro(&mut self, ma: Arc<dyn Macro<Vec<Command>>>) {
247 self.commands.insert(ma.name().to_owned(), ma);
248 }
249
250 pub fn add_action_macro(&mut self, ma: Arc<dyn Macro<Vec<Action>>>) {
251 self.actions.insert(ma.name().to_owned(), ma);
252 }
253
254 pub fn add_expr_macro(&mut self, ma: Arc<dyn Macro<Expr>>) {
255 self.exprs.insert(ma.name().to_owned(), ma);
256 }
257
258 pub(crate) fn add_user_defined(&mut self, name: String) -> Result<(), Error> {
259 if self.actions.contains_key(&name)
260 || self.exprs.contains_key(&name)
261 || self.commands.contains_key(&name)
262 {
263 return Err(Error::CommandAlreadyExists(name, span!()));
264 }
265 self.user_defined.insert(name);
266 Ok(())
267 }
268
269 pub fn parse_command(&mut self, sexp: &Sexp) -> Result<Vec<Command>, ParseError> {
270 let (head, tail, span) = sexp.expect_call("command")?;
271
272 if let Some(macr0) = self.commands.get(&head).cloned() {
273 return macr0.parse(tail, span, self);
274 }
275
276 if self.user_defined.contains(&head) {
278 let args = map_fallible(tail, self, Self::parse_expr)?;
279 return Ok(vec![Command::UserDefined(span, head, args)]);
280 }
281
282 Ok(match head.as_str() {
283 "sort" => {
284 match tail {
290 [name] => vec![Command::Sort {
291 span,
292 name: name.expect_atom("sort name")?,
293 presort_and_args: None,
294 uf: None,
295 proof_func: None,
296 container_rebuild: None,
297 proof_constructors: None,
298 unionable: true,
299 }],
300 [name, call @ Sexp::List(..), rest @ ..] => {
301 let (func, args, _) = call.expect_call("container sort declaration")?;
302 let mut proof_func = None;
306 let mut container_rebuild = None;
307 for (key, val) in self.parse_options(rest)? {
308 match (key, val) {
309 (":internal-proof-func", [pf]) => {
310 proof_func =
311 Some(pf.expect_atom("internal-proof-func function name")?);
312 }
313 (":internal-container-rebuild", [spec]) => {
314 container_rebuild = Some(parse_container_rebuild_spec(spec)?);
315 }
316 _ => {
317 return error!(
318 span,
319 "usage:\n(sort <name> (<container sort> <argument sort>*) [:internal-proof-func <name>] [:internal-container-rebuild <spec>])"
320 );
321 }
322 }
323 }
324 vec![Command::Sort {
325 span,
326 name: name.expect_atom("sort name")?,
327 presort_and_args: Some((
328 func,
329 map_fallible(args, self, Self::parse_expr)?,
330 )),
331 uf: None,
332 proof_func,
333 container_rebuild,
334 proof_constructors: None,
335 unionable: true,
336 }]
337 }
338 [name, rest @ ..] => {
339 let mut uf = None;
342 let mut proof_func = None;
343 let mut proof_constructors = None;
344 for (key, val) in self.parse_options(rest)? {
345 match (key, val) {
346 (":internal-uf", [uf_ctor]) => {
347 uf = Some((uf_ctor.expect_atom("uf constructor name")?, None));
348 }
349 (":internal-uf", [uf_ctor, uf_index]) => {
350 uf = Some((
351 uf_ctor.expect_atom("uf constructor name")?,
352 Some(uf_index.expect_atom("uf index function name")?),
353 ));
354 }
355 (":internal-proof-func", [pf]) => {
356 proof_func =
357 Some(pf.expect_atom("internal-proof-func function name")?);
358 }
359 (":internal-proof-names", [congr, trans, sym, normalize]) => {
360 proof_constructors = Some(ProofConstructorNames {
361 congr: congr.expect_atom("congr constructor")?,
362 trans: trans.expect_atom("trans constructor")?,
363 sym: sym.expect_atom("sym constructor")?,
364 normalize: normalize
365 .expect_atom("container-normalize constructor")?,
366 });
367 }
368 _ => {
369 return error!(
370 span,
371 "usages:\n(sort <name>)\n(sort <name> :internal-uf <uf-constructor> [<uf-index>])\n(sort <name> :internal-proof-func <internal-proof-func-name>)\n(sort <name> :internal-proof-names <congr> <trans> <sym> <normalize>)\n(sort <name> (<container sort> <argument sort>*))"
372 );
373 }
374 }
375 }
376 vec![Command::Sort {
377 span,
378 name: name.expect_atom("sort name")?,
379 presort_and_args: None,
380 uf,
381 proof_func,
382 container_rebuild: None,
383 proof_constructors,
384 unionable: true,
385 }]
386 }
387 _ => {
388 return error!(
389 span,
390 "usages:\n(sort <name>)\n(sort <name> (<container sort> <argument sort>*))"
391 );
392 }
393 }
394 }
395 "datatype" => match tail {
396 [name, variants @ ..] => vec![Command::Datatype {
397 span,
398 name: name.expect_atom("sort name")?,
399 variants: map_fallible(variants, self, Self::variant)?,
400 }],
401 _ => return error!(span, "usage: (datatype <name> <variant>*)"),
402 },
403 "datatype*" => vec![Command::Datatypes {
404 span,
405 datatypes: map_fallible(tail, self, Self::rec_datatype)?,
406 }],
407 "function" => match tail {
408 [name, inputs, output, rest @ ..] => {
409 let mut merge = None;
410 let mut hidden = false;
411 let mut let_binding = false;
412 let mut term_constructor = None;
413 let mut unextractable = false;
414 for (key, val) in self.parse_options(rest)? {
415 match (key, val) {
416 (":no-merge", []) => {
417 if merge.is_some() {
418 return error!(
419 span,
420 "conflicting merge options: :no-merge and :merge cannot both be specified"
421 );
422 }
423 merge = Some(None);
424 }
425 (":merge", [e]) => {
426 if merge.is_some() {
427 return error!(
428 span,
429 "conflicting merge options: :merge and :no-merge cannot both be specified"
430 );
431 }
432 merge = Some(Some(self.parse_expr(e)?));
433 }
434 (":internal-hidden", []) => hidden = true,
435 (":internal-let", []) => let_binding = true,
436 (":unextractable", []) => unextractable = true,
437 (":internal-term-constructor", [tc]) => {
438 term_constructor = Some(tc.expect_atom("term constructor name")?)
439 }
440 _ => return error!(span, "could not parse function options"),
441 }
442 }
443 let merge = match merge {
444 Some(m) => m,
445 None => {
446 return error!(
447 span,
448 "functions are required to specify merge behaviour"
449 );
450 }
451 };
452 vec![Command::Function {
453 name: name.expect_atom("function name")?,
454 schema: self.parse_schema(inputs, output)?,
455 merge,
456 hidden,
457 let_binding,
458 term_constructor,
459 unextractable,
460 span,
461 }]
462 }
463 _ => {
464 let a = "(function <name> (<input sort>*) <output sort> :merge <expr>)";
465 let b = "(function <name> (<input sort>*) <output sort> :no-merge)";
466 return error!(span, "usages:\n{a}\n{b}");
467 }
468 },
469 "constructor" => {
470 match tail {
476 [name, inputs, output, rest @ ..] => {
477 let mut cost = None;
478 let mut unextractable = false;
479 let mut hidden = false;
480 let mut let_binding = false;
481 for (key, val) in self.parse_options(rest)? {
482 match (key, val) {
483 (":unextractable", []) => unextractable = true,
484 (":internal-hidden", []) => hidden = true,
485 (":internal-let", []) => let_binding = true,
486 (":cost", [c]) => cost = Some(c.expect_uint("cost")?),
487 _ => return error!(span, "could not parse constructor options"),
488 }
489 }
490
491 vec![Command::Constructor {
492 span,
493 name: name.expect_atom("constructor name")?,
494 schema: self.parse_schema(inputs, output)?,
495 cost,
496 unextractable,
497 hidden,
498 let_binding,
499 term_constructor: None,
500 }]
501 }
502 _ => {
503 let a = "(constructor <name> (<input sort>*) <output sort>)";
504 let b = "(constructor <name> (<input sort>*) <output sort> :cost <cost>)";
505 let c = "(constructor <name> (<input sort>*) <output sort> :unextractable)";
506 return error!(span, "usages:\n{a}\n{b}\n{c}");
507 }
508 }
509 }
510 "relation" => match tail {
511 [name, inputs] => vec![Command::Relation {
512 span,
513 name: name.expect_atom("relation name")?,
514 inputs: map_fallible(inputs.expect_list("input sorts")?, self, |_, sexp| {
515 sexp.expect_atom("input sort")
516 })?,
517 }],
518 _ => return error!(span, "usage: (relation <name> (<input sort>*))"),
519 },
520 "ruleset" => match tail {
521 [name] => vec![Command::AddRuleset(span, name.expect_atom("ruleset name")?)],
522 _ => return error!(span, "usage: (ruleset <name>)"),
523 },
524 "unstable-combined-ruleset" => match tail {
525 [name, subrulesets @ ..] => vec![Command::UnstableCombinedRuleset(
526 span,
527 name.expect_atom("combined ruleset name")?,
528 map_fallible(subrulesets, self, |_, sexp| {
529 sexp.expect_atom("subruleset name")
530 })?,
531 )],
532 _ => {
533 return error!(
534 span,
535 "usage: (unstable-combined-ruleset <name> <child ruleset>*)"
536 );
537 }
538 },
539 "rule" => match tail {
540 [lhs, rhs, rest @ ..] => {
541 let body =
542 map_fallible(lhs.expect_list("rule query")?, self, Self::parse_fact)?;
543 let head: Vec<Vec<_>> =
544 map_fallible(rhs.expect_list("rule actions")?, self, Self::parse_action)?;
545 let head = GenericActions(head.into_iter().flatten().collect());
546
547 let mut ruleset = String::new();
548 let mut name = String::new();
549 let mut eval_mode: Option<RuleEvalMode> = None;
552 let mut no_decomp = false;
553 let mut include_subsumed = false;
554 for option in self.parse_options(rest)? {
555 match option {
556 (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?,
557 (":name", [s]) => name = s.expect_string("rule name")?,
558 (":naive", []) | (":unsafe-seminaive", []) => {
559 let mode = if option.0 == ":naive" {
560 RuleEvalMode::Naive
561 } else {
562 RuleEvalMode::UnsafeSeminaive
563 };
564 if eval_mode.is_some() {
565 return error!(
566 span,
567 ":naive and :unsafe-seminaive are mutually exclusive"
568 );
569 }
570 eval_mode = Some(mode);
571 }
572 (":no-decomp", []) => no_decomp = true,
573 (":internal-include-subsumed", []) => include_subsumed = true,
574 _ => return error!(span, "could not parse rule option"),
575 }
576 }
577
578 vec![Command::Rule {
579 rule: Rule {
580 span,
581 head,
582 body,
583 name,
584 ruleset,
585 eval_mode: eval_mode.unwrap_or_default(),
586 no_decomp,
587 include_subsumed,
588 },
589 }]
590 }
591 _ => return error!(span, "usage: (rule (<fact>*) (<action>*) <option>*)"),
592 },
593 "rewrite" => match tail {
594 [lhs, rhs, rest @ ..] => {
595 let lhs = self.parse_expr(lhs)?;
596 let rhs = self.parse_expr(rhs)?;
597
598 let mut ruleset = String::new();
599 let mut conditions = Vec::new();
600 let mut subsume = false;
601 let mut name = String::new();
602 for option in self.parse_options(rest)? {
603 match option {
604 (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?,
605 (":subsume", []) => subsume = true,
606 (":when", [w]) => {
607 conditions = map_fallible(
608 w.expect_list("rewrite conditions")?,
609 self,
610 Self::parse_fact,
611 )?
612 }
613 (":name", [s]) => name = s.expect_string("rule name")?,
614 _ => return error!(span, "could not parse rewrite options"),
615 }
616 }
617
618 vec![Command::Rewrite(
619 ruleset,
620 Rewrite {
621 span,
622 lhs,
623 rhs,
624 conditions,
625 name,
626 },
627 subsume,
628 )]
629 }
630 _ => return error!(span, "usage: (rewrite <expr> <expr> <option>*)"),
631 },
632 "birewrite" => match tail {
633 [lhs, rhs, rest @ ..] => {
634 let lhs = self.parse_expr(lhs)?;
635 let rhs = self.parse_expr(rhs)?;
636
637 let mut ruleset = String::new();
638 let mut conditions = Vec::new();
639 let mut name = String::new();
640 for option in self.parse_options(rest)? {
641 match option {
642 (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?,
643 (":when", [w]) => {
644 conditions = map_fallible(
645 w.expect_list("rewrite conditions")?,
646 self,
647 Self::parse_fact,
648 )?
649 }
650 (":name", [s]) => name = s.expect_string("rule name")?,
651 _ => return error!(span, "could not parse birewrite options"),
652 }
653 }
654
655 vec![Command::BiRewrite(
656 ruleset,
657 Rewrite {
658 span,
659 lhs,
660 rhs,
661 conditions,
662 name,
663 },
664 )]
665 }
666 _ => return error!(span, "usage: (birewrite <expr> <expr> <option>*)"),
667 },
668 "run" => {
669 if tail.is_empty() {
670 return error!(span, "usage: (run <ruleset>? <uint> <:until (<fact>*)>?)");
671 }
672
673 let has_ruleset = tail.len() >= 2 && tail[1].expect_uint::<u32>("").is_ok();
674
675 let (ruleset, limit, rest) = if has_ruleset {
676 (
677 tail[0].expect_atom("ruleset name")?,
678 tail[1].expect_uint("number of iterations")?,
679 &tail[2..],
680 )
681 } else {
682 (
683 String::new(),
684 tail[0].expect_uint("number of iterations")?,
685 &tail[1..],
686 )
687 };
688
689 let until = match self.parse_options(rest)?.as_slice() {
690 [] => None,
691 [(":until", facts)] => Some(map_fallible(facts, self, Self::parse_fact)?),
692 _ => return error!(span, "could not parse run options"),
693 };
694
695 vec![Command::RunSchedule(Schedule::Repeat(
696 span.clone(),
697 limit,
698 Box::new(Schedule::Run(span, RunConfig { ruleset, until })),
699 ))]
700 }
701 "run-schedule" => vec![Command::RunSchedule(Schedule::Sequence(
702 span,
703 map_fallible(tail, self, Self::parse_schedule)?,
704 ))],
705 "extract" => match tail {
706 [e] => vec![Command::Extract(
707 span.clone(),
708 self.parse_expr(e)?,
709 Expr::Lit(span, Literal::Int(0)),
710 )],
711 [e, v] => vec![Command::Extract(
712 span,
713 self.parse_expr(e)?,
714 self.parse_expr(v)?,
715 )],
716 _ => return error!(span, "usage: (extract <expr> <number of variants>?)"),
717 },
718 "check" => vec![Command::Check(
719 span,
720 map_fallible(tail, self, Self::parse_fact)?,
721 )],
722 "prove" => vec![Command::Prove(
723 span,
724 map_fallible(tail, self, Self::parse_fact)?,
725 )],
726 "prove-exists" => match tail {
727 [constructor] => vec![Command::ProveExists(
728 span,
729 constructor.expect_atom("constructor name")?,
730 )],
731 _ => return error!(span, "usage: (prove-exists <constructor>)"),
732 },
733 "push" => match tail {
734 [] => vec![Command::Push(1)],
735 [n] => vec![Command::Push(n.expect_uint("number of times to push")?)],
736 _ => return error!(span, "usage: (push <uint>?)"),
737 },
738 "pop" => match tail {
739 [] => vec![Command::Pop(span, 1)],
740 [n] => vec![Command::Pop(span, n.expect_uint("number of times to pop")?)],
741 _ => return error!(span, "usage: (pop <uint>?)"),
742 },
743 "print-stats" => match tail {
744 [] => vec![Command::PrintOverallStatistics(span, None)],
745 [Sexp::Atom(o, _), file] if o == ":file" => vec![Command::PrintOverallStatistics(
746 span,
747 Some(file.expect_string("file name")?),
748 )],
749 _ => {
750 return error!(
751 span,
752 "usages: (print-stats)\n(print-stats :file \"<filename>\")"
753 );
754 }
755 },
756 "print-function" => match tail {
757 [name] => vec![Command::PrintFunction(
758 span,
759 name.expect_atom("table name")?,
760 None,
761 None,
762 PrintFunctionMode::Default,
763 )],
764 [name, rest @ ..] => {
765 let rows: Option<usize> = rest[0].expect_uint("number of rows").ok();
766 let rest = if rows.is_some() { &rest[1..] } else { rest };
767
768 let mut file = None;
769 let mut mode = PrintFunctionMode::Default;
770 for opt in self.parse_options(rest)? {
771 match opt {
772 (":file", [file_name]) => {
773 file = Some(file_name.expect_string("file name")?);
774 }
775 (":mode", [Sexp::Atom(mode_str, _)]) => {
776 mode = match mode_str.as_str() {
777 "default" => PrintFunctionMode::Default,
778 "csv" => PrintFunctionMode::CSV,
779 _ => {
780 return error!(
781 span,
782 "Unknown print-function mode. Supported modes are `default` and `csv`."
783 );
784 }
785 };
786 }
787 _ => {
788 return error!(
789 span,
790 "Unknown option to print-function. Supported options are `:mode csv|default` and `:file \"<filename>\"`."
791 );
792 }
793 }
794 }
795 vec![Command::PrintFunction(
796 span,
797 name.expect_atom("table name")?,
798 rows,
799 file,
800 mode,
801 )]
802 }
803 _ => {
804 return error!(
805 span,
806 "usage: (print-function <table name> <number of rows>? <option>*)"
807 );
808 }
809 },
810 "print-size" => match tail {
811 [] => vec![Command::PrintSize(span, None)],
812 [name] => vec![Command::PrintSize(
813 span,
814 Some(name.expect_atom("table name")?),
815 )],
816 _ => return error!(span, "usage: (print-size <table name>?)"),
817 },
818 "input" => match tail {
819 [name, file] => vec![Command::Input {
820 span,
821 name: name.expect_atom("table name")?,
822 file: file.expect_string("file name")?,
823 }],
824 _ => return error!(span, "usage: (input <table name> \"<file name>\")"),
825 },
826 "output" => match tail {
827 [file, exprs @ ..] => vec![Command::Output {
828 span,
829 file: file.expect_string("file name")?,
830 exprs: map_fallible(exprs, self, Self::parse_expr)?,
831 }],
832 _ => return error!(span, "usage: (output <file name> <expr>+)"),
833 },
834 "include" => match tail {
835 [file] => vec![Command::Include(span, file.expect_string("file name")?)],
836 _ => return error!(span, "usage: (include <file name>)"),
837 },
838 "fail" => match tail {
839 [subcommand] => {
840 let mut cs = self.parse_command(subcommand)?;
841 if cs.len() != 1 {
842 todo!("extend Fail to work with multiple parsed commands")
843 }
844 vec![Command::Fail(span, Box::new(cs.remove(0)))]
845 }
846 _ => return error!(span, "usage: (fail <command>)"),
847 },
848 _ => self
849 .parse_action(sexp)?
850 .into_iter()
851 .map(Command::Action)
852 .collect(),
853 })
854 }
855
856 pub fn parse_schedule(&mut self, sexp: &Sexp) -> Result<Schedule, ParseError> {
857 if let Sexp::Atom(ruleset, span) = sexp {
858 return Ok(Schedule::Run(
859 span.clone(),
860 RunConfig {
861 ruleset: ruleset.clone(),
862 until: None,
863 },
864 ));
865 }
866
867 let (head, tail, span) = sexp.expect_call("schedule")?;
868
869 Ok(match head.as_str() {
870 "saturate" => Schedule::Saturate(
871 span.clone(),
872 Box::new(Schedule::Sequence(
873 span,
874 map_fallible(tail, self, Self::parse_schedule)?,
875 )),
876 ),
877 "seq" => Schedule::Sequence(span, map_fallible(tail, self, Self::parse_schedule)?),
878 "repeat" => match tail {
879 [limit, tail @ ..] => Schedule::Repeat(
880 span.clone(),
881 limit.expect_uint("number of iterations")?,
882 Box::new(Schedule::Sequence(
883 span,
884 map_fallible(tail, self, Self::parse_schedule)?,
885 )),
886 ),
887 _ => return error!(span, "usage: (repeat <number of iterations> <schedule>*)"),
888 },
889 "run" => {
890 let has_ruleset = match tail.first() {
891 None => false,
892 Some(Sexp::Atom(o, _)) if *o == ":until" => false,
893 _ => true,
894 };
895
896 let (ruleset, rest) = if has_ruleset {
897 (tail[0].expect_atom("ruleset name")?, &tail[1..])
898 } else {
899 (String::new(), tail)
900 };
901
902 let until = match self.parse_options(rest)?.as_slice() {
903 [] => None,
904 [(":until", facts)] => Some(map_fallible(facts, self, Self::parse_fact)?),
905 _ => return error!(span, "could not parse run options"),
906 };
907
908 Schedule::Run(span, RunConfig { ruleset, until })
909 }
910 _ => return error!(span, "expected either saturate, seq, repeat, or run"),
911 })
912 }
913
914 pub fn parse_action(&mut self, sexp: &Sexp) -> Result<Vec<Action>, ParseError> {
915 let (head, tail, span) = sexp.expect_call("action")?;
916
917 if let Some(func) = self.actions.get(&head).cloned() {
918 return func.parse(tail, span, self);
919 }
920
921 Ok(match head.as_str() {
922 "let" => match tail {
923 [name, value] => {
924 let binding_span = name.span();
925 let binding = name.expect_atom("binding name")?;
926 self.ensure_symbol_not_reserved(&binding, &binding_span)?;
927 vec![Action::Let(span, binding, self.parse_expr(value)?)]
928 }
929 _ => return error!(span, "usage: (let <name> <expr>)"),
930 },
931 "set" => match tail {
932 [call, value] => {
933 let (func, args, _) = call.expect_call("table lookup")?;
934 let args = map_fallible(args, self, Self::parse_expr)?;
935 let value = self.parse_expr(value)?;
936 vec![Action::Set(span, func, args, value)]
937 }
938 _ => return error!(span, "usage: (set (<table name> <expr>*) <expr>)"),
939 },
940 "delete" => match tail {
941 [call] => {
942 let (func, args, _) = call.expect_call("table lookup")?;
943 let args = map_fallible(args, self, Self::parse_expr)?;
944 vec![Action::Change(span, Change::Delete, func, args)]
945 }
946 _ => return error!(span, "usage: (delete (<table name> <expr>*))"),
947 },
948 "subsume" => match tail {
949 [call] => {
950 let (func, args, _) = call.expect_call("table lookup")?;
951 let args = map_fallible(args, self, Self::parse_expr)?;
952 vec![Action::Change(span, Change::Subsume, func, args)]
953 }
954 _ => return error!(span, "usage: (subsume (<table name> <expr>*))"),
955 },
956 "union" => match tail {
957 [e1, e2] => vec![Action::Union(
958 span,
959 self.parse_expr(e1)?,
960 self.parse_expr(e2)?,
961 )],
962 _ => return error!(span, "usage: (union <expr> <expr>)"),
963 },
964 "panic" => match tail {
965 [message] => vec![Action::Panic(span, message.expect_string("error message")?)],
966 _ => return error!(span, "usage: (panic <string>)"),
967 },
968 _ => vec![Action::Expr(span, self.parse_expr(sexp)?)],
969 })
970 }
971
972 pub fn parse_fact(&mut self, sexp: &Sexp) -> Result<Fact, ParseError> {
973 let (head, tail, span) = sexp.expect_call("fact")?;
974
975 Ok(match head.as_str() {
976 "=" => match tail {
977 [e1, e2] => Fact::Eq(span, self.parse_expr(e1)?, self.parse_expr(e2)?),
978 _ => return error!(span, "usage: (= <expr> <expr>)"),
979 },
980 _ => Fact::Fact(self.parse_expr(sexp)?),
981 })
982 }
983
984 pub fn parse_expr(&mut self, sexp: &Sexp) -> Result<Expr, ParseError> {
985 Ok(match sexp {
986 Sexp::Literal(literal, span) => Expr::Lit(span.clone(), literal.clone()),
987 Sexp::Atom(symbol, span) => Expr::Var(
988 span.clone(),
989 if *symbol == "_" {
990 self.symbol_gen.fresh(symbol)
991 } else {
992 self.ensure_symbol_not_reserved(symbol, span)?;
993 symbol.clone()
994 },
995 ),
996 Sexp::List(list, span) => match list.as_slice() {
997 [] => Expr::Lit(span.clone(), Literal::Unit),
998 _ => {
999 let (head, tail, span) = sexp.expect_call("call expression")?;
1000
1001 if let Some(func) = self.exprs.get(&head).cloned() {
1002 return func.parse(tail, span, self);
1003 }
1004
1005 Expr::Call(
1006 span.clone(),
1007 head,
1008 map_fallible(tail, self, Self::parse_expr)?,
1009 )
1010 }
1011 },
1012 })
1013 }
1014
1015 pub fn rec_datatype(
1016 &mut self,
1017 sexp: &Sexp,
1018 ) -> Result<(Span, String, Subdatatypes), ParseError> {
1019 let (head, tail, span) = sexp.expect_call("datatype")?;
1020
1021 Ok(match head.as_str() {
1022 "sort" => match tail {
1023 [name, call] => {
1024 let name = name.expect_atom("sort name")?;
1025 let (func, args, _) = call.expect_call("container sort declaration")?;
1026 let args = map_fallible(args, self, Self::parse_expr)?;
1027 (span, name, Subdatatypes::NewSort(func, args))
1028 }
1029 _ => {
1030 return error!(
1031 span,
1032 "usage: (sort <name> (<container sort> <argument sort>*))"
1033 );
1034 }
1035 },
1036 _ => {
1037 let variants = map_fallible(tail, self, Self::variant)?;
1038 (span, head, Subdatatypes::Variants(variants))
1039 }
1040 })
1041 }
1042
1043 pub fn variant(&mut self, sexp: &Sexp) -> Result<Variant, ParseError> {
1044 let (name, tail, span) = sexp.expect_call("datatype variant")?;
1045
1046 let (types, cost, unextractable) = match tail {
1047 [types @ .., Sexp::Atom(o, _)] if *o == ":unextractable" => (types, None, true),
1048 [types @ .., Sexp::Atom(o, _), c] if *o == ":cost" => {
1049 (types, Some(c.expect_uint("cost")?), false)
1050 }
1051 types => (types, None, false),
1052 };
1053
1054 Ok(Variant {
1055 span,
1056 name,
1057 types: map_fallible(types, self, |_, sexp| {
1058 sexp.expect_atom("variant argument type")
1059 })?,
1060 cost,
1061 unextractable,
1062 })
1063 }
1064
1065 pub fn parse_options<'a>(
1067 &self,
1068 sexps: &'a [Sexp],
1069 ) -> Result<Vec<(&'a str, &'a [Sexp])>, ParseError> {
1070 fn option_name(sexp: &Sexp) -> Option<&str> {
1071 if let Sexp::Atom(s, _) = sexp
1072 && let Some(':') = s.chars().next()
1073 {
1074 return Some(s);
1075 }
1076 None
1077 }
1078
1079 let mut out = Vec::new();
1080 let mut i = 0;
1081 while i < sexps.len() {
1082 let Some(key) = option_name(&sexps[i]) else {
1083 return error!(sexps[i].span(), "option key must start with ':'");
1084 };
1085 i += 1;
1086
1087 let start = i;
1088 while i < sexps.len() && option_name(&sexps[i]).is_none() {
1089 i += 1;
1090 }
1091 out.push((key, &sexps[start..i]));
1092 }
1093 Ok(out)
1094 }
1095
1096 pub fn parse_schema(&self, input: &Sexp, output: &Sexp) -> Result<Schema, ParseError> {
1097 Ok(Schema {
1098 input: input
1099 .expect_list("input sorts")?
1100 .iter()
1101 .map(|sexp| sexp.expect_atom("input sort"))
1102 .collect::<Result<_, _>>()?,
1103 output: output.expect_atom("output sort")?,
1104 })
1105 }
1106}
1107
1108#[derive(Clone, Debug)]
1109pub(crate) struct SexpParser {
1110 source: Arc<SrcFile>,
1111 index: usize,
1112}
1113
1114impl SexpParser {
1115 pub(crate) fn new(name: Option<String>, contents: &str) -> SexpParser {
1116 SexpParser {
1117 source: Arc::new(SrcFile {
1118 name,
1119 contents: contents.to_string(),
1120 }),
1121 index: 0,
1122 }
1123 }
1124
1125 fn current_char(&self) -> Option<char> {
1126 self.source.contents[self.index..].chars().next()
1127 }
1128
1129 fn advance_char(&mut self) {
1130 assert!(self.index < self.source.contents.len());
1131 loop {
1132 self.index += 1;
1133 if self.source.contents.is_char_boundary(self.index) {
1134 break;
1135 }
1136 }
1137 }
1138
1139 fn advance_past_whitespace(&mut self) {
1140 let mut in_comment = false;
1141 loop {
1142 match self.current_char() {
1143 None => break,
1144 Some(';') => in_comment = true,
1145 Some('\n') => in_comment = false,
1146 Some(c) if c.is_whitespace() => {}
1147 Some(_) if in_comment => {}
1148 Some(_) => break,
1149 }
1150 self.advance_char();
1151 }
1152 }
1153
1154 fn is_at_end(&self) -> bool {
1155 self.index == self.source.contents.len()
1156 }
1157
1158 fn next(&mut self) -> Result<(Token, EgglogSpan), ParseError> {
1159 self.advance_past_whitespace();
1160 let mut span = EgglogSpan {
1161 file: self.source.clone(),
1162 i: self.index,
1163 j: self.index,
1164 };
1165
1166 let Some(c) = self.current_char() else {
1167 return error!(s(span), "unexpected end of file");
1168 };
1169 self.advance_char();
1170
1171 let token = match c {
1172 '(' => Token::Open,
1173 ')' => Token::Close,
1174 '"' => {
1175 let mut in_escape = false;
1176 let mut string = String::new();
1177
1178 loop {
1179 span.j = self.index;
1180 match self.current_char() {
1181 None => return error!(s(span), "string is missing end quote"),
1182 Some('"') if !in_escape => break,
1183 Some('\\') if !in_escape => in_escape = true,
1184 Some(c) => {
1185 string.push(match (in_escape, c) {
1186 (false, c) => c,
1187 (true, 'n') => '\n',
1188 (true, 't') => '\t',
1189 (true, '\\') => '\\',
1190 (true, '\"') => '\"',
1191 (true, c) => {
1192 return error!(s(span), "unrecognized escape character {c}");
1193 }
1194 });
1195 in_escape = false;
1196 }
1197 }
1198 self.advance_char();
1199 }
1200 self.advance_char();
1201
1202 Token::String(string)
1203 }
1204 _ => {
1205 loop {
1206 match self.current_char() {
1207 Some(c) if c.is_whitespace() => break,
1208 Some(';' | '(' | ')') => break,
1209 None => break,
1210 Some(_) => self.advance_char(),
1211 }
1212 }
1213 Token::Other
1214 }
1215 };
1216
1217 span.j = self.index;
1218 self.advance_past_whitespace();
1219
1220 Ok((token, span))
1221 }
1222}
1223
1224fn s(span: EgglogSpan) -> Span {
1225 Span::Egglog(Arc::new(span))
1226}
1227
1228enum Token {
1229 Open,
1230 Close,
1231 String(String),
1232 Other,
1233}
1234
1235fn sexp(ctx: &mut SexpParser) -> Result<Sexp, ParseError> {
1236 let mut stack: Vec<(EgglogSpan, Vec<Sexp>)> = vec![];
1237
1238 loop {
1239 let (token, span) = ctx.next()?;
1240
1241 let sexp = match token {
1242 Token::Open => {
1243 stack.push((span, vec![]));
1244 continue;
1245 }
1246 Token::Close => {
1247 if stack.is_empty() {
1248 return error!(s(span), "unexpected `)`");
1249 }
1250 let (mut list_span, list) = stack.pop().unwrap();
1251 list_span.j = span.j;
1252 Sexp::List(list, s(list_span))
1253 }
1254 Token::String(sym) => Sexp::Literal(Literal::String(sym), s(span)),
1255 Token::Other => {
1256 let span = s(span);
1257 let s = span.string();
1258
1259 if s == "true" {
1260 Sexp::Literal(Literal::Bool(true), span)
1261 } else if s == "false" {
1262 Sexp::Literal(Literal::Bool(false), span)
1263 } else if let Ok(int) = s.parse::<i64>() {
1264 Sexp::Literal(Literal::Int(int), span)
1265 } else if s == "NaN" {
1266 Sexp::Literal(Literal::Float(OrderedFloat(f64::NAN)), span)
1267 } else if s == "inf" {
1268 Sexp::Literal(Literal::Float(OrderedFloat(f64::INFINITY)), span)
1269 } else if s == "-inf" {
1270 Sexp::Literal(Literal::Float(OrderedFloat(f64::NEG_INFINITY)), span)
1271 } else if let Ok(float) = s.parse::<f64>() {
1272 if float.is_finite() {
1273 Sexp::Literal(Literal::Float(OrderedFloat(float)), span)
1274 } else {
1275 Sexp::Atom(s.into(), span)
1276 }
1277 } else {
1278 Sexp::Atom(s.into(), span)
1279 }
1280 }
1281 };
1282
1283 if stack.is_empty() {
1284 return Ok(sexp);
1285 } else {
1286 stack.last_mut().unwrap().1.push(sexp);
1287 }
1288 }
1289}
1290
1291pub(crate) fn all_sexps(mut ctx: SexpParser) -> Result<Vec<Sexp>, ParseError> {
1292 let mut sexps = Vec::new();
1293 ctx.advance_past_whitespace();
1294 while !ctx.is_at_end() {
1295 sexps.push(sexp(&mut ctx)?);
1296 ctx.advance_past_whitespace();
1297 }
1298 Ok(sexps)
1299}
1300
1301#[cfg(test)]
1302mod tests {
1303 use super::*;
1304
1305 #[test]
1306 fn test_parser_display_roundtrip() {
1307 let s = r#"(f (g a 3) 4.0 (H "hello"))"#;
1308 let e = Parser::default().get_expr_from_string(None, s).unwrap();
1309 assert_eq!(format!("{e}"), s);
1310 }
1311
1312 #[test]
1313 #[rustfmt::skip]
1314 fn rust_span_display() {
1315 let actual = format!("{}", span!()).replace('\\', "/");
1316 assert!(actual.starts_with("At "));
1317 assert!(actual.contains(":"));
1318 assert!(actual.ends_with("src/ast/parse.rs"));
1319 }
1320
1321 #[test]
1322 fn test_parser_macros() {
1323 let mut parser = Parser::default();
1324 let y = "xxxx";
1325 parser.add_expr_macro(Arc::new(SimpleMacro::new("qqqq", |tail, span, macros| {
1326 Ok(Expr::Call(
1327 span,
1328 y.into(),
1329 map_fallible(tail, macros, Parser::parse_expr)?,
1330 ))
1331 })));
1332 let s = r#"(f (qqqq a 3) 4.0 (H "hello"))"#;
1333 let t = r#"(f (xxxx a 3) 4.0 (H "hello"))"#;
1334 let e = parser.get_expr_from_string(None, s).unwrap();
1335 assert_eq!(format!("{e}"), t);
1336 }
1337}