diff --git a/cli/generate/src/parse_grammar.rs b/cli/generate/src/parse_grammar.rs index 2df0009c..0b8de958 100644 --- a/cli/generate/src/parse_grammar.rs +++ b/cli/generate/src/parse_grammar.rs @@ -117,6 +117,8 @@ pub enum ParseGrammarError { Unexpected, #[error("Reserved word sets must be arrays")] InvalidReservedWordSet, + #[error("Grammar Error: Unexpected rule `{0}` in `token()` call")] + UnexpectedRule(String), } impl From for ParseGrammarError { @@ -196,7 +198,7 @@ pub(crate) fn parse_grammar(input: &str) -> ParseGrammarResult { .extras .into_iter() .try_fold(Vec::::new(), |mut acc, item| { - let rule = parse_rule(item); + let rule = parse_rule(item, false)?; if let Rule::String(ref value) = rule { if value.is_empty() { Err(ParseGrammarError::InvalidExtra)?; @@ -209,8 +211,8 @@ pub(crate) fn parse_grammar(input: &str) -> ParseGrammarResult { let mut external_tokens = grammar_json .externals .into_iter() - .map(parse_rule) - .collect::>(); + .map(|e| parse_rule(e, false)) + .collect::>>()?; let mut precedence_orderings = Vec::with_capacity(grammar_json.precedences.len()); for list in grammar_json.precedences { @@ -230,7 +232,7 @@ pub(crate) fn parse_grammar(input: &str) -> ParseGrammarResult { let rules = grammar_json .rules .into_iter() - .map(|(n, r)| Ok((n, parse_rule(serde_json::from_value(r)?)))) + .map(|(n, r)| Ok((n, parse_rule(serde_json::from_value(r)?, false)?))) .collect::>>()?; let mut in_progress = HashSet::new(); @@ -277,7 +279,7 @@ pub(crate) fn parse_grammar(input: &str) -> ParseGrammarResult { }; for value in rule_values { - reserved_words.push(parse_rule(serde_json::from_value(value)?)); + reserved_words.push(parse_rule(serde_json::from_value(value)?, false)?); } Ok(ReservedWordContext { name, @@ -300,16 +302,16 @@ pub(crate) fn parse_grammar(input: &str) -> ParseGrammarResult { }) } -fn parse_rule(json: RuleJSON) -> Rule { +fn parse_rule(json: RuleJSON, is_token: bool) -> ParseGrammarResult { match json { RuleJSON::ALIAS { content, value, named, - } => Rule::alias(parse_rule(*content), value, named), - RuleJSON::BLANK => Rule::Blank, - RuleJSON::STRING { value } => Rule::String(value), - RuleJSON::PATTERN { value, flags } => Rule::Pattern( + } => parse_rule(*content, is_token).map(|r| Rule::alias(r, value, named)), + RuleJSON::BLANK => Ok(Rule::Blank), + RuleJSON::STRING { value } => Ok(Rule::String(value)), + RuleJSON::PATTERN { value, flags } => Ok(Rule::Pattern( value, flags.map_or(String::new(), |f| { f.matches(|c| { @@ -325,34 +327,54 @@ fn parse_rule(json: RuleJSON) -> Rule { }) .collect() }), - ), - RuleJSON::SYMBOL { name } => Rule::NamedSymbol(name), - RuleJSON::CHOICE { members } => Rule::choice(members.into_iter().map(parse_rule).collect()), - RuleJSON::FIELD { content, name } => Rule::field(name, parse_rule(*content)), - RuleJSON::SEQ { members } => Rule::seq(members.into_iter().map(parse_rule).collect()), - RuleJSON::REPEAT1 { content } => Rule::repeat(parse_rule(*content)), - RuleJSON::REPEAT { content } => { - Rule::choice(vec![Rule::repeat(parse_rule(*content)), Rule::Blank]) + )), + RuleJSON::SYMBOL { name } => { + if is_token { + Err(ParseGrammarError::UnexpectedRule(name))? + } else { + Ok(Rule::NamedSymbol(name)) + } + } + RuleJSON::CHOICE { members } => members + .into_iter() + .map(|m| parse_rule(m, is_token)) + .collect::>>() + .map(Rule::choice), + RuleJSON::FIELD { content, name } => { + parse_rule(*content, is_token).map(|r| Rule::field(name, r)) + } + RuleJSON::SEQ { members } => members + .into_iter() + .map(|m| parse_rule(m, is_token)) + .collect::>>() + .map(Rule::seq), + RuleJSON::REPEAT1 { content } => parse_rule(*content, is_token).map(Rule::repeat), + RuleJSON::REPEAT { content } => { + parse_rule(*content, is_token).map(|m| Rule::choice(vec![Rule::repeat(m), Rule::Blank])) + } + RuleJSON::PREC { value, content } => { + parse_rule(*content, is_token).map(|r| Rule::prec(value.into(), r)) } - RuleJSON::PREC { value, content } => Rule::prec(value.into(), parse_rule(*content)), RuleJSON::PREC_LEFT { value, content } => { - Rule::prec_left(value.into(), parse_rule(*content)) + parse_rule(*content, is_token).map(|r| Rule::prec_left(value.into(), r)) } RuleJSON::PREC_RIGHT { value, content } => { - Rule::prec_right(value.into(), parse_rule(*content)) + parse_rule(*content, is_token).map(|r| Rule::prec_right(value.into(), r)) } RuleJSON::PREC_DYNAMIC { value, content } => { - Rule::prec_dynamic(value, parse_rule(*content)) + parse_rule(*content, is_token).map(|r| Rule::prec_dynamic(value, r)) } RuleJSON::RESERVED { content, context_name, - } => Rule::Reserved { - rule: Box::new(parse_rule(*content)), + } => parse_rule(*content, is_token).map(|r| Rule::Reserved { + rule: Box::new(r), context_name, - }, - RuleJSON::TOKEN { content } => Rule::token(parse_rule(*content)), - RuleJSON::IMMEDIATE_TOKEN { content } => Rule::immediate_token(parse_rule(*content)), + }), + RuleJSON::TOKEN { content } => parse_rule(*content, true).map(Rule::token), + RuleJSON::IMMEDIATE_TOKEN { content } => { + parse_rule(*content, is_token).map(Rule::immediate_token) + } } }