From c331027fa7c9dd1c0c32ebddec1925ca62d3386e Mon Sep 17 00:00:00 2001 From: Yihong Zhang Date: Sun, 5 Jan 2025 13:54:38 -0800 Subject: [PATCH] address nits --- src/ast/parse.rs | 108 ++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 57 deletions(-) diff --git a/src/ast/parse.rs b/src/ast/parse.rs index 3fd12a02..57bf3eb5 100644 --- a/src/ast/parse.rs +++ b/src/ast/parse.rs @@ -131,13 +131,7 @@ impl Display for Span { // error messages are defined in the same place that they are created, // making it easier to improve errors over time. #[derive(Debug, Error)] -pub struct ParseError(Span, String); - -impl ParseError { - pub fn new(span: Span, message: &str) -> Self { - Self(span, message.to_string()) - } -} +pub struct ParseError(pub Span, pub String); impl std::fmt::Display for ParseError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { @@ -223,46 +217,6 @@ fn map_fallible( .collect::>() } -// helper for parsing a list of options -fn options(sexps: &[Sexp]) -> Result, ParseError> { - fn option_name(sexp: &Sexp) -> Option<&str> { - if let Ok(symbol) = sexp.expect_atom("") { - let s: &str = symbol.into(); - if let Some(':') = s.chars().next() { - return Some(s); - } - } - None - } - - let mut out = Vec::new(); - let mut i = 0; - while i < sexps.len() { - let Some(key) = option_name(&sexps[i]) else { - return error!(sexps[i].span(), "option key must start with ':'"); - }; - i += 1; - - let start = i; - while i < sexps.len() && option_name(&sexps[i]).is_none() { - i += 1; - } - out.push((key, &sexps[start..i])); - } - Ok(out) -} - -fn schema(input: &Sexp, output: &Sexp) -> Result { - Ok(Schema { - input: input - .expect_list("input sorts")? - .iter() - .map(|sexp| sexp.expect_atom("input sort")) - .collect::>()?, - output: output.expect_atom("output sort")?, - }) -} - pub trait Macro { fn get_head(&self) -> String; fn parse(&self, args: &[Sexp], span: Span, parser: &mut Parser) -> Result; @@ -391,8 +345,8 @@ impl Parser { "function" => match tail { [name, inputs, output, rest @ ..] => vec![Command::Function { name: name.expect_atom("function name")?, - schema: schema(inputs, output)?, - merge: match options(rest)?.as_slice() { + schema: self.parse_schema(inputs, output)?, + merge: match self.parse_options(rest)?.as_slice() { [(":no-merge", [])] => None, [(":merge", [e])] => Some(self.parse_expr(e)?), [] => { @@ -415,7 +369,7 @@ impl Parser { [name, inputs, output, rest @ ..] => { let mut cost = None; let mut unextractable = false; - match options(rest)?.as_slice() { + match self.parse_options(rest)?.as_slice() { [] => {} [(":unextractable", [])] => unextractable = true, [(":cost", [c])] => cost = Some(c.expect_uint("cost")?), @@ -425,7 +379,7 @@ impl Parser { vec![Command::Constructor { span, name: name.expect_atom("constructor name")?, - schema: schema(inputs, output)?, + schema: self.parse_schema(inputs, output)?, cost, unextractable, }] @@ -475,7 +429,7 @@ impl Parser { let mut ruleset = "".into(); let mut name = "".into(); - for option in options(rest)? { + for option in self.parse_options(rest)? { match option { (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?, (":name", [s]) => name = s.expect_string("rule name")?.into(), @@ -499,7 +453,7 @@ impl Parser { let mut ruleset = "".into(); let mut conditions = Vec::new(); let mut subsume = false; - for option in options(rest)? { + for option in self.parse_options(rest)? { match option { (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?, (":subsume", []) => subsume = true, @@ -534,7 +488,7 @@ impl Parser { let mut ruleset = "".into(); let mut conditions = Vec::new(); - for option in options(rest)? { + for option in self.parse_options(rest)? { match option { (":ruleset", [r]) => ruleset = r.expect_atom("ruleset name")?, (":when", [w]) => { @@ -581,7 +535,7 @@ impl Parser { ) }; - let until = match options(rest)?.as_slice() { + let until = match self.parse_options(rest)?.as_slice() { [] => None, [(":until", facts)] => Some(map_fallible(facts, self, Self::parse_fact)?), _ => return error!(span, "could not parse run options"), @@ -607,7 +561,7 @@ impl Parser { }, "query-extract" => match tail { [rest @ .., e] => { - let variants = match options(rest)?.as_slice() { + let variants = match self.parse_options(rest)?.as_slice() { [] => 0, [(":variants", [v])] => v.expect_uint("number of variants")?, _ => return error!(span, "could not parse query-extract options"), @@ -744,7 +698,7 @@ impl Parser { ("".into(), tail) }; - let until = match options(rest)?.as_slice() { + let until = match self.parse_options(rest)?.as_slice() { [] => None, [(":until", facts)] => Some(map_fallible(facts, self, Self::parse_fact)?), _ => return error!(span, "could not parse run options"), @@ -905,6 +859,46 @@ impl Parser { cost, }) } + + // helper for parsing a list of options + pub fn parse_options<'a>(&self, sexps: &'a [Sexp]) -> Result, ParseError> { + fn option_name(sexp: &Sexp) -> Option<&str> { + if let Ok(symbol) = sexp.expect_atom("") { + let s: &str = symbol.into(); + if let Some(':') = s.chars().next() { + return Some(s); + } + } + None + } + + let mut out = Vec::new(); + let mut i = 0; + while i < sexps.len() { + let Some(key) = option_name(&sexps[i]) else { + return error!(sexps[i].span(), "option key must start with ':'"); + }; + i += 1; + + let start = i; + while i < sexps.len() && option_name(&sexps[i]).is_none() { + i += 1; + } + out.push((key, &sexps[start..i])); + } + Ok(out) + } + + pub fn parse_schema(&self, input: &Sexp, output: &Sexp) -> Result { + Ok(Schema { + input: input + .expect_list("input sorts")? + .iter() + .map(|sexp| sexp.expect_atom("input sort")) + .collect::>()?, + output: output.expect_atom("output sort")?, + }) + } } #[derive(Clone, Debug)]