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 Span::Rust(std::sync::Arc::new(RustSpan {
13 file: file!(),
14 line: line!(),
15 column: column!(),
16 }))
17 };
18}
19
20#[derive(Debug, Error)]
26pub struct ParseError(pub Span, pub String);
27
28impl std::fmt::Display for ParseError {
29 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
30 write!(f, "{}\nparse error: {}", self.0, self.1)
31 }
32}
33
34macro_rules! error {
35 ($span:expr, $($fmt:tt)*) => {
36 Err(ParseError($span, format!($($fmt)*)))
37 };
38}
39
40pub enum Sexp {
41 Literal(Literal, Span),
44 Atom(String, Span),
45 List(Vec<Sexp>, Span),
46}
47
48impl Sexp {
49 pub fn span(&self) -> Span {
50 match self {
51 Sexp::Literal(_, span) => span.clone(),
52 Sexp::Atom(_, span) => span.clone(),
53 Sexp::List(_, span) => span.clone(),
54 }
55 }
56
57 pub fn expect_uint<UInt: TryFrom<u64>>(&self, e: &'static str) -> Result<UInt, ParseError> {
58 if let Sexp::Literal(Literal::Int(x), _) = self {
59 if *x >= 0 {
60 if let Ok(v) = (*x as u64).try_into() {
61 return Ok(v);
62 }
63 }
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 if let [Sexp::Atom(func, _), args @ ..] = sexps.as_slice() {
95 return Ok((func.clone(), args, span.clone()));
96 }
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
114pub trait Macro<T>: Send + Sync {
115 fn name(&self) -> &str;
116 fn parse(&self, args: &[Sexp], span: Span, parser: &mut Parser) -> Result<T, ParseError>;
117}
118
119pub struct SimpleMacro<T, F: Fn(&[Sexp], Span, &mut Parser) -> Result<T, ParseError> + Send + Sync>(
120 String,
121 F,
122);
123
124impl<T, F> SimpleMacro<T, F>
125where
126 F: Fn(&[Sexp], Span, &mut Parser) -> Result<T, ParseError> + Send + Sync,
127{
128 pub fn new(head: &str, f: F) -> Self {
129 Self(head.to_owned(), f)
130 }
131}
132
133impl<T, F> Macro<T> for SimpleMacro<T, F>
134where
135 F: Fn(&[Sexp], Span, &mut Parser) -> Result<T, ParseError> + Send + Sync,
136{
137 fn name(&self) -> &str {
138 &self.0
139 }
140
141 fn parse(&self, args: &[Sexp], span: Span, parser: &mut Parser) -> Result<T, ParseError> {
142 self.1(args, span, parser)
143 }
144}
145
146#[derive(Clone)]
147pub struct Parser {
148 commands: HashMap<String, Arc<dyn Macro<Vec<Command>>>>,
149 actions: HashMap<String, Arc<dyn Macro<Vec<Action>>>>,
150 exprs: HashMap<String, Arc<dyn Macro<Expr>>>,
151 user_defined: HashSet<String>,
152 pub symbol_gen: SymbolGen,
153}
154
155impl Default for Parser {
156 fn default() -> Self {
157 Self {
158 commands: Default::default(),
159 actions: Default::default(),
160 exprs: Default::default(),
161 user_defined: Default::default(),
162 symbol_gen: SymbolGen::new(INTERNAL_SYMBOL_PREFIX.to_string()),
163 }
164 }
165}
166
167impl Parser {
168 fn ensure_symbol_not_reserved(&self, symbol: &str, span: &Span) -> Result<(), ParseError> {
169 if self.symbol_gen.is_reserved(symbol) {
170 return error!(
171 span.clone(),
172 "symbols starting with '{}' are reserved for egglog internals",
173 self.symbol_gen.reserved_prefix()
174 );
175 }
176 Ok(())
177 }
178
179 pub fn get_program_from_string(
180 &mut self,
181 filename: Option<String>,
182 input: &str,
183 ) -> Result<Vec<Command>, ParseError> {
184 let sexps = all_sexps(SexpParser::new(filename, input))?;
185 let nested: Vec<Vec<_>> = map_fallible(&sexps, self, Self::parse_command)?;
186 Ok(nested.into_iter().flatten().collect())
187 }
188
189 pub fn get_expr_from_string(
191 &mut self,
192 filename: Option<String>,
193 input: &str,
194 ) -> Result<Expr, ParseError> {
195 let sexp = sexp(&mut SexpParser::new(filename, input))?;
196 self.parse_expr(&sexp)
197 }
198
199 pub fn add_command_macro(&mut self, ma: Arc<dyn Macro<Vec<Command>>>) {
200 self.commands.insert(ma.name().to_owned(), ma);
201 }
202
203 pub fn add_action_macro(&mut self, ma: Arc<dyn Macro<Vec<Action>>>) {
204 self.actions.insert(ma.name().to_owned(), ma);
205 }
206
207 pub fn add_expr_macro(&mut self, ma: Arc<dyn Macro<Expr>>) {
208 self.exprs.insert(ma.name().to_owned(), ma);
209 }
210
211 pub(crate) fn add_user_defined(&mut self, name: String) -> Result<(), Error> {
212 if self.actions.contains_key(&name)
213 || self.exprs.contains_key(&name)
214 || self.commands.contains_key(&name)
215 {
216 use egglog_ast::span::{RustSpan, Span};
217 return Err(Error::CommandAlreadyExists(name, span!()));
218 }
219 self.user_defined.insert(name);
220 Ok(())
221 }
222
223 pub fn parse_command(&mut self, sexp: &Sexp) -> Result<Vec<Command>, ParseError> {
224 let (head, tail, span) = sexp.expect_call("command")?;
225
226 if let Some(macr0) = self.commands.get(&head).cloned() {
227 return macr0.parse(tail, span, self);
228 }
229
230 if self.user_defined.contains(&head) {
232 let args = map_fallible(tail, self, Self::parse_expr)?;
233 return Ok(vec![Command::UserDefined(span, head, args)]);
234 }
235
236 Ok(match head.as_str() {
237 "sort" => match tail {
238 [name] => vec![Command::Sort(span, name.expect_atom("sort name")?, None)],
239 [name, call] => {
240 let (func, args, _) = call.expect_call("container sort declaration")?;
241 vec![Command::Sort(
242 span,
243 name.expect_atom("sort name")?,
244 Some((func, map_fallible(args, self, Self::parse_expr)?)),
245 )]
246 }
247 _ => {
248 return error!(
249 span,
250 "usages:\n(sort <name>)\n(sort <name> (<container sort> <argument sort>*))"
251 );
252 }
253 },
254 "datatype" => match tail {
255 [name, variants @ ..] => vec![Command::Datatype {
256 span,
257 name: name.expect_atom("sort name")?,
258 variants: map_fallible(variants, self, Self::variant)?,
259 }],
260 _ => return error!(span, "usage: (datatype <name> <variant>*)"),
261 },
262 "datatype*" => vec![Command::Datatypes {
263 span,
264 datatypes: map_fallible(tail, self, Self::rec_datatype)?,
265 }],
266 "function" => match tail {
267 [name, inputs, output, rest @ ..] => vec![Command::Function {
268 name: name.expect_atom("function name")?,
269 schema: self.parse_schema(inputs, output)?,
270 merge: match self.parse_options(rest)?.as_slice() {
271 [(":no-merge", [])] => None,
272 [(":merge", [e])] => Some(self.parse_expr(e)?),
273 [] => {
274 return error!(
275 span,
276 "functions are required to specify merge behaviour"
277 );
278 }
279 _ => return error!(span, "could not parse function options"),
280 },
281 span,
282 }],
283 _ => {
284 let a = "(function <name> (<input sort>*) <output sort> :merge <expr>)";
285 let b = "(function <name> (<input sort>*) <output sort> :no-merge)";
286 return error!(span, "usages:\n{a}\n{b}");
287 }
288 },
289 "constructor" => match tail {
290 [name, inputs, output, rest @ ..] => {
291 let mut cost = None;
292 let mut unextractable = false;
293 match self.parse_options(rest)?.as_slice() {
294 [] => {}
295 [(":unextractable", [])] => unextractable = true,
296 [(":cost", [c])] => cost = Some(c.expect_uint("cost")?),
297 _ => return error!(span, "could not parse constructor options"),
298 }
299
300 vec![Command::Constructor {
301 span,
302 name: name.expect_atom("constructor name")?,
303 schema: self.parse_schema(inputs, output)?,
304 cost,
305 unextractable,
306 }]
307 }
308 _ => {
309 let a = "(constructor <name> (<input sort>*) <output sort>)";
310 let b = "(constructor <name> (<input sort>*) <output sort> :cost <cost>)";
311 let c = "(constructor <name> (<input sort>*) <output sort> :unextractable)";
312 return error!(span, "usages:\n{a}\n{b}\n{c}");
313 }
314 },
315 "relation" => match tail {
316 [name, inputs] => vec![Command::Relation {
317 span,
318 name: name.expect_atom("relation name")?,
319 inputs: map_fallible(inputs.expect_list("input sorts")?, self, |_, sexp| {
320 sexp.expect_atom("input sort")
321 })?,
322 }],
323 _ => return error!(span, "usage: (relation <name> (<input sort>*))"),
324 },
325 "ruleset" => match tail {
326 [name] => vec![Command::AddRuleset(span, name.expect_atom("ruleset name")?)],
327 _ => return error!(span, "usage: (ruleset <name>)"),
328 },
329 "unstable-combined-ruleset" => match tail {
330 [name, subrulesets @ ..] => vec![Command::UnstableCombinedRuleset(
331 span,
332 name.expect_atom("combined ruleset name")?,
333 map_fallible(subrulesets, self, |_, sexp| {
334 sexp.expect_atom("subruleset name")
335 })?,
336 )],
337 _ => {
338 return error!(
339 span,
340 "usage: (unstable-combined-ruleset <name> <child ruleset>*)"
341 );
342 }
343 },
344 "rule" => match tail {
345 [lhs, rhs, rest @ ..] => {
346 let body =
347 map_fallible(lhs.expect_list("rule query")?, self, Self::parse_fact)?;
348 let head: Vec<Vec<_>> =
349 map_fallible(rhs.expect_list("rule actions")?, self, Self::parse_action)?;
350 let head = GenericActions(head.into_iter().flatten().collect());
351
352 let mut ruleset = String::new();
353 let mut name = String::new();
354 for option in self.parse_options(rest)? {
355 match option {
356 (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?,
357 (":name", [s]) => name = s.expect_string("rule name")?,
358 _ => return error!(span, "could not parse rule option"),
359 }
360 }
361
362 vec![Command::Rule {
363 rule: Rule {
364 span,
365 head,
366 body,
367 name,
368 ruleset,
369 },
370 }]
371 }
372 _ => return error!(span, "usage: (rule (<fact>*) (<action>*) <option>*)"),
373 },
374 "rewrite" => match tail {
375 [lhs, rhs, rest @ ..] => {
376 let lhs = self.parse_expr(lhs)?;
377 let rhs = self.parse_expr(rhs)?;
378
379 let mut ruleset = String::new();
380 let mut conditions = Vec::new();
381 let mut subsume = false;
382 for option in self.parse_options(rest)? {
383 match option {
384 (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?,
385 (":subsume", []) => subsume = true,
386 (":when", [w]) => {
387 conditions = map_fallible(
388 w.expect_list("rewrite conditions")?,
389 self,
390 Self::parse_fact,
391 )?
392 }
393 _ => return error!(span, "could not parse rewrite options"),
394 }
395 }
396
397 vec![Command::Rewrite(
398 ruleset,
399 Rewrite {
400 span,
401 lhs,
402 rhs,
403 conditions,
404 },
405 subsume,
406 )]
407 }
408 _ => return error!(span, "usage: (rewrite <expr> <expr> <option>*)"),
409 },
410 "birewrite" => match tail {
411 [lhs, rhs, rest @ ..] => {
412 let lhs = self.parse_expr(lhs)?;
413 let rhs = self.parse_expr(rhs)?;
414
415 let mut ruleset = String::new();
416 let mut conditions = Vec::new();
417 for option in self.parse_options(rest)? {
418 match option {
419 (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?,
420 (":when", [w]) => {
421 conditions = map_fallible(
422 w.expect_list("rewrite conditions")?,
423 self,
424 Self::parse_fact,
425 )?
426 }
427 _ => return error!(span, "could not parse birewrite options"),
428 }
429 }
430
431 vec![Command::BiRewrite(
432 ruleset,
433 Rewrite {
434 span,
435 lhs,
436 rhs,
437 conditions,
438 },
439 )]
440 }
441 _ => return error!(span, "usage: (birewrite <expr> <expr> <option>*)"),
442 },
443 "run" => {
444 if tail.is_empty() {
445 return error!(span, "usage: (run <ruleset>? <uint> <:until (<fact>*)>?)");
446 }
447
448 let has_ruleset = tail.len() >= 2 && tail[1].expect_uint::<u32>("").is_ok();
449
450 let (ruleset, limit, rest) = if has_ruleset {
451 (
452 tail[0].expect_atom("ruleset name")?,
453 tail[1].expect_uint("number of iterations")?,
454 &tail[2..],
455 )
456 } else {
457 (
458 String::new(),
459 tail[0].expect_uint("number of iterations")?,
460 &tail[1..],
461 )
462 };
463
464 let until = match self.parse_options(rest)?.as_slice() {
465 [] => None,
466 [(":until", facts)] => Some(map_fallible(facts, self, Self::parse_fact)?),
467 _ => return error!(span, "could not parse run options"),
468 };
469
470 vec![Command::RunSchedule(Schedule::Repeat(
471 span.clone(),
472 limit,
473 Box::new(Schedule::Run(span, RunConfig { ruleset, until })),
474 ))]
475 }
476 "run-schedule" => vec![Command::RunSchedule(Schedule::Sequence(
477 span,
478 map_fallible(tail, self, Self::schedule)?,
479 ))],
480 "extract" => match tail {
481 [e] => vec![Command::Extract(
482 span.clone(),
483 self.parse_expr(e)?,
484 Expr::Lit(span, Literal::Int(0)),
485 )],
486 [e, v] => vec![Command::Extract(
487 span,
488 self.parse_expr(e)?,
489 self.parse_expr(v)?,
490 )],
491 _ => return error!(span, "usage: (extract <expr> <number of variants>?)"),
492 },
493 "check" => vec![Command::Check(
494 span,
495 map_fallible(tail, self, Self::parse_fact)?,
496 )],
497 "push" => match tail {
498 [] => vec![Command::Push(1)],
499 [n] => vec![Command::Push(n.expect_uint("number of times to push")?)],
500 _ => return error!(span, "usage: (push <uint>?)"),
501 },
502 "pop" => match tail {
503 [] => vec![Command::Pop(span, 1)],
504 [n] => vec![Command::Pop(span, n.expect_uint("number of times to pop")?)],
505 _ => return error!(span, "usage: (pop <uint>?)"),
506 },
507 "print-stats" => match tail {
508 [] => vec![Command::PrintOverallStatistics(span, None)],
509 [Sexp::Atom(o, _), file] if o == ":file" => vec![Command::PrintOverallStatistics(
510 span,
511 Some(file.expect_string("file name")?),
512 )],
513 _ => {
514 return error!(
515 span,
516 "usages: (print-stats)\n(print-stats :file \"<filename>\")"
517 );
518 }
519 },
520 "print-function" => match tail {
521 [name] => vec![Command::PrintFunction(
522 span,
523 name.expect_atom("table name")?,
524 None,
525 None,
526 PrintFunctionMode::Default,
527 )],
528 [name, rest @ ..] => {
529 let rows: Option<usize> = rest[0].expect_uint("number of rows").ok();
530 let rest = if rows.is_some() { &rest[1..] } else { rest };
531
532 let mut file = None;
533 let mut mode = PrintFunctionMode::Default;
534 for opt in self.parse_options(rest)? {
535 match opt {
536 (":file", [file_name]) => {
537 file = Some(file_name.expect_string("file name")?);
538 }
539 (":mode", [Sexp::Atom(mode_str, _)]) => {
540 mode = match mode_str.as_str() {
541 "default" => PrintFunctionMode::Default,
542 "csv" => PrintFunctionMode::CSV,
543 _ => {
544 return error!(
545 span,
546 "Unknown print-function mode. Supported modes are `default` and `csv`."
547 );
548 }
549 };
550 }
551 _ => {
552 return error!(
553 span,
554 "Unknown option to print-function. Supported options are `:mode csv|default` and `:file \"<filename>\"`."
555 );
556 }
557 }
558 }
559 vec![Command::PrintFunction(
560 span,
561 name.expect_atom("table name")?,
562 rows,
563 file,
564 mode,
565 )]
566 }
567 _ => {
568 return error!(
569 span,
570 "usage: (print-function <table name> <number of rows>? <option>*)"
571 );
572 }
573 },
574 "print-size" => match tail {
575 [] => vec![Command::PrintSize(span, None)],
576 [name] => vec![Command::PrintSize(
577 span,
578 Some(name.expect_atom("table name")?),
579 )],
580 _ => return error!(span, "usage: (print-size <table name>?)"),
581 },
582 "input" => match tail {
583 [name, file] => vec![Command::Input {
584 span,
585 name: name.expect_atom("table name")?,
586 file: file.expect_string("file name")?,
587 }],
588 _ => return error!(span, "usage: (input <table name> \"<file name>\")"),
589 },
590 "output" => match tail {
591 [file, exprs @ ..] => vec![Command::Output {
592 span,
593 file: file.expect_string("file name")?,
594 exprs: map_fallible(exprs, self, Self::parse_expr)?,
595 }],
596 _ => return error!(span, "usage: (output <file name> <expr>+)"),
597 },
598 "include" => match tail {
599 [file] => vec![Command::Include(span, file.expect_string("file name")?)],
600 _ => return error!(span, "usage: (include <file name>)"),
601 },
602 "fail" => match tail {
603 [subcommand] => {
604 let mut cs = self.parse_command(subcommand)?;
605 if cs.len() != 1 {
606 todo!("extend Fail to work with multiple parsed commands")
607 }
608 vec![Command::Fail(span, Box::new(cs.remove(0)))]
609 }
610 _ => return error!(span, "usage: (fail <command>)"),
611 },
612 _ => self
613 .parse_action(sexp)?
614 .into_iter()
615 .map(Command::Action)
616 .collect(),
617 })
618 }
619
620 pub fn schedule(&mut self, sexp: &Sexp) -> Result<Schedule, ParseError> {
621 if let Sexp::Atom(ruleset, span) = sexp {
622 return Ok(Schedule::Run(
623 span.clone(),
624 RunConfig {
625 ruleset: ruleset.clone(),
626 until: None,
627 },
628 ));
629 }
630
631 let (head, tail, span) = sexp.expect_call("schedule")?;
632
633 Ok(match head.as_str() {
634 "saturate" => Schedule::Saturate(
635 span.clone(),
636 Box::new(Schedule::Sequence(
637 span,
638 map_fallible(tail, self, Self::schedule)?,
639 )),
640 ),
641 "seq" => Schedule::Sequence(span, map_fallible(tail, self, Self::schedule)?),
642 "repeat" => match tail {
643 [limit, tail @ ..] => Schedule::Repeat(
644 span.clone(),
645 limit.expect_uint("number of iterations")?,
646 Box::new(Schedule::Sequence(
647 span,
648 map_fallible(tail, self, Self::schedule)?,
649 )),
650 ),
651 _ => return error!(span, "usage: (repeat <number of iterations> <schedule>*)"),
652 },
653 "run" => {
654 let has_ruleset = match tail.first() {
655 None => false,
656 Some(Sexp::Atom(o, _)) if *o == ":until" => false,
657 _ => true,
658 };
659
660 let (ruleset, rest) = if has_ruleset {
661 (tail[0].expect_atom("ruleset name")?, &tail[1..])
662 } else {
663 (String::new(), tail)
664 };
665
666 let until = match self.parse_options(rest)?.as_slice() {
667 [] => None,
668 [(":until", facts)] => Some(map_fallible(facts, self, Self::parse_fact)?),
669 _ => return error!(span, "could not parse run options"),
670 };
671
672 Schedule::Run(span, RunConfig { ruleset, until })
673 }
674 _ => return error!(span, "expected either saturate, seq, repeat, or run"),
675 })
676 }
677
678 pub fn parse_action(&mut self, sexp: &Sexp) -> Result<Vec<Action>, ParseError> {
679 let (head, tail, span) = sexp.expect_call("action")?;
680
681 if let Some(func) = self.actions.get(&head).cloned() {
682 return func.parse(tail, span, self);
683 }
684
685 Ok(match head.as_str() {
686 "let" => match tail {
687 [name, value] => {
688 let binding_span = name.span();
689 let binding = name.expect_atom("binding name")?;
690 self.ensure_symbol_not_reserved(&binding, &binding_span)?;
691 vec![Action::Let(span, binding, self.parse_expr(value)?)]
692 }
693 _ => return error!(span, "usage: (let <name> <expr>)"),
694 },
695 "set" => match tail {
696 [call, value] => {
697 let (func, args, _) = call.expect_call("table lookup")?;
698 let args = map_fallible(args, self, Self::parse_expr)?;
699 let value = self.parse_expr(value)?;
700 vec![Action::Set(span, func, args, value)]
701 }
702 _ => return error!(span, "usage: (set (<table name> <expr>*) <expr>)"),
703 },
704 "delete" => match tail {
705 [call] => {
706 let (func, args, _) = call.expect_call("table lookup")?;
707 let args = map_fallible(args, self, Self::parse_expr)?;
708 vec![Action::Change(span, Change::Delete, func, args)]
709 }
710 _ => return error!(span, "usage: (delete (<table name> <expr>*))"),
711 },
712 "subsume" => match tail {
713 [call] => {
714 let (func, args, _) = call.expect_call("table lookup")?;
715 let args = map_fallible(args, self, Self::parse_expr)?;
716 vec![Action::Change(span, Change::Subsume, func, args)]
717 }
718 _ => return error!(span, "usage: (subsume (<table name> <expr>*))"),
719 },
720 "union" => match tail {
721 [e1, e2] => vec![Action::Union(
722 span,
723 self.parse_expr(e1)?,
724 self.parse_expr(e2)?,
725 )],
726 _ => return error!(span, "usage: (union <expr> <expr>)"),
727 },
728 "panic" => match tail {
729 [message] => vec![Action::Panic(span, message.expect_string("error message")?)],
730 _ => return error!(span, "usage: (panic <string>)"),
731 },
732 _ => vec![Action::Expr(span, self.parse_expr(sexp)?)],
733 })
734 }
735
736 pub fn parse_fact(&mut self, sexp: &Sexp) -> Result<Fact, ParseError> {
737 let (head, tail, span) = sexp.expect_call("fact")?;
738
739 Ok(match head.as_str() {
740 "=" => match tail {
741 [e1, e2] => Fact::Eq(span, self.parse_expr(e1)?, self.parse_expr(e2)?),
742 _ => return error!(span, "usage: (= <expr> <expr>)"),
743 },
744 _ => Fact::Fact(self.parse_expr(sexp)?),
745 })
746 }
747
748 pub fn parse_expr(&mut self, sexp: &Sexp) -> Result<Expr, ParseError> {
749 Ok(match sexp {
750 Sexp::Literal(literal, span) => Expr::Lit(span.clone(), literal.clone()),
751 Sexp::Atom(symbol, span) => Expr::Var(
752 span.clone(),
753 if *symbol == "_" {
754 self.symbol_gen.fresh(symbol)
755 } else {
756 self.ensure_symbol_not_reserved(symbol, span)?;
757 symbol.clone()
758 },
759 ),
760 Sexp::List(list, span) => match list.as_slice() {
761 [] => Expr::Lit(span.clone(), Literal::Unit),
762 _ => {
763 let (head, tail, span) = sexp.expect_call("call expression")?;
764
765 if let Some(func) = self.exprs.get(&head).cloned() {
766 return func.parse(tail, span, self);
767 }
768
769 Expr::Call(
770 span.clone(),
771 head,
772 map_fallible(tail, self, Self::parse_expr)?,
773 )
774 }
775 },
776 })
777 }
778
779 pub fn rec_datatype(
780 &mut self,
781 sexp: &Sexp,
782 ) -> Result<(Span, String, Subdatatypes), ParseError> {
783 let (head, tail, span) = sexp.expect_call("datatype")?;
784
785 Ok(match head.as_str() {
786 "sort" => match tail {
787 [name, call] => {
788 let name = name.expect_atom("sort name")?;
789 let (func, args, _) = call.expect_call("container sort declaration")?;
790 let args = map_fallible(args, self, Self::parse_expr)?;
791 (span, name, Subdatatypes::NewSort(func, args))
792 }
793 _ => {
794 return error!(
795 span,
796 "usage: (sort <name> (<container sort> <argument sort>*))"
797 );
798 }
799 },
800 _ => {
801 let variants = map_fallible(tail, self, Self::variant)?;
802 (span, head, Subdatatypes::Variants(variants))
803 }
804 })
805 }
806
807 pub fn variant(&mut self, sexp: &Sexp) -> Result<Variant, ParseError> {
808 let (name, tail, span) = sexp.expect_call("datatype variant")?;
809
810 let (types, cost, unextractable) = match tail {
811 [types @ .., Sexp::Atom(o, _)] if *o == ":unextractable" => (types, None, true),
812 [types @ .., Sexp::Atom(o, _), c] if *o == ":cost" => {
813 (types, Some(c.expect_uint("cost")?), false)
814 }
815 types => (types, None, false),
816 };
817
818 Ok(Variant {
819 span,
820 name,
821 types: map_fallible(types, self, |_, sexp| {
822 sexp.expect_atom("variant argument type")
823 })?,
824 cost,
825 unextractable,
826 })
827 }
828
829 pub fn parse_options<'a>(
831 &self,
832 sexps: &'a [Sexp],
833 ) -> Result<Vec<(&'a str, &'a [Sexp])>, ParseError> {
834 fn option_name(sexp: &Sexp) -> Option<&str> {
835 if let Sexp::Atom(s, _) = sexp {
836 if let Some(':') = s.chars().next() {
837 return Some(s);
838 }
839 }
840 None
841 }
842
843 let mut out = Vec::new();
844 let mut i = 0;
845 while i < sexps.len() {
846 let Some(key) = option_name(&sexps[i]) else {
847 return error!(sexps[i].span(), "option key must start with ':'");
848 };
849 i += 1;
850
851 let start = i;
852 while i < sexps.len() && option_name(&sexps[i]).is_none() {
853 i += 1;
854 }
855 out.push((key, &sexps[start..i]));
856 }
857 Ok(out)
858 }
859
860 pub fn parse_schema(&self, input: &Sexp, output: &Sexp) -> Result<Schema, ParseError> {
861 Ok(Schema {
862 input: input
863 .expect_list("input sorts")?
864 .iter()
865 .map(|sexp| sexp.expect_atom("input sort"))
866 .collect::<Result<_, _>>()?,
867 output: output.expect_atom("output sort")?,
868 })
869 }
870}
871
872#[derive(Clone, Debug)]
873pub(crate) struct SexpParser {
874 source: Arc<SrcFile>,
875 index: usize,
876}
877
878impl SexpParser {
879 pub(crate) fn new(name: Option<String>, contents: &str) -> SexpParser {
880 SexpParser {
881 source: Arc::new(SrcFile {
882 name,
883 contents: contents.to_string(),
884 }),
885 index: 0,
886 }
887 }
888
889 fn current_char(&self) -> Option<char> {
890 self.source.contents[self.index..].chars().next()
891 }
892
893 fn advance_char(&mut self) {
894 assert!(self.index < self.source.contents.len());
895 loop {
896 self.index += 1;
897 if self.source.contents.is_char_boundary(self.index) {
898 break;
899 }
900 }
901 }
902
903 fn advance_past_whitespace(&mut self) {
904 let mut in_comment = false;
905 loop {
906 match self.current_char() {
907 None => break,
908 Some(';') => in_comment = true,
909 Some('\n') => in_comment = false,
910 Some(c) if c.is_whitespace() => {}
911 Some(_) if in_comment => {}
912 Some(_) => break,
913 }
914 self.advance_char();
915 }
916 }
917
918 fn is_at_end(&self) -> bool {
919 self.index == self.source.contents.len()
920 }
921
922 fn next(&mut self) -> Result<(Token, EgglogSpan), ParseError> {
923 self.advance_past_whitespace();
924 let mut span = EgglogSpan {
925 file: self.source.clone(),
926 i: self.index,
927 j: self.index,
928 };
929
930 let Some(c) = self.current_char() else {
931 return error!(s(span), "unexpected end of file");
932 };
933 self.advance_char();
934
935 let token = match c {
936 '(' => Token::Open,
937 ')' => Token::Close,
938 '"' => {
939 let mut in_escape = false;
940 let mut string = String::new();
941
942 loop {
943 span.j = self.index;
944 match self.current_char() {
945 None => return error!(s(span), "string is missing end quote"),
946 Some('"') if !in_escape => break,
947 Some('\\') if !in_escape => in_escape = true,
948 Some(c) => {
949 string.push(match (in_escape, c) {
950 (false, c) => c,
951 (true, 'n') => '\n',
952 (true, 't') => '\t',
953 (true, '\\') => '\\',
954 (true, '\"') => '\"',
955 (true, c) => {
956 return error!(s(span), "unrecognized escape character {c}");
957 }
958 });
959 in_escape = false;
960 }
961 }
962 self.advance_char();
963 }
964 self.advance_char();
965
966 Token::String(string)
967 }
968 _ => {
969 loop {
970 match self.current_char() {
971 Some(c) if c.is_whitespace() => break,
972 Some(';' | '(' | ')') => break,
973 None => break,
974 Some(_) => self.advance_char(),
975 }
976 }
977 Token::Other
978 }
979 };
980
981 span.j = self.index;
982 self.advance_past_whitespace();
983
984 Ok((token, span))
985 }
986}
987
988fn s(span: EgglogSpan) -> Span {
989 Span::Egglog(Arc::new(span))
990}
991
992enum Token {
993 Open,
994 Close,
995 String(String),
996 Other,
997}
998
999fn sexp(ctx: &mut SexpParser) -> Result<Sexp, ParseError> {
1000 let mut stack: Vec<(EgglogSpan, Vec<Sexp>)> = vec![];
1001
1002 loop {
1003 let (token, span) = ctx.next()?;
1004
1005 let sexp = match token {
1006 Token::Open => {
1007 stack.push((span, vec![]));
1008 continue;
1009 }
1010 Token::Close => {
1011 if stack.is_empty() {
1012 return error!(s(span), "unexpected `)`");
1013 }
1014 let (mut list_span, list) = stack.pop().unwrap();
1015 list_span.j = span.j;
1016 Sexp::List(list, s(list_span))
1017 }
1018 Token::String(sym) => Sexp::Literal(Literal::String(sym), s(span)),
1019 Token::Other => {
1020 let span = s(span);
1021 let s = span.string();
1022
1023 if s == "true" {
1024 Sexp::Literal(Literal::Bool(true), span)
1025 } else if s == "false" {
1026 Sexp::Literal(Literal::Bool(false), span)
1027 } else if let Ok(int) = s.parse::<i64>() {
1028 Sexp::Literal(Literal::Int(int), span)
1029 } else if s == "NaN" {
1030 Sexp::Literal(Literal::Float(OrderedFloat(f64::NAN)), span)
1031 } else if s == "inf" {
1032 Sexp::Literal(Literal::Float(OrderedFloat(f64::INFINITY)), span)
1033 } else if s == "-inf" {
1034 Sexp::Literal(Literal::Float(OrderedFloat(f64::NEG_INFINITY)), span)
1035 } else if let Ok(float) = s.parse::<f64>() {
1036 if float.is_finite() {
1037 Sexp::Literal(Literal::Float(OrderedFloat(float)), span)
1038 } else {
1039 Sexp::Atom(s.into(), span)
1040 }
1041 } else {
1042 Sexp::Atom(s.into(), span)
1043 }
1044 }
1045 };
1046
1047 if stack.is_empty() {
1048 return Ok(sexp);
1049 } else {
1050 stack.last_mut().unwrap().1.push(sexp);
1051 }
1052 }
1053}
1054
1055pub(crate) fn all_sexps(mut ctx: SexpParser) -> Result<Vec<Sexp>, ParseError> {
1056 let mut sexps = Vec::new();
1057 ctx.advance_past_whitespace();
1058 while !ctx.is_at_end() {
1059 sexps.push(sexp(&mut ctx)?);
1060 ctx.advance_past_whitespace();
1061 }
1062 Ok(sexps)
1063}
1064
1065#[cfg(test)]
1066mod tests {
1067 use super::*;
1068
1069 #[test]
1070 fn test_parser_display_roundtrip() {
1071 let s = r#"(f (g a 3) 4.0 (H "hello"))"#;
1072 let e = Parser::default().get_expr_from_string(None, s).unwrap();
1073 assert_eq!(format!("{}", e), s);
1074 }
1075
1076 #[test]
1077 #[rustfmt::skip]
1078 fn rust_span_display() {
1079 let actual = format!("{}", span!()).replace('\\', "/");
1080 assert!(actual.starts_with("At "));
1081 assert!(actual.contains(":"));
1082 assert!(actual.ends_with("src/ast/parse.rs"));
1083 }
1084
1085 #[test]
1086 fn test_parser_macros() {
1087 let mut parser = Parser::default();
1088 let y = "xxxx";
1089 parser.add_expr_macro(Arc::new(SimpleMacro::new("qqqq", |tail, span, macros| {
1090 Ok(Expr::Call(
1091 span,
1092 y.into(),
1093 map_fallible(tail, macros, Parser::parse_expr)?,
1094 ))
1095 })));
1096 let s = r#"(f (qqqq a 3) 4.0 (H "hello"))"#;
1097 let t = r#"(f (xxxx a 3) 4.0 (H "hello"))"#;
1098 let e = parser.get_expr_from_string(None, s).unwrap();
1099 assert_eq!(format!("{}", e), t);
1100 }
1101}