diff --git a/crates/codegen/runtime/cargo/src/runtime/language/generated/mod.rs b/crates/codegen/runtime/cargo/src/runtime/language/generated/mod.rs index d89b610d98..b59f5f6d34 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/generated/mod.rs +++ b/crates/codegen/runtime/cargo/src/runtime/language/generated/mod.rs @@ -10,6 +10,8 @@ unused_imports )] +use std::collections::HashSet; + #[cfg(feature = "__private_napi_interfaces")] use napi_derive::napi; use semver::Version; diff --git a/crates/codegen/runtime/cargo/src/runtime/language/lexer/mod.rs b/crates/codegen/runtime/cargo/src/runtime/language/lexer/mod.rs index 1c8e24910d..c3d8234f23 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/lexer/mod.rs +++ b/crates/codegen/runtime/cargo/src/runtime/language/lexer/mod.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{IsLexicalContext, TerminalKind}; use crate::language::parser_support::{ParserContext, ParserResult}; @@ -95,7 +97,7 @@ pub(crate) trait Lexer { .is_some_and(|t| t.accepted_as(kind)) { input.set_position(start); - return ParserResult::no_match(vec![kind]); + return ParserResult::no_match(HashSet::from([kind])); } let end = input.position(); @@ -104,7 +106,7 @@ pub(crate) trait Lexer { kind, input.content(start.utf8..end.utf8), ))], - vec![], + HashSet::new(), ) } @@ -130,7 +132,7 @@ pub(crate) trait Lexer { .is_some_and(|t| t.accepted_as(kind)) { input.set_position(restore); - return ParserResult::no_match(vec![kind]); + return ParserResult::no_match(HashSet::from([kind])); } let end = input.position(); children.push(Edge::anonymous(cst::Node::terminal( @@ -145,6 +147,6 @@ pub(crate) trait Lexer { input.set_position(restore); } - ParserResult::r#match(children, vec![]) + ParserResult::r#match(children, HashSet::new()) } } diff --git a/crates/codegen/runtime/cargo/src/runtime/language/mod.rs.jinja2 b/crates/codegen/runtime/cargo/src/runtime/language/mod.rs.jinja2 index 137aaf2644..2c3d6de85a 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/mod.rs.jinja2 +++ b/crates/codegen/runtime/cargo/src/runtime/language/mod.rs.jinja2 @@ -8,6 +8,8 @@ unused_imports )] +use std::collections::HashSet; + use semver::Version; #[cfg(feature = "__private_napi_interfaces")] use napi_derive::napi; diff --git a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/choice_helper.rs b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/choice_helper.rs index e08b261a3b..899c24daf5 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/choice_helper.rs +++ b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/choice_helper.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::mem; use std::ops::ControlFlow; @@ -24,7 +25,7 @@ pub struct ChoiceHelper { impl ChoiceHelper { pub fn new(input: &mut ParserContext<'_>) -> Self { Self { - result: ParserResult::no_match(vec![]), + result: ParserResult::no_match(HashSet::new()), start_position: input.mark(), recovered_errors: vec![], last_progress: input.position(), diff --git a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/parser_function.rs b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/parser_function.rs index 14d5b3e5d0..355a5c1031 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/parser_function.rs +++ b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/parser_function.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::rc::Rc; use metaslang_cst::TerminalKind as _; @@ -92,7 +93,7 @@ where ParserResult::SkippedUntil(SkippedUntil { nodes, expected, .. - }) => (nodes, vec![expected]), + }) => (nodes, HashSet::from([expected])), }; let topmost_node = match &nodes[..] { diff --git a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/parser_result.rs b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/parser_result.rs index a2158540cd..3bea97ac60 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/parser_result.rs +++ b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/parser_result.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::ops::ControlFlow; use metaslang_cst::TerminalKind as _; @@ -18,13 +19,13 @@ pub enum ParserResult { impl Default for ParserResult { fn default() -> Self { Self::NoMatch(NoMatch { - expected_terminals: vec![], + expected_terminals: HashSet::new(), }) } } impl ParserResult { - pub fn r#match(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn r#match(nodes: Vec, expected_terminals: HashSet) -> Self { ParserResult::Match(Match::new(nodes, expected_terminals)) } @@ -32,16 +33,19 @@ impl ParserResult { ParserResult::PrattOperatorMatch(PrattOperatorMatch::new(elements)) } - pub fn incomplete_match(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn incomplete_match( + nodes: Vec, + expected_terminals: HashSet, + ) -> Self { ParserResult::IncompleteMatch(IncompleteMatch::new(nodes, expected_terminals)) } /// Whenever a parser didn't run because it's disabled due to versioning. Shorthand for `no_match(vec![])`. pub fn disabled() -> Self { - Self::no_match(vec![]) + Self::no_match(HashSet::new()) } - pub fn no_match(expected_terminals: Vec) -> Self { + pub fn no_match(expected_terminals: HashSet) -> Self { ParserResult::NoMatch(NoMatch::new(expected_terminals)) } @@ -123,11 +127,11 @@ impl ParserResult { pub struct Match { pub nodes: Vec, /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl Match { - pub fn new(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn new(nodes: Vec, expected_terminals: HashSet) -> Self { Self { nodes, expected_terminals, @@ -197,11 +201,11 @@ impl PrattOperatorMatch { pub struct IncompleteMatch { pub nodes: Vec, /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl IncompleteMatch { - pub fn new(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn new(nodes: Vec, expected_terminals: HashSet) -> Self { Self { nodes, expected_terminals, @@ -239,11 +243,11 @@ impl IncompleteMatch { #[derive(PartialEq, Eq, Clone, Debug)] pub struct NoMatch { /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl NoMatch { - pub fn new(expected_terminals: Vec) -> Self { + pub fn new(expected_terminals: HashSet) -> Self { Self { expected_terminals } } } diff --git a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/precedence_helper.rs b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/precedence_helper.rs index 38b467a1c5..3e385982ca 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/precedence_helper.rs +++ b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/precedence_helper.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{EdgeLabel, NonterminalKind}; use crate::language::parser_support::parser_result::PrattElement::{ @@ -237,7 +239,7 @@ impl PrecedenceHelper { // 3. Until we have a single expression. match <[_; 1]>::try_from(elements) { - Ok([Expression { nodes }]) => ParserResult::r#match(nodes, vec![]), + Ok([Expression { nodes }]) => ParserResult::r#match(nodes, HashSet::new()), Ok([head]) => unreachable!("Expected an expression: {:#?}", head), Err(elems) => unreachable!("Expected a single element: {:#?}", elems), } diff --git a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/recovery.rs b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/recovery.rs index f28a2e5e08..e8a5a3962d 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/recovery.rs +++ b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/recovery.rs @@ -85,7 +85,7 @@ impl ParserResult { { nodes.extend(leading_trivia); if matches!(result_kind, ParseResultKind::Match) { - expected_terminals.push(expected); + expected_terminals.insert(expected); } let skipped = input.content(skipped_range.utf8()); diff --git a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/separated_helper.rs b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/separated_helper.rs index c4c0462057..b550a4b1f8 100644 --- a/crates/codegen/runtime/cargo/src/runtime/language/parser_support/separated_helper.rs +++ b/crates/codegen/runtime/cargo/src/runtime/language/parser_support/separated_helper.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{EdgeLabel, IsLexicalContext, TerminalKind}; use crate::language::lexer::Lexer; @@ -41,7 +43,9 @@ impl SeparatedHelper { // NOTE: We can't correctly attempt recovery until #600 lands, otherwise we'd risk misparses, // as we need to stop at certain synchronizing terminals (and we can't reliably scan until // a delimiter, as not every list is enclosed in a delimited group). - Some(..) | None => return ParserResult::r#match(accum, vec![separator]), + Some(..) | None => { + return ParserResult::r#match(accum, HashSet::from([separator])) + } } } // Body was partially parsed, so try to recover by skipping terminals until we see a separator diff --git a/crates/codegen/runtime/cargo/src/runtime/parse_error/mod.rs b/crates/codegen/runtime/cargo/src/runtime/parse_error/mod.rs index e30d8a0495..d1c714ae31 100644 --- a/crates/codegen/runtime/cargo/src/runtime/parse_error/mod.rs +++ b/crates/codegen/runtime/cargo/src/runtime/parse_error/mod.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeSet; +use std::collections::HashSet; use std::fmt; use crate::diagnostic::{self, Diagnostic}; @@ -11,7 +11,7 @@ use crate::text_index::TextRange; #[derive(Debug, PartialEq, Eq, Clone)] pub struct ParseError { pub(crate) text_range: TextRange, - pub(crate) terminals_that_would_have_allowed_more_progress: Vec, + pub(crate) terminals_that_would_have_allowed_more_progress: HashSet, } impl ParseError { @@ -29,7 +29,7 @@ impl ParseError { impl ParseError { pub(crate) fn new( text_range: TextRange, - terminals_that_would_have_allowed_more_progress: Vec, + terminals_that_would_have_allowed_more_progress: HashSet, ) -> Self { Self { text_range, @@ -44,23 +44,28 @@ impl fmt::Display for ParseError { .terminals_that_would_have_allowed_more_progress .is_empty() { - write!(f, "Expected end of file.") - } else { - let deduped = self - .terminals_that_would_have_allowed_more_progress - .iter() - .collect::>(); - - write!(f, "Expected ")?; - - for kind in deduped.iter().take(deduped.len() - 1) { - write!(f, "{kind} or ")?; - } - let last = deduped.last().expect("we just checked that it's not empty"); - write!(f, "{last}.")?; - - Ok(()) + return write!(f, "Expected end of file."); } + + let mut ordered = self + .terminals_that_would_have_allowed_more_progress + .iter() + .collect::>(); + + ordered.sort(); + + let mut ordered = ordered.iter(); + let first = ordered.next().expect("we just checked that it's not empty"); + + write!(f, "Expected {first}")?; + + for kind in ordered { + write!(f, " or {kind}")?; + } + + write!(f, ".")?; + + Ok(()) } } diff --git a/crates/codegen/runtime/generator/src/parser/codegen/precedence_parser_definition.rs b/crates/codegen/runtime/generator/src/parser/codegen/precedence_parser_definition.rs index 30c11f90a3..17c07879f0 100644 --- a/crates/codegen/runtime/generator/src/parser/codegen/precedence_parser_definition.rs +++ b/crates/codegen/runtime/generator/src/parser/codegen/precedence_parser_definition.rs @@ -49,9 +49,9 @@ impl PrecedenceParserDefinitionCodegen for PrecedenceParserDefinitionRef { [inner @ cst::Edge { node: cst::Node::Nonterminal(node), .. }] if node.kind == NonterminalKind::#op_nonterminal_name => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } }; diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/generated/mod.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/generated/mod.rs index a9d45e2ed1..dd43c584e5 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/generated/mod.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/generated/mod.rs @@ -10,6 +10,8 @@ unused_imports )] +use std::collections::HashSet; + #[cfg(feature = "__private_napi_interfaces")] use napi_derive::napi; use semver::Version; @@ -264,9 +266,9 @@ impl Language { }] if node.kind == NonterminalKind::AdditiveExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -311,9 +313,9 @@ impl Language { }] if node.kind == NonterminalKind::AndExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -381,9 +383,9 @@ impl Language { }] if node.kind == NonterminalKind::ArrayTypeName => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -486,9 +488,9 @@ impl Language { }] if node.kind == NonterminalKind::AssignmentExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -509,9 +511,9 @@ impl Language { }] if node.kind == NonterminalKind::BitwiseAndExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -532,9 +534,9 @@ impl Language { }] if node.kind == NonterminalKind::BitwiseOrExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -555,9 +557,9 @@ impl Language { }] if node.kind == NonterminalKind::BitwiseXorExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -656,9 +658,9 @@ impl Language { }] if node.kind == NonterminalKind::CallOptionsExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -737,9 +739,9 @@ impl Language { }] if node.kind == NonterminalKind::ComparisonExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -760,9 +762,9 @@ impl Language { }] if node.kind == NonterminalKind::ConditionalExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -1330,9 +1332,9 @@ impl Language { }] if node.kind == NonterminalKind::EqualityExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -1635,9 +1637,9 @@ impl Language { }] if node.kind == NonterminalKind::ExponentiationExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -2661,9 +2663,9 @@ impl Language { }] if node.kind == NonterminalKind::FunctionCallExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -3104,9 +3106,9 @@ impl Language { }] if node.kind == NonterminalKind::IndexAccessExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -3397,9 +3399,9 @@ impl Language { }] if node.kind == NonterminalKind::MemberAccessExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -3489,9 +3491,9 @@ impl Language { }] if node.kind == NonterminalKind::MultiplicativeExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -3727,9 +3729,9 @@ impl Language { }] if node.kind == NonterminalKind::OrExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -3954,9 +3956,9 @@ impl Language { }] if node.kind == NonterminalKind::PostfixExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -4026,9 +4028,9 @@ impl Language { }] if node.kind == NonterminalKind::PrefixExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -4214,9 +4216,9 @@ impl Language { }] if node.kind == NonterminalKind::ShiftExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -5586,9 +5588,9 @@ impl Language { }] if node.kind == NonterminalKind::VersionComparator => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -5779,9 +5781,9 @@ impl Language { }] if node.kind == NonterminalKind::VersionRange => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -6552,9 +6554,9 @@ impl Language { }] if node.kind == NonterminalKind::YulFunctionCallExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/lexer/mod.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/lexer/mod.rs index 5583450711..87cb59d0da 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/lexer/mod.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/lexer/mod.rs @@ -1,5 +1,7 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{IsLexicalContext, TerminalKind}; use crate::language::parser_support::{ParserContext, ParserResult}; @@ -97,7 +99,7 @@ pub(crate) trait Lexer { .is_some_and(|t| t.accepted_as(kind)) { input.set_position(start); - return ParserResult::no_match(vec![kind]); + return ParserResult::no_match(HashSet::from([kind])); } let end = input.position(); @@ -106,7 +108,7 @@ pub(crate) trait Lexer { kind, input.content(start.utf8..end.utf8), ))], - vec![], + HashSet::new(), ) } @@ -132,7 +134,7 @@ pub(crate) trait Lexer { .is_some_and(|t| t.accepted_as(kind)) { input.set_position(restore); - return ParserResult::no_match(vec![kind]); + return ParserResult::no_match(HashSet::from([kind])); } let end = input.position(); children.push(Edge::anonymous(cst::Node::terminal( @@ -147,6 +149,6 @@ pub(crate) trait Lexer { input.set_position(restore); } - ParserResult::r#match(children, vec![]) + ParserResult::r#match(children, HashSet::new()) } } diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/choice_helper.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/choice_helper.rs index 7d2851f770..d40eb3f2a4 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/choice_helper.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/choice_helper.rs @@ -1,5 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; use std::mem; use std::ops::ControlFlow; @@ -26,7 +27,7 @@ pub struct ChoiceHelper { impl ChoiceHelper { pub fn new(input: &mut ParserContext<'_>) -> Self { Self { - result: ParserResult::no_match(vec![]), + result: ParserResult::no_match(HashSet::new()), start_position: input.mark(), recovered_errors: vec![], last_progress: input.position(), diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/parser_function.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/parser_function.rs index 330e17e119..2baaed52c0 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/parser_function.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/parser_function.rs @@ -1,5 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; use std::rc::Rc; use metaslang_cst::TerminalKind as _; @@ -94,7 +95,7 @@ where ParserResult::SkippedUntil(SkippedUntil { nodes, expected, .. - }) => (nodes, vec![expected]), + }) => (nodes, HashSet::from([expected])), }; let topmost_node = match &nodes[..] { diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/parser_result.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/parser_result.rs index df1bde403d..ba0c0b3b90 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/parser_result.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/parser_result.rs @@ -1,5 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; use std::ops::ControlFlow; use metaslang_cst::TerminalKind as _; @@ -20,13 +21,13 @@ pub enum ParserResult { impl Default for ParserResult { fn default() -> Self { Self::NoMatch(NoMatch { - expected_terminals: vec![], + expected_terminals: HashSet::new(), }) } } impl ParserResult { - pub fn r#match(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn r#match(nodes: Vec, expected_terminals: HashSet) -> Self { ParserResult::Match(Match::new(nodes, expected_terminals)) } @@ -34,16 +35,19 @@ impl ParserResult { ParserResult::PrattOperatorMatch(PrattOperatorMatch::new(elements)) } - pub fn incomplete_match(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn incomplete_match( + nodes: Vec, + expected_terminals: HashSet, + ) -> Self { ParserResult::IncompleteMatch(IncompleteMatch::new(nodes, expected_terminals)) } /// Whenever a parser didn't run because it's disabled due to versioning. Shorthand for `no_match(vec![])`. pub fn disabled() -> Self { - Self::no_match(vec![]) + Self::no_match(HashSet::new()) } - pub fn no_match(expected_terminals: Vec) -> Self { + pub fn no_match(expected_terminals: HashSet) -> Self { ParserResult::NoMatch(NoMatch::new(expected_terminals)) } @@ -125,11 +129,11 @@ impl ParserResult { pub struct Match { pub nodes: Vec, /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl Match { - pub fn new(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn new(nodes: Vec, expected_terminals: HashSet) -> Self { Self { nodes, expected_terminals, @@ -199,11 +203,11 @@ impl PrattOperatorMatch { pub struct IncompleteMatch { pub nodes: Vec, /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl IncompleteMatch { - pub fn new(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn new(nodes: Vec, expected_terminals: HashSet) -> Self { Self { nodes, expected_terminals, @@ -241,11 +245,11 @@ impl IncompleteMatch { #[derive(PartialEq, Eq, Clone, Debug)] pub struct NoMatch { /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl NoMatch { - pub fn new(expected_terminals: Vec) -> Self { + pub fn new(expected_terminals: HashSet) -> Self { Self { expected_terminals } } } diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/precedence_helper.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/precedence_helper.rs index 114576b7fb..3058f27b88 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/precedence_helper.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/precedence_helper.rs @@ -1,5 +1,7 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{EdgeLabel, NonterminalKind}; use crate::language::parser_support::parser_result::PrattElement::{ @@ -239,7 +241,7 @@ impl PrecedenceHelper { // 3. Until we have a single expression. match <[_; 1]>::try_from(elements) { - Ok([Expression { nodes }]) => ParserResult::r#match(nodes, vec![]), + Ok([Expression { nodes }]) => ParserResult::r#match(nodes, HashSet::new()), Ok([head]) => unreachable!("Expected an expression: {:#?}", head), Err(elems) => unreachable!("Expected a single element: {:#?}", elems), } diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/recovery.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/recovery.rs index 37c2c0a7e5..00051a5c0a 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/recovery.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/recovery.rs @@ -87,7 +87,7 @@ impl ParserResult { { nodes.extend(leading_trivia); if matches!(result_kind, ParseResultKind::Match) { - expected_terminals.push(expected); + expected_terminals.insert(expected); } let skipped = input.content(skipped_range.utf8()); diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/separated_helper.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/separated_helper.rs index 0c4cb9d860..a4d7b79b29 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/separated_helper.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language/parser_support/separated_helper.rs @@ -1,5 +1,7 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{EdgeLabel, IsLexicalContext, TerminalKind}; use crate::language::lexer::Lexer; @@ -43,7 +45,9 @@ impl SeparatedHelper { // NOTE: We can't correctly attempt recovery until #600 lands, otherwise we'd risk misparses, // as we need to stop at certain synchronizing terminals (and we can't reliably scan until // a delimiter, as not every list is enclosed in a delimited group). - Some(..) | None => return ParserResult::r#match(accum, vec![separator]), + Some(..) | None => { + return ParserResult::r#match(accum, HashSet::from([separator])) + } } } // Body was partially parsed, so try to recover by skipping terminals until we see a separator diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/parse_error/mod.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/parse_error/mod.rs index 5518734d2d..7db5eda2c8 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/parse_error/mod.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/parse_error/mod.rs @@ -1,6 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. -use std::collections::BTreeSet; +use std::collections::HashSet; use std::fmt; use crate::diagnostic::{self, Diagnostic}; @@ -13,7 +13,7 @@ use crate::text_index::TextRange; #[derive(Debug, PartialEq, Eq, Clone)] pub struct ParseError { pub(crate) text_range: TextRange, - pub(crate) terminals_that_would_have_allowed_more_progress: Vec, + pub(crate) terminals_that_would_have_allowed_more_progress: HashSet, } impl ParseError { @@ -31,7 +31,7 @@ impl ParseError { impl ParseError { pub(crate) fn new( text_range: TextRange, - terminals_that_would_have_allowed_more_progress: Vec, + terminals_that_would_have_allowed_more_progress: HashSet, ) -> Self { Self { text_range, @@ -46,23 +46,28 @@ impl fmt::Display for ParseError { .terminals_that_would_have_allowed_more_progress .is_empty() { - write!(f, "Expected end of file.") - } else { - let deduped = self - .terminals_that_would_have_allowed_more_progress - .iter() - .collect::>(); - - write!(f, "Expected ")?; - - for kind in deduped.iter().take(deduped.len() - 1) { - write!(f, "{kind} or ")?; - } - let last = deduped.last().expect("we just checked that it's not empty"); - write!(f, "{last}.")?; - - Ok(()) + return write!(f, "Expected end of file."); } + + let mut ordered = self + .terminals_that_would_have_allowed_more_progress + .iter() + .collect::>(); + + ordered.sort(); + + let mut ordered = ordered.iter(); + let first = ordered.next().expect("we just checked that it's not empty"); + + write!(f, "Expected {first}")?; + + for kind in ordered { + write!(f, " or {kind}")?; + } + + write!(f, ".")?; + + Ok(()) } } diff --git a/crates/solidity/testing/snapshots/cst_output/YulBlock/ignore_unknown_delim/generated/0.8.10-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulBlock/ignore_unknown_delim/generated/0.8.10-failure.yml deleted file mode 100644 index 43f766b12c..0000000000 --- a/crates/solidity/testing/snapshots/cst_output/YulBlock/ignore_unknown_delim/generated/0.8.10-failure.yml +++ /dev/null @@ -1,84 +0,0 @@ -# This file is generated automatically by infrastructure scripts. Please don't edit by hand. - -Source: > - 1 │ { │ 0..1 - 2 │ function mult(a, b) -> result { │ 2..34 - 3 │ result := mul(a, b) │ 35..56 - 4 │ result := [mul(a, b) │ 57..79 - 5 │ } │ 80..82 - 6 │ } │ 83..84 - -Errors: # 1 total - - > - Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBaseFeeKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLeaveKeyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulSwitchKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. - ╭─[crates/solidity/testing/snapshots/cst_output/YulBlock/ignore_unknown_delim/input.sol:4:10] - │ - 4 │ ╭─▶ result := [mul(a, b) - 5 │ ├─▶ } - │ │ - │ ╰─────────── Error occurred here. - ───╯ - -Tree: - - (YulBlock): # "{\n\tfunction mult(a, b) -> result {\n\t\tresult := mul..." (0..85) - - (open_brace꞉ OpenBrace): "{" # (0..1) - - (trailing_trivia꞉ EndOfLine): "\n" # (1..2) - - (statements꞉ YulStatements): # "\tfunction mult(a, b) -> result {\n\t\tresult := mul(a..." (2..83) - - (item꞉ YulStatement) ► (variant꞉ YulFunctionDefinition): # "\tfunction mult(a, b) -> result {\n\t\tresult := mul(a..." (2..83) - - (leading_trivia꞉ Whitespace): "\t" # (2..3) - - (function_keyword꞉ YulFunctionKeyword): "function" # (3..11) - - (leading_trivia꞉ Whitespace): " " # (11..12) - - (name꞉ YulIdentifier): "mult" # (12..16) - - (parameters꞉ YulParametersDeclaration): # "(a, b)" (16..22) - - (open_paren꞉ OpenParen): "(" # (16..17) - - (parameters꞉ YulParameters): # "a, b" (17..21) - - (item꞉ YulIdentifier): "a" # (17..18) - - (separator꞉ Comma): "," # (18..19) - - (leading_trivia꞉ Whitespace): " " # (19..20) - - (item꞉ YulIdentifier): "b" # (20..21) - - (close_paren꞉ CloseParen): ")" # (21..22) - - (returns꞉ YulReturnsDeclaration): # " -> result" (22..32) - - (leading_trivia꞉ Whitespace): " " # (22..23) - - (minus_greater_than꞉ MinusGreaterThan): "->" # (23..25) - - (variables꞉ YulVariableNames): # " result" (25..32) - - (leading_trivia꞉ Whitespace): " " # (25..26) - - (item꞉ YulIdentifier): "result" # (26..32) - - (body꞉ YulBlock): # " {\n\t\tresult := mul(a, b)\n\t\tresult := [mul(a, b)\n\t}..." (32..83) - - (leading_trivia꞉ Whitespace): " " # (32..33) - - (open_brace꞉ OpenBrace): "{" # (33..34) - - (trailing_trivia꞉ EndOfLine): "\n" # (34..35) - - (statements꞉ YulStatements): # "\t\tresult := mul(a, b)\n\t\tresult" (35..65) - - (item꞉ YulStatement) ► (variant꞉ YulVariableAssignmentStatement): # "\t\tresult := mul(a, b)\n" (35..57) - - (variables꞉ YulPaths): # "\t\tresult" (35..43) - - (item꞉ YulPath): # "\t\tresult" (35..43) - - (item꞉ YulPathComponent): # "\t\tresult" (35..43) - - (leading_trivia꞉ Whitespace): "\t\t" # (35..37) - - (variant꞉ YulIdentifier): "result" # (37..43) - - (assignment꞉ YulAssignmentOperator): # " :=" (43..46) - - (leading_trivia꞉ Whitespace): " " # (43..44) - - (variant꞉ ColonEqual): ":=" # (44..46) - - (expression꞉ YulExpression) ► (variant꞉ YulFunctionCallExpression): # " mul(a, b)\n" (46..57) - - (operand꞉ YulExpression) ► (variant꞉ YulBuiltInFunction): # " mul" (46..50) - - (leading_trivia꞉ Whitespace): " " # (46..47) - - (variant꞉ YulMulKeyword): "mul" # (47..50) - - (open_paren꞉ OpenParen): "(" # (50..51) - - (arguments꞉ YulArguments): # "a, b" (51..55) - - (item꞉ YulExpression) ► (variant꞉ YulPath): # "a" (51..52) - - (item꞉ YulPathComponent) ► (variant꞉ YulIdentifier): "a" # (51..52) - - (separator꞉ Comma): "," # (52..53) - - (item꞉ YulExpression) ► (variant꞉ YulPath): # " b" (53..55) - - (item꞉ YulPathComponent): # " b" (53..55) - - (leading_trivia꞉ Whitespace): " " # (53..54) - - (variant꞉ YulIdentifier): "b" # (54..55) - - (close_paren꞉ CloseParen): ")" # (55..56) - - (trailing_trivia꞉ EndOfLine): "\n" # (56..57) - - (item꞉ YulStatement) ► (variant꞉ YulExpression) ► (variant꞉ YulPath): # "\t\tresult" (57..65) - - (item꞉ YulPathComponent): # "\t\tresult" (57..65) - - (leading_trivia꞉ Whitespace): "\t\t" # (57..59) - - (variant꞉ YulIdentifier): "result" # (59..65) - - (leading_trivia꞉ Whitespace): " " # (65..66) - - (UNRECOGNIZED): ":= [mul(a, b)\n\t" # (66..81) - - (close_brace꞉ CloseBrace): "}" # (81..82) - - (trailing_trivia꞉ EndOfLine): "\n" # (82..83) - - (close_brace꞉ CloseBrace): "}" # (83..84) - - (trailing_trivia꞉ EndOfLine): "\n" # (84..85) diff --git a/crates/solidity/testing/snapshots/cst_output/YulBlock/multiple_stack_assignments/generated/0.8.10-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulBlock/multiple_stack_assignments/generated/0.8.10-failure.yml deleted file mode 100644 index 1e429c2819..0000000000 --- a/crates/solidity/testing/snapshots/cst_output/YulBlock/multiple_stack_assignments/generated/0.8.10-failure.yml +++ /dev/null @@ -1,45 +0,0 @@ -# This file is generated automatically by infrastructure scripts. Please don't edit by hand. - -Source: > - 1 │ { │ 0..1 - 2 │ 1 │ 2..5 - 3 │ 2 │ 6..9 - 4 │ 3 │ 10..13 - 5 │ =: success │ 14..26 - 6 │ =: success │ 27..39 - 7 │ =: success │ 40..52 - 8 │ } │ 53..54 - -Errors: # 1 total - - > - Error: Expected CloseBrace or DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or OpenBrace or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBaseFeeKeyword or YulBlockHashKeyword or YulBreakKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulContinueKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulForKeyword or YulFunctionKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulIfKeyword or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLeaveKeyword or YulLetKeyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulSwitchKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. - ╭─[crates/solidity/testing/snapshots/cst_output/YulBlock/multiple_stack_assignments/input.sol:5:3] - │ - 5 │ ╭─▶ =: success - ┆ ┆ - 7 │ ├─▶ =: success - │ │ - │ ╰────────────────── Error occurred here. - ───╯ - -Tree: - - (YulBlock): # "{\n 1\n 2\n 3\n =: success\n =: success\n =: succe..." (0..55) - - (open_brace꞉ OpenBrace): "{" # (0..1) - - (trailing_trivia꞉ EndOfLine): "\n" # (1..2) - - (statements꞉ YulStatements): # " 1\n 2\n 3\n" (2..14) - - (item꞉ YulStatement) ► (variant꞉ YulExpression) ► (variant꞉ YulLiteral): # " 1\n" (2..6) - - (leading_trivia꞉ Whitespace): " " # (2..4) - - (variant꞉ YulDecimalLiteral): "1" # (4..5) - - (trailing_trivia꞉ EndOfLine): "\n" # (5..6) - - (item꞉ YulStatement) ► (variant꞉ YulExpression) ► (variant꞉ YulLiteral): # " 2\n" (6..10) - - (leading_trivia꞉ Whitespace): " " # (6..8) - - (variant꞉ YulDecimalLiteral): "2" # (8..9) - - (trailing_trivia꞉ EndOfLine): "\n" # (9..10) - - (item꞉ YulStatement) ► (variant꞉ YulExpression) ► (variant꞉ YulLiteral): # " 3\n" (10..14) - - (leading_trivia꞉ Whitespace): " " # (10..12) - - (variant꞉ YulDecimalLiteral): "3" # (12..13) - - (trailing_trivia꞉ EndOfLine): "\n" # (13..14) - - (leading_trivia꞉ Whitespace): " " # (14..16) - - (UNRECOGNIZED): "=: success\n =: success\n =: success\n" # (16..53) - - (close_brace꞉ CloseBrace): "}" # (53..54) - - (trailing_trivia꞉ EndOfLine): "\n" # (54..55) diff --git a/crates/solidity/testing/snapshots/cst_output/YulExpression/decimal_trailing_ident_start/generated/0.8.10-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulExpression/decimal_trailing_ident_start/generated/0.8.10-failure.yml deleted file mode 100644 index 4a20fefc34..0000000000 --- a/crates/solidity/testing/snapshots/cst_output/YulExpression/decimal_trailing_ident_start/generated/0.8.10-failure.yml +++ /dev/null @@ -1,17 +0,0 @@ -# This file is generated automatically by infrastructure scripts. Please don't edit by hand. - -Source: > - 1 │ 1a │ 0..2 - -Errors: # 1 total - - > - Error: Expected DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBaseFeeKeyword or YulBlockHashKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. - ╭─[crates/solidity/testing/snapshots/cst_output/YulExpression/decimal_trailing_ident_start/input.sol:1:1] - │ - 1 │ 1a - │ ─┬─ - │ ╰─── Error occurred here. - ───╯ - -Tree: - - (UNRECOGNIZED): "1a\n" # (0..3) diff --git a/crates/solidity/testing/snapshots/cst_output/YulExpression/hex_trailing_ident_start/generated/0.8.10-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulExpression/hex_trailing_ident_start/generated/0.8.10-failure.yml deleted file mode 100644 index 66cc443373..0000000000 --- a/crates/solidity/testing/snapshots/cst_output/YulExpression/hex_trailing_ident_start/generated/0.8.10-failure.yml +++ /dev/null @@ -1,17 +0,0 @@ -# This file is generated automatically by infrastructure scripts. Please don't edit by hand. - -Source: > - 1 │ 0x1$ │ 0..4 - -Errors: # 1 total - - > - Error: Expected DoubleQuotedHexStringLiteral or DoubleQuotedStringLiteral or SingleQuotedHexStringLiteral or SingleQuotedStringLiteral or YulAddKeyword or YulAddModKeyword or YulAddressKeyword or YulAndKeyword or YulBalanceKeyword or YulBaseFeeKeyword or YulBlockHashKeyword or YulByteKeyword or YulCallCodeKeyword or YulCallDataCopyKeyword or YulCallDataLoadKeyword or YulCallDataSizeKeyword or YulCallKeyword or YulCallValueKeyword or YulCallerKeyword or YulChainIdKeyword or YulCoinBaseKeyword or YulCreate2Keyword or YulCreateKeyword or YulDecimalLiteral or YulDelegateCallKeyword or YulDifficultyKeyword or YulDivKeyword or YulEqKeyword or YulExpKeyword or YulExtCodeCopyKeyword or YulExtCodeHashKeyword or YulExtCodeSizeKeyword or YulFalseKeyword or YulGasKeyword or YulGasLimitKeyword or YulGasPriceKeyword or YulGtKeyword or YulHexLiteral or YulIdentifier or YulInvalidKeyword or YulIsZeroKeyword or YulKeccak256Keyword or YulLog0Keyword or YulLog1Keyword or YulLog2Keyword or YulLog3Keyword or YulLog4Keyword or YulLtKeyword or YulMLoadKeyword or YulMSizeKeyword or YulMStore8Keyword or YulMStoreKeyword or YulModKeyword or YulMulKeyword or YulMulModKeyword or YulNotKeyword or YulNumberKeyword or YulOrKeyword or YulOriginKeyword or YulPopKeyword or YulReturnDataCopyKeyword or YulReturnDataSizeKeyword or YulReturnKeyword or YulRevertKeyword or YulSDivKeyword or YulSLoadKeyword or YulSModKeyword or YulSStoreKeyword or YulSarKeyword or YulSelfBalanceKeyword or YulSelfDestructKeyword or YulSgtKeyword or YulShlKeyword or YulShrKeyword or YulSignExtendKeyword or YulSltKeyword or YulStaticCallKeyword or YulStopKeyword or YulSubKeyword or YulTimestampKeyword or YulTrueKeyword or YulXorKeyword. - ╭─[crates/solidity/testing/snapshots/cst_output/YulExpression/hex_trailing_ident_start/input.sol:1:1] - │ - 1 │ 0x1$ - │ ──┬── - │ ╰──── Error occurred here. - ───╯ - -Tree: - - (UNRECOGNIZED): "0x1$\n" # (0..5) diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/generated/mod.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/generated/mod.rs index c8bc9fe429..2ed9438db4 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/generated/mod.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/generated/mod.rs @@ -10,6 +10,8 @@ unused_imports )] +use std::collections::HashSet; + #[cfg(feature = "__private_napi_interfaces")] use napi_derive::napi; use semver::Version; @@ -101,9 +103,9 @@ impl Language { }] if node.kind == NonterminalKind::AdditionExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -251,9 +253,9 @@ impl Language { }] if node.kind == NonterminalKind::MemberAccessExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } @@ -274,9 +276,9 @@ impl Language { }] if node.kind == NonterminalKind::NegationExpression => { ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), }, - _ => ParserResult::no_match(vec![]), + _ => ParserResult::no_match(HashSet::new()), } } diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/lexer/mod.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/lexer/mod.rs index 5583450711..87cb59d0da 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/lexer/mod.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/lexer/mod.rs @@ -1,5 +1,7 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{IsLexicalContext, TerminalKind}; use crate::language::parser_support::{ParserContext, ParserResult}; @@ -97,7 +99,7 @@ pub(crate) trait Lexer { .is_some_and(|t| t.accepted_as(kind)) { input.set_position(start); - return ParserResult::no_match(vec![kind]); + return ParserResult::no_match(HashSet::from([kind])); } let end = input.position(); @@ -106,7 +108,7 @@ pub(crate) trait Lexer { kind, input.content(start.utf8..end.utf8), ))], - vec![], + HashSet::new(), ) } @@ -132,7 +134,7 @@ pub(crate) trait Lexer { .is_some_and(|t| t.accepted_as(kind)) { input.set_position(restore); - return ParserResult::no_match(vec![kind]); + return ParserResult::no_match(HashSet::from([kind])); } let end = input.position(); children.push(Edge::anonymous(cst::Node::terminal( @@ -147,6 +149,6 @@ pub(crate) trait Lexer { input.set_position(restore); } - ParserResult::r#match(children, vec![]) + ParserResult::r#match(children, HashSet::new()) } } diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/choice_helper.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/choice_helper.rs index 7d2851f770..d40eb3f2a4 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/choice_helper.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/choice_helper.rs @@ -1,5 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; use std::mem; use std::ops::ControlFlow; @@ -26,7 +27,7 @@ pub struct ChoiceHelper { impl ChoiceHelper { pub fn new(input: &mut ParserContext<'_>) -> Self { Self { - result: ParserResult::no_match(vec![]), + result: ParserResult::no_match(HashSet::new()), start_position: input.mark(), recovered_errors: vec![], last_progress: input.position(), diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/parser_function.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/parser_function.rs index 330e17e119..2baaed52c0 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/parser_function.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/parser_function.rs @@ -1,5 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; use std::rc::Rc; use metaslang_cst::TerminalKind as _; @@ -94,7 +95,7 @@ where ParserResult::SkippedUntil(SkippedUntil { nodes, expected, .. - }) => (nodes, vec![expected]), + }) => (nodes, HashSet::from([expected])), }; let topmost_node = match &nodes[..] { diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/parser_result.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/parser_result.rs index df1bde403d..ba0c0b3b90 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/parser_result.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/parser_result.rs @@ -1,5 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; use std::ops::ControlFlow; use metaslang_cst::TerminalKind as _; @@ -20,13 +21,13 @@ pub enum ParserResult { impl Default for ParserResult { fn default() -> Self { Self::NoMatch(NoMatch { - expected_terminals: vec![], + expected_terminals: HashSet::new(), }) } } impl ParserResult { - pub fn r#match(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn r#match(nodes: Vec, expected_terminals: HashSet) -> Self { ParserResult::Match(Match::new(nodes, expected_terminals)) } @@ -34,16 +35,19 @@ impl ParserResult { ParserResult::PrattOperatorMatch(PrattOperatorMatch::new(elements)) } - pub fn incomplete_match(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn incomplete_match( + nodes: Vec, + expected_terminals: HashSet, + ) -> Self { ParserResult::IncompleteMatch(IncompleteMatch::new(nodes, expected_terminals)) } /// Whenever a parser didn't run because it's disabled due to versioning. Shorthand for `no_match(vec![])`. pub fn disabled() -> Self { - Self::no_match(vec![]) + Self::no_match(HashSet::new()) } - pub fn no_match(expected_terminals: Vec) -> Self { + pub fn no_match(expected_terminals: HashSet) -> Self { ParserResult::NoMatch(NoMatch::new(expected_terminals)) } @@ -125,11 +129,11 @@ impl ParserResult { pub struct Match { pub nodes: Vec, /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl Match { - pub fn new(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn new(nodes: Vec, expected_terminals: HashSet) -> Self { Self { nodes, expected_terminals, @@ -199,11 +203,11 @@ impl PrattOperatorMatch { pub struct IncompleteMatch { pub nodes: Vec, /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl IncompleteMatch { - pub fn new(nodes: Vec, expected_terminals: Vec) -> Self { + pub fn new(nodes: Vec, expected_terminals: HashSet) -> Self { Self { nodes, expected_terminals, @@ -241,11 +245,11 @@ impl IncompleteMatch { #[derive(PartialEq, Eq, Clone, Debug)] pub struct NoMatch { /// Terminals that would have allowed for more progress. Collected for the purposes of error reporting. - pub expected_terminals: Vec, + pub expected_terminals: HashSet, } impl NoMatch { - pub fn new(expected_terminals: Vec) -> Self { + pub fn new(expected_terminals: HashSet) -> Self { Self { expected_terminals } } } diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/precedence_helper.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/precedence_helper.rs index 114576b7fb..3058f27b88 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/precedence_helper.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/precedence_helper.rs @@ -1,5 +1,7 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{EdgeLabel, NonterminalKind}; use crate::language::parser_support::parser_result::PrattElement::{ @@ -239,7 +241,7 @@ impl PrecedenceHelper { // 3. Until we have a single expression. match <[_; 1]>::try_from(elements) { - Ok([Expression { nodes }]) => ParserResult::r#match(nodes, vec![]), + Ok([Expression { nodes }]) => ParserResult::r#match(nodes, HashSet::new()), Ok([head]) => unreachable!("Expected an expression: {:#?}", head), Err(elems) => unreachable!("Expected a single element: {:#?}", elems), } diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/recovery.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/recovery.rs index 37c2c0a7e5..00051a5c0a 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/recovery.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/recovery.rs @@ -87,7 +87,7 @@ impl ParserResult { { nodes.extend(leading_trivia); if matches!(result_kind, ParseResultKind::Match) { - expected_terminals.push(expected); + expected_terminals.insert(expected); } let skipped = input.content(skipped_range.utf8()); diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/separated_helper.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/separated_helper.rs index 0c4cb9d860..a4d7b79b29 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/separated_helper.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/language/parser_support/separated_helper.rs @@ -1,5 +1,7 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use std::collections::HashSet; + use crate::cst::{self, Edge}; use crate::kinds::{EdgeLabel, IsLexicalContext, TerminalKind}; use crate::language::lexer::Lexer; @@ -43,7 +45,9 @@ impl SeparatedHelper { // NOTE: We can't correctly attempt recovery until #600 lands, otherwise we'd risk misparses, // as we need to stop at certain synchronizing terminals (and we can't reliably scan until // a delimiter, as not every list is enclosed in a delimited group). - Some(..) | None => return ParserResult::r#match(accum, vec![separator]), + Some(..) | None => { + return ParserResult::r#match(accum, HashSet::from([separator])) + } } } // Body was partially parsed, so try to recover by skipping terminals until we see a separator diff --git a/crates/testlang/outputs/cargo/slang_testlang/src/generated/parse_error/mod.rs b/crates/testlang/outputs/cargo/slang_testlang/src/generated/parse_error/mod.rs index 5518734d2d..7db5eda2c8 100644 --- a/crates/testlang/outputs/cargo/slang_testlang/src/generated/parse_error/mod.rs +++ b/crates/testlang/outputs/cargo/slang_testlang/src/generated/parse_error/mod.rs @@ -1,6 +1,6 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. -use std::collections::BTreeSet; +use std::collections::HashSet; use std::fmt; use crate::diagnostic::{self, Diagnostic}; @@ -13,7 +13,7 @@ use crate::text_index::TextRange; #[derive(Debug, PartialEq, Eq, Clone)] pub struct ParseError { pub(crate) text_range: TextRange, - pub(crate) terminals_that_would_have_allowed_more_progress: Vec, + pub(crate) terminals_that_would_have_allowed_more_progress: HashSet, } impl ParseError { @@ -31,7 +31,7 @@ impl ParseError { impl ParseError { pub(crate) fn new( text_range: TextRange, - terminals_that_would_have_allowed_more_progress: Vec, + terminals_that_would_have_allowed_more_progress: HashSet, ) -> Self { Self { text_range, @@ -46,23 +46,28 @@ impl fmt::Display for ParseError { .terminals_that_would_have_allowed_more_progress .is_empty() { - write!(f, "Expected end of file.") - } else { - let deduped = self - .terminals_that_would_have_allowed_more_progress - .iter() - .collect::>(); - - write!(f, "Expected ")?; - - for kind in deduped.iter().take(deduped.len() - 1) { - write!(f, "{kind} or ")?; - } - let last = deduped.last().expect("we just checked that it's not empty"); - write!(f, "{last}.")?; - - Ok(()) + return write!(f, "Expected end of file."); } + + let mut ordered = self + .terminals_that_would_have_allowed_more_progress + .iter() + .collect::>(); + + ordered.sort(); + + let mut ordered = ordered.iter(); + let first = ordered.next().expect("we just checked that it's not empty"); + + write!(f, "Expected {first}")?; + + for kind in ordered { + write!(f, " or {kind}")?; + } + + write!(f, ".")?; + + Ok(()) } }