From 8cfaa523a8bb9d746b5d954ef7a98c530de94b5d Mon Sep 17 00:00:00 2001 From: AntonyBlakey Date: Sun, 21 Jan 2024 04:50:35 +0000 Subject: [PATCH] Tree query language and engine --- .changeset/curvy-donkeys-shout.md | 5 + Cargo.lock | 54 +- Cargo.toml | 6 +- .../parser/generator/src/rust_generator.rs | 3 + crates/codegen/parser/runtime/Cargo.toml | 1 + crates/codegen/parser/runtime/src/cursor.rs | 6 +- crates/codegen/parser/runtime/src/kinds.rs | 13 + crates/codegen/parser/runtime/src/lib.rs | 9 + .../parser/runtime/src/query_engine.rs | 439 +++ .../parser/runtime/src/query_engine_tests.rs | 169 + .../codegen/parser/runtime/src/query_model.rs | 144 + .../parser/runtime/src/query_parser.rs | 257 ++ .../parser/runtime/src/query_parser_tests.rs | 26 + .../runtime/src/templates/kinds.rs.jinja2 | 4 +- .../runtime/src/templates/mod.rs.jinja2 | 3 + crates/codegen/parser/runtime/src/visitor.rs | 1 - .../solidity/outputs/cargo/crate/Cargo.toml | 1 + .../cargo/crate/src/generated/cursor.rs | 6 +- .../cargo/crate/src/generated/kinds.rs | 4 +- .../outputs/cargo/crate/src/generated/mod.rs | 3 + .../cargo/crate/src/generated/query_engine.rs | 441 +++ .../cargo/crate/src/generated/query_model.rs | 146 + .../cargo/crate/src/generated/query_parser.rs | 259 ++ .../solidity/outputs/cargo/crate/src/main.rs | 2 +- crates/solidity/outputs/npm/crate/Cargo.toml | 1 + .../src/generated/napi/napi_ast_selectors.rs | 2958 +++++++++++++++++ package-lock.json | 144 + 27 files changed, 5088 insertions(+), 17 deletions(-) create mode 100644 .changeset/curvy-donkeys-shout.md create mode 100644 crates/codegen/parser/runtime/src/query_engine.rs create mode 100644 crates/codegen/parser/runtime/src/query_engine_tests.rs create mode 100644 crates/codegen/parser/runtime/src/query_model.rs create mode 100644 crates/codegen/parser/runtime/src/query_parser.rs create mode 100644 crates/codegen/parser/runtime/src/query_parser_tests.rs delete mode 100644 crates/codegen/parser/runtime/src/visitor.rs create mode 100644 crates/solidity/outputs/cargo/crate/src/generated/query_engine.rs create mode 100644 crates/solidity/outputs/cargo/crate/src/generated/query_model.rs create mode 100644 crates/solidity/outputs/cargo/crate/src/generated/query_parser.rs create mode 100644 crates/solidity/outputs/npm/crate/src/generated/napi/napi_ast_selectors.rs diff --git a/.changeset/curvy-donkeys-shout.md b/.changeset/curvy-donkeys-shout.md new file mode 100644 index 0000000000..c2f725ad21 --- /dev/null +++ b/.changeset/curvy-donkeys-shout.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": patch +--- + +Add tree query implementation as `Query::parse` and `Cursor::query` diff --git a/Cargo.lock b/Cargo.lock index 7923103d34..3e4e6b057c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -469,6 +469,7 @@ dependencies = [ "napi", "napi-build", "napi-derive", + "nom", "serde", "strum", "strum_macros", @@ -1273,6 +1274,12 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -1370,6 +1377,16 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "num-traits" version = "0.2.16" @@ -1528,7 +1545,9 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" dependencies = [ + "phf_macros", "phf_shared", + "proc-macro-hack", ] [[package]] @@ -1551,6 +1570,20 @@ dependencies = [ "rand", ] +[[package]] +name = "phf_macros" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "phf_shared" version = "0.10.0" @@ -1597,6 +1630,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + [[package]] name = "proc-macro2" version = "1.0.66" @@ -2022,6 +2061,7 @@ dependencies = [ "clap", "codegen_parser_generator", "infra_utils", + "nom", "semver", "serde", "serde_json", @@ -2096,6 +2136,7 @@ dependencies = [ "napi", "napi-build", "napi-derive", + "nom", "semver", "serde", "slang_solidity", @@ -2185,21 +2226,24 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "phf", +] [[package]] name = "strum_macros" -version = "0.24.3" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 1.0.109", + "syn 2.0.29", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2971963b38..5889cfcca9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,6 +80,7 @@ napi = { version = "2.14.2", features = ["compat-mode", "napi8", "serde-json"] } napi-build = { version = "2.1.0" } napi-derive = { version = "2.14.6" } once_cell = { version = "1.19.0" } +nom = { version = "7.1.3" } owo-colors = { version = "3.5.0", features = ["supports-colors"] } proc-macro2 = { version = "1.0.53" } quote = { version = "1.0.26" } @@ -92,8 +93,9 @@ serde = { version = "1.0.158", features = ["derive", "rc"] } serde_json = { version = "1.0.94", features = ["preserve_order"] } serde_yaml = { version = "0.9.19" } similar-asserts = { version = "1.4.2" } -strum = { version = "0.24.0" } -strum_macros = { version = "0.24.0" } +stack-graphs = { version = "0.12.0" } +strum = { version = "0.25.0", features = ["phf"] } +strum_macros = { version = "0.25.3" } syn = { version = "2.0.29", features = [ "fold", "full", diff --git a/crates/codegen/parser/generator/src/rust_generator.rs b/crates/codegen/parser/generator/src/rust_generator.rs index adbcdbf27a..dca530624b 100644 --- a/crates/codegen/parser/generator/src/rust_generator.rs +++ b/crates/codegen/parser/generator/src/rust_generator.rs @@ -131,6 +131,9 @@ impl RustGenerator { "lexer.rs", "parse_error.rs", "parse_output.rs", + "query_engine.rs", + "query_model.rs", + "query_parser.rs", "text_index.rs", "napi/napi_cst.rs", "napi/napi_cursor.rs", diff --git a/crates/codegen/parser/runtime/Cargo.toml b/crates/codegen/parser/runtime/Cargo.toml index 8d74028ae3..0fb849002e 100644 --- a/crates/codegen/parser/runtime/Cargo.toml +++ b/crates/codegen/parser/runtime/Cargo.toml @@ -15,6 +15,7 @@ napi-build = { workspace = true, optional = true } ariadne = { workspace = true } napi = { workspace = true, optional = true } napi-derive = { workspace = true, optional = true } +nom = { workspace = true } serde = { workspace = true } strum = { workspace = true } strum_macros = { workspace = true } diff --git a/crates/codegen/parser/runtime/src/cursor.rs b/crates/codegen/parser/runtime/src/cursor.rs index 25bdcb6c8b..4d91aeafd6 100644 --- a/crates/codegen/parser/runtime/src/cursor.rs +++ b/crates/codegen/parser/runtime/src/cursor.rs @@ -26,9 +26,9 @@ impl PathRuleNode { /// A pointer to a [`Node`] in a CST, used by the [`Cursor`] to implement the traversal. #[derive(Clone, Debug, PartialEq, Eq)] -struct PathNode { +pub(super) struct PathNode { /// The node the cursor is currently pointing to. - node: Node, + pub(super) node: Node, /// The index of the current child node in the parent's children. // Required to go to the next/previous sibling. child_number: usize, @@ -64,7 +64,7 @@ pub struct Cursor { /// The list of ancestor rule nodes that the `current` node is a part of. path: Vec, /// The node the cursor is currently pointing to. - current: PathNode, + pub(super) current: PathNode, /// Whether the cursor is completed, i.e. at the root node as a result of traversal (or when `complete`d). /// If `true`, the cursor cannot be moved. is_completed: bool, diff --git a/crates/codegen/parser/runtime/src/kinds.rs b/crates/codegen/parser/runtime/src/kinds.rs index 2b1ac308ca..63dbf32543 100644 --- a/crates/codegen/parser/runtime/src/kinds.rs +++ b/crates/codegen/parser/runtime/src/kinds.rs @@ -13,11 +13,17 @@ use napi_derive::napi; strum_macros::Display, strum_macros::EnumString, )] +#[strum(use_phf)] #[cfg_attr( feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds") )] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum TokenKind { SKIPPED, + Identifier, // Expanded by the template engine + // Used for testing + X, + Y, + Z, } #[derive( @@ -32,12 +38,18 @@ pub enum TokenKind { strum_macros::Display, strum_macros::EnumString, )] +#[strum(use_phf)] #[cfg_attr( feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds") )] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum RuleKind { LeadingTrivia, TrailingTrivia, // Expanded by the template engine + // Used for testing + A, + B, + C, + D, } impl RuleKind { @@ -58,6 +70,7 @@ impl RuleKind { strum_macros::Display, strum_macros::EnumString, )] +#[strum(use_phf)] #[cfg_attr(feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds"))] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum FieldName { diff --git a/crates/codegen/parser/runtime/src/lib.rs b/crates/codegen/parser/runtime/src/lib.rs index 8ed2f8ed55..2f5f5a554b 100644 --- a/crates/codegen/parser/runtime/src/lib.rs +++ b/crates/codegen/parser/runtime/src/lib.rs @@ -9,7 +9,16 @@ pub mod kinds; pub(crate) mod lexer; pub mod parse_error; pub mod parse_output; +pub mod query_engine; +pub mod query_model; +pub(crate) mod query_parser; pub mod text_index; #[cfg(feature = "slang_napi_interfaces")] pub mod napi; + +#[cfg(test)] +pub mod query_engine_tests; + +#[cfg(test)] +pub mod query_parser_tests; diff --git a/crates/codegen/parser/runtime/src/query_engine.rs b/crates/codegen/parser/runtime/src/query_engine.rs new file mode 100644 index 0000000000..2e5c7f6a4f --- /dev/null +++ b/crates/codegen/parser/runtime/src/query_engine.rs @@ -0,0 +1,439 @@ +use std::collections::HashMap; +use std::rc::Rc; + +use super::cst; +use super::cursor::Cursor; +use super::query_model::{ + AlternativesMatch, BindingMatch, Kind, NodeId, NodeMatch, OneOrMoreMatch, OptionalMatch, Query, + SequenceMatch, +}; + +impl Cursor { + pub fn query(self, queries: Vec) -> QueryIterator { + QueryIterator::new(self, queries) + } + + fn consume(&mut self) -> bool { + if self.is_completed() { + false + } else { + if !self.go_to_next_sibling() { + self.complete(); + } + true + } + } + + fn matches_query_node_id(&self, node_id: &NodeId) -> bool { + match &self.current.node { + cst::Node::Rule(rule) => match node_id { + NodeId::Anonymous => true, + NodeId::Kind { kind } => Kind::Rule(rule.kind) == *kind, + NodeId::String { .. } => false, + NodeId::Field { field } => Some(*field) == self.node_name(), + NodeId::FieldAndKind { field, kind } => { + Some(*field) == self.node_name() && Kind::Rule(rule.kind) == *kind + } + NodeId::FieldAndString { .. } => false, + }, + + cst::Node::Token(token) => match node_id { + NodeId::Anonymous => true, + NodeId::Kind { kind } => Kind::Token(token.kind) == *kind, + NodeId::String { string } => token.text == *string, + NodeId::Field { field } => Some(*field) == self.node_name(), + NodeId::FieldAndKind { field, kind } => { + Some(*field) == self.node_name() && Kind::Token(token.kind) == *kind + } + NodeId::FieldAndString { field, string } => { + Some(*field) == self.node_name() && token.text == *string + } + }, + } + } +} + +impl Query { + fn create_qecref(&self, cursor: Cursor) -> QECRef { + match self { + Query::Binding(r#match) => Box::new(BindingCombinator::new(r#match.clone(), cursor)), + Query::Node(r#match) => Box::new(NodeCombinator::new(r#match.clone(), cursor)), + Query::Sequence(r#match) => Box::new(SequenceCombinator::new(r#match.clone(), cursor)), + Query::Alternatives(r#match) => { + Box::new(AlternativesCombinator::new(r#match.clone(), cursor)) + } + Query::Optional(r#match) => Box::new(OptionalCombinator::new(r#match.clone(), cursor)), + Query::OneOrMore(r#match) => { + Box::new(OneOrMoreCombinator::new(r#match.clone(), cursor)) + } + Query::Ellipsis => Box::new(EllipsisCombinator::new(cursor)), + } + } +} + +pub struct QueryIterator { + cursor: Cursor, + queries: Vec, + query_number: usize, + combinator: QECRef, +} + +impl QueryIterator { + pub fn new(cursor: Cursor, queries: Vec) -> Self { + let query_number = 0; + let combinator = queries[query_number].create_qecref(cursor.clone()); + Self { + cursor, + queries, + query_number, + combinator, + } + } +} + +impl Iterator for QueryIterator { + type Item = (usize, HashMap>); + + fn next(&mut self) -> Option { + while self.query_number < self.queries.len() { + if self.combinator.next().is_some() { + let mut bindings = HashMap::new(); + self.combinator.accumulate_bindings(&mut bindings); + return Some((self.query_number, bindings)); + } + + self.query_number += 1; + if self.query_number < self.queries.len() { + self.combinator = + self.queries[self.query_number].create_qecref(self.cursor.clone()); + } + } + + None + } +} + +trait QueryEngineCombinator { + // None -> failed to match, you must backtrack. DO NOT call again + // Some(cursor) if cursor.is_complete -> matched, end of input + // Some(cursor) if !cursor.is_complete -> matched, more input to go + fn next(&mut self) -> Option; + fn accumulate_bindings(&self, bindings: &mut HashMap>); +} +type QECRef = Box; + +struct BindingCombinator { + r#match: Rc, + cursor: Cursor, + child: QECRef, +} + +impl BindingCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + let child = r#match.child.create_qecref(cursor.clone()); + Self { + r#match, + cursor, + child, + } + } +} + +impl QueryEngineCombinator for BindingCombinator { + fn next(&mut self) -> Option { + self.child.next() + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + bindings + .entry(self.r#match.name.clone()) + .or_default() + .push(self.cursor.clone()); + } +} + +struct NodeCombinator { + r#match: Rc, + child: Option, + cursor: Cursor, + is_initialised: bool, +} + +impl NodeCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + Self { + r#match, + child: None, + cursor, + is_initialised: false, + } + } +} + +impl QueryEngineCombinator for NodeCombinator { + fn next(&mut self) -> Option { + if self.cursor.is_completed() { + return None; + } + + if !self.is_initialised { + self.is_initialised = true; + + if !self.cursor.matches_query_node_id(&self.r#match.id) { + return None; + } + + if let Some(child) = self.r#match.child.as_ref() { + let mut child_cursor = self.cursor.clone(); + if !child_cursor.go_to_first_child() { + return None; + } + + self.child = Some(child.create_qecref(child_cursor)); + } else { + let mut return_cursor = self.cursor.clone(); + return_cursor.consume(); + return Some(return_cursor); + } + } + + if let Some(child) = self.child.as_mut() { + while let Some(cursor) = child.as_mut().next() { + if cursor.is_completed() { + let mut return_cursor = self.cursor.clone(); + return_cursor.consume(); + return Some(return_cursor); + } + } + self.child = None; + } + + None + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + if let Some(child) = self.child.as_ref() { + child.accumulate_bindings(bindings); + } + } +} + +struct SequenceCombinator { + r#match: Rc, + children: Vec, + cursor: Cursor, + is_initialised: bool, +} + +impl SequenceCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + Self { + r#match, + children: vec![], + cursor, + is_initialised: false, + } + } +} + +impl QueryEngineCombinator for SequenceCombinator { + fn next(&mut self) -> Option { + if !self.is_initialised { + self.is_initialised = true; + + let child_cursor = self.cursor.clone(); + let child = self.r#match.children[0].create_qecref(child_cursor); + self.children.push(child); + } + + while !self.children.is_empty() { + if let Some(child_cursor) = self.children.last_mut().unwrap().next() { + if self.children.len() == self.r#match.children.len() { + return Some(child_cursor); + } + + let child = self.r#match.children[self.children.len()].create_qecref(child_cursor); + self.children.push(child); + } else { + self.children.pop(); + } + } + + None + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + for child in &self.children { + child.accumulate_bindings(bindings); + } + } +} + +struct AlternativesCombinator { + r#match: Rc, + next_child_number: usize, + child: Option, + cursor: Cursor, +} + +impl AlternativesCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + Self { + r#match, + next_child_number: 0, + child: None, + cursor, + } + } +} + +impl QueryEngineCombinator for AlternativesCombinator { + fn next(&mut self) -> Option { + loop { + if self.child.is_none() { + match self.r#match.children.get(self.next_child_number) { + Some(child) => { + let child = child.create_qecref(self.cursor.clone()); + self.child = Some(child); + self.next_child_number += 1; + } + None => return None, + } + } + + match self.child.as_mut().unwrap().next() { + Some(cursor) => return Some(cursor), + None => self.child = None, + } + } + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + self.child.as_ref().unwrap().accumulate_bindings(bindings); + } +} + +struct OptionalCombinator { + r#match: Rc, + child: Option, + cursor: Cursor, + have_nonempty_match: bool, +} + +impl OptionalCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + Self { + r#match, + child: None, + cursor, + have_nonempty_match: false, + } + } +} + +impl QueryEngineCombinator for OptionalCombinator { + fn next(&mut self) -> Option { + if let Some(child) = self.child.as_mut() { + match child.next() { + result @ Some(_) => { + self.have_nonempty_match = true; + result + } + None => { + self.child = None; + None + } + } + } else { + let child_cursor = self.cursor.clone(); + let child = self.r#match.child.create_qecref(child_cursor); + self.child = Some(child); + Some(self.cursor.clone()) + } + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + if self.have_nonempty_match { + if let Some(child) = self.child.as_ref() { + child.accumulate_bindings(bindings); + } + } + } +} + +struct OneOrMoreCombinator { + r#match: Rc, + children: Vec, + cursor_for_next_repetition: Option, +} + +impl OneOrMoreCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + let cursor_for_next_repetition = Some(cursor); + Self { + r#match, + children: vec![], + cursor_for_next_repetition, + } + } +} + +impl QueryEngineCombinator for OneOrMoreCombinator { + fn next(&mut self) -> Option { + loop { + if let Some(cursor_for_next_repetition) = self.cursor_for_next_repetition.take() { + let next_child = self.r#match.child.create_qecref(cursor_for_next_repetition); + self.children.push(next_child); + } else { + let tail = self.children.last_mut().unwrap(); + if let Some(cursor) = tail.next() { + if !cursor.is_completed() { + self.cursor_for_next_repetition = Some(cursor.clone()); + } + return Some(cursor); + } + self.children.pop(); + if self.children.is_empty() { + return None; + } + } + } + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + for child in &self.children { + child.accumulate_bindings(bindings); + } + } +} + +struct EllipsisCombinator { + cursor: Cursor, + has_returned_initial_empty_value: bool, +} + +impl EllipsisCombinator { + fn new(cursor: Cursor) -> Self { + Self { + cursor, + has_returned_initial_empty_value: false, + } + } +} + +impl QueryEngineCombinator for EllipsisCombinator { + fn next(&mut self) -> Option { + if !self.has_returned_initial_empty_value { + self.has_returned_initial_empty_value = true; + return Some(self.cursor.clone()); + } + + if self.cursor.consume() { + return Some(self.cursor.clone()); + } + + None + } + + fn accumulate_bindings(&self, _bindings: &mut HashMap>) {} +} diff --git a/crates/codegen/parser/runtime/src/query_engine_tests.rs b/crates/codegen/parser/runtime/src/query_engine_tests.rs new file mode 100644 index 0000000000..7178a04b56 --- /dev/null +++ b/crates/codegen/parser/runtime/src/query_engine_tests.rs @@ -0,0 +1,169 @@ +use std::collections::{BTreeMap, HashMap}; + +use super::cst::{NamedNode, Node}; +use super::cursor::Cursor; +use super::kinds::{RuleKind, TokenKind}; +use super::query_model::Query; +use super::text_index::TextIndex; + +fn token(kind: TokenKind, text: &str) -> NamedNode { + NamedNode { + name: None, + node: Node::token(kind, text.to_string()), + } +} + +fn rule(kind: RuleKind, children: [NamedNode; N]) -> NamedNode { + NamedNode { + name: None, + node: Node::rule(kind, children.into_iter().collect()), + } +} + +fn binding_cursors_to_strings( + bindings: HashMap>, +) -> BTreeMap> { + bindings + .into_iter() + .map(|(key, values)| { + ( + key, + values + .iter() + .map(|v| v.node().unparse()) + .collect::>(), + ) + }) + .collect::>() +} + +#[allow(unused_macro_rules)] +macro_rules! cst_tree { + ( @inner [ $($child:expr)* ]) => { [ $($child),* ] }; + + ( @inner [ $($child:expr)* ] $kind:ident $text:literal $(, $($rest:tt)*)? ) => { + cst_tree!(@inner [ $($child)* token(TokenKind::$kind, $text) ] $($($rest)*)?) + }; + + ( @inner [ $($child:expr)* ] $kind:ident [ $($children:tt)* ] $(, $($rest:tt)*)? ) => { + cst_tree!(@inner [ $($child)* rule(RuleKind::$kind, cst_tree!(@inner [] $($children)*)) ] $($($rest)*)?) + }; + + // Start with a rule + ( $kind:ident [ $($children:tt)* ] ) => { + rule(RuleKind::$kind, cst_tree!(@inner [] $($children)*)) + }; + +} + +macro_rules! query_result { + ( $( { $( $key:ident : [ $($value:literal),* ] ),* } )* ) => { + vec![ $( { + #[allow(unused_mut)] + let mut bindings = BTreeMap::new(); + $( bindings.insert( stringify!($key).to_string(), vec![ $( $value.to_string() ),* ]); )* + bindings + } ),* ] + }; + +} + +fn run_query_test(tree: &NamedNode, query: &str, results: Vec>>) { + let cursor = tree.cursor_with_offset(TextIndex::ZERO); + let query = vec![Query::parse(query).unwrap()]; + let mut results = results.into_iter(); + for (_query_no, bindings) in cursor.query(query) { + let bindings = binding_cursors_to_strings(bindings); + if let Some(expected_bindings) = results.next() { + assert_eq!(bindings, expected_bindings); + } else { + panic!("Unexpected query result"); + } + } + assert!(results.next().is_none(), "Missing query result"); +} + +fn common_test_tree() -> NamedNode { + cst_tree!( + A [ + X "t1", + X "t2", + X "t3", + ] + ) +} + +#[test] +fn test_spread() { + run_query_test( + &common_test_tree(), + "[A ... @x1 [X] ... @x2 [X] ...]", + query_result! { + {x1: ["t1"], x2: ["t2"]} + {x1: ["t1"], x2: ["t3"]} + {x1: ["t2"], x2: ["t3"]} + }, + ); +} + +#[test] +fn test_adjacent() { + run_query_test( + &common_test_tree(), + "[A ... @y1 [X] @y2 [X] ...]", + query_result! { + {y1: ["t1"], y2: ["t2"]} + {y1: ["t2"], y2: ["t3"]} + }, + ); +} + +#[test] +fn test_text_value() { + run_query_test( + &common_test_tree(), + r#"[A ... @z1 [X] ["t2"] @z2 [X] ...]"#, + query_result! { + {z1: ["t1"], z2: ["t3"]} + }, + ); +} + +#[test] +fn test_one_or_more() { + run_query_test( + &common_test_tree(), + "[A ... (@x [X])+ ]", + query_result! { + {x: ["t1", "t2", "t3"]} + {x: ["t2", "t3"]} + {x: ["t3"]} + }, + ); +} + +#[test] +fn test_zero_or_more() { + run_query_test( + &common_test_tree(), + "[A ... (@y [X])* ]", + query_result! { + {y: ["t1", "t2", "t3"]} + {y: ["t2", "t3"]} + {y: ["t3"]} + {} + }, + ); +} + +#[test] +fn test_optional() { + run_query_test( + &common_test_tree(), + "[A ... (@z [X])? ]", + query_result! { + {z: ["t3"]} + {} + }, + ); +} diff --git a/crates/codegen/parser/runtime/src/query_model.rs b/crates/codegen/parser/runtime/src/query_model.rs new file mode 100644 index 0000000000..6651880a95 --- /dev/null +++ b/crates/codegen/parser/runtime/src/query_model.rs @@ -0,0 +1,144 @@ +use std::rc::Rc; + +use super::kinds::{FieldName, RuleKind, TokenKind}; + +#[derive(Clone)] +pub enum Query { + Binding(Rc), + Node(Rc), + Optional(Rc), + Alternatives(Rc), + Sequence(Rc), + OneOrMore(Rc), + Ellipsis, +} + +impl Query { + pub fn parse(text: &str) -> Result { + super::query_parser::parse_query(text) + } + + pub fn unparse(&self) -> String { + match self { + Self::Binding(binding) => { + format!("@{} {}", binding.name, binding.child.unparse()) + } + Self::Node(node) => { + if let Some(child) = &node.child { + format!("[{} {}]", node.id.unparse(), child.unparse()) + } else { + format!("[{}]", node.id.unparse()) + } + } + Self::Optional(optional) => { + format!("({})?", optional.child.unparse()) + } + Self::Alternatives(alternatives) => { + format!( + "({})", + alternatives + .children + .iter() + .map(|c| c.unparse()) + .collect::>() + .join(" | ") + ) + } + Self::Sequence(sequence) => sequence + .children + .iter() + .map(|c| c.unparse()) + .collect::>() + .join(" "), + Self::OneOrMore(one_or_more) => { + format!("({})+", one_or_more.child.unparse()) + } + Self::Ellipsis => "...".to_string(), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Kind { + Rule(RuleKind), + Token(TokenKind), +} + +impl Kind { + fn unparse(self) -> String { + match self { + Kind::Rule(rule) => rule.to_string(), + Kind::Token(token) => token.to_string(), + } + } +} + +#[derive(Clone)] +pub enum NodeId { + Anonymous, + Kind { kind: Kind }, + String { string: String }, + Field { field: FieldName }, + FieldAndKind { field: FieldName, kind: Kind }, + FieldAndString { field: FieldName, string: String }, +} + +impl NodeId { + fn unparse(&self) -> String { + match self { + NodeId::Anonymous => "_".to_string(), + NodeId::Kind { kind } => kind.unparse(), + NodeId::String { string } => format!("\"{}\"", Self::escape_string(string)), + NodeId::Field { field } => field.to_string(), + NodeId::FieldAndKind { field, kind } => { + format!("{field}; {}", kind.unparse()) + } + NodeId::FieldAndString { field, string } => { + format!("{field}: \"{}\"", Self::escape_string(string)) + } + } + } + + fn escape_string(string: &str) -> String { + string + .chars() + .map(|c| match c { + '"' => "\\\"".to_string(), + '\\' => "\\\\".to_string(), + '\n' => "\\n".to_string(), + '\r' => "\\r".to_string(), + '\t' => "\\t".to_string(), + '\u{08}' => "\\b".to_string(), + '\u{0c}' => "\\f".to_string(), + _ if c.is_ascii_graphic() => c.to_string(), + _ => format!("\\u{{{:x}}}", c as u32), + }) + .collect::() + } +} + +pub struct BindingMatch { + pub name: String, + pub child: Query, +} + +pub struct NodeMatch { + pub id: NodeId, + pub child: Option, +} + +pub struct SequenceMatch { + pub children: Vec, +} + +pub struct AlternativesMatch { + pub children: Vec, +} + +pub struct OptionalMatch { + pub child: Query, +} + +pub struct OneOrMoreMatch { + pub child: Query, +} diff --git a/crates/codegen/parser/runtime/src/query_parser.rs b/crates/codegen/parser/runtime/src/query_parser.rs new file mode 100644 index 0000000000..d87cef7710 --- /dev/null +++ b/crates/codegen/parser/runtime/src/query_parser.rs @@ -0,0 +1,257 @@ +use std::rc::Rc; + +use nom::branch::alt; +use nom::bytes::complete::{is_not, tag, take_while, take_while1, take_while_m_n}; +use nom::character::complete::{char, multispace0, multispace1, satisfy}; +use nom::combinator::{all_consuming, map_opt, map_res, opt, recognize, value, verify}; +use nom::error::VerboseError; +use nom::multi::{fold_many0, many0, many1}; +use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::{Finish, IResult, Parser}; + +use super::kinds::{FieldName, RuleKind, TokenKind}; +use super::query_model::{ + AlternativesMatch, BindingMatch, Kind, NodeId, NodeMatch, OneOrMoreMatch, OptionalMatch, Query, + SequenceMatch, +}; + +pub(super) fn parse_query(input: &str) -> Result { + all_consuming(preceded( + multispace0, + opt(binding_name_token) + .and(alt(( + parse_node, + delimited( + token('('), + pair(parse_node, many1(preceded(token('|'), parse_node))), + token(')'), + ) + .map(|(first, rest)| { + let mut children = vec![first]; + children.extend(rest); + Query::Alternatives(Rc::new(AlternativesMatch { children })) + }), + ))) + .map(|(binding_name, child)| { + if let Some(name) = binding_name { + Query::Binding(Rc::new(BindingMatch { name, child })) + } else { + child + } + }), + )) + .parse(input) + .finish() + .map(|(_, query)| query) + .map_err(|e| e.to_string()) +} + +fn parse_node(i: &str) -> IResult<&str, Query, VerboseError<&str>> { + delimited( + token('['), + parse_node_id.and(many0(parse_match)), + token(']'), + ) + .map(|(id, mut children)| { + let child = if children.is_empty() { + None + } else if children.len() == 1 { + Some(children.pop().unwrap()) + } else { + Some(Query::Sequence(Rc::new(SequenceMatch { children }))) + }; + Query::Node(Rc::new(NodeMatch { id, child })) + }) + .parse(i) +} + +fn parse_node_id(input: &str) -> IResult<&str, NodeId, VerboseError<&str>> { + pub enum Tail { + Anonymous, + Kind(Kind), + String(String), + } + + opt(field_name_token) + .and(alt(( + token('_').map(|_| Tail::Anonymous), + kind_name_token.map(Tail::Kind), + string_token.map(Tail::String), + ))) + .map(|(field, tail)| match (field, tail) { + (None, Tail::Anonymous) => NodeId::Anonymous, + (None, Tail::Kind(kind)) => NodeId::Kind { kind }, + (None, Tail::String(string)) => NodeId::String { string }, + (Some(field), Tail::Anonymous) => NodeId::Field { field }, + (Some(field), Tail::Kind(kind)) => NodeId::FieldAndKind { field, kind }, + (Some(field), Tail::String(string)) => NodeId::FieldAndString { field, string }, + }) + .parse(input) +} + +#[derive(Clone)] +enum Quantifier { + ZeroOrOne, + ZeroOrMore, + OneOrMore, +} + +fn parse_match(input: &str) -> IResult<&str, Query, VerboseError<&str>> { + opt(binding_name_token) + .and(alt(( + parse_node, + pair( + delimited(token('('), many1(parse_match), token(')')), + parse_trailing_quantifier, + ) + .map(|(mut children, quantifier)| { + let child = if children.len() == 1 { + children.pop().unwrap() + } else { + Query::Sequence(Rc::new(SequenceMatch { children })) + }; + match quantifier { + Quantifier::ZeroOrOne => Query::Optional(Rc::new(OptionalMatch { child })), + Quantifier::ZeroOrMore => Query::Optional(Rc::new(OptionalMatch { + child: Query::OneOrMore(Rc::new(OneOrMoreMatch { child })), + })), + Quantifier::OneOrMore => Query::OneOrMore(Rc::new(OneOrMoreMatch { child })), + } + }), + delimited( + token('('), + pair(parse_match, many1(preceded(token('|'), parse_match))), + token(')'), + ) + .map(|(first, rest)| { + let mut children = vec![first]; + children.extend(rest); + Query::Alternatives(Rc::new(AlternativesMatch { children })) + }), + ellipsis_token.map(|_| Query::Ellipsis), + ))) + .map(|(binding, child)| { + if let Some(name) = binding { + Query::Binding(Rc::new(BindingMatch { name, child })) + } else { + child + } + }) + .parse(input) +} + +fn parse_trailing_quantifier(i: &str) -> IResult<&str, Quantifier, VerboseError<&str>> { + alt(( + value(Quantifier::ZeroOrOne, token('?')), + value(Quantifier::ZeroOrMore, token('*')), + value(Quantifier::OneOrMore, token('+')), + )) + .parse(i) +} + +fn raw_identifier(i: &str) -> IResult<&str, String, VerboseError<&str>> { + let identifier_head = satisfy(|c| c.is_alphabetic()); + let is_identifier_tail = |c: char| c == '_' || c.is_alphanumeric(); + recognize(alt(( + // single underscore is the anonymous syntax item, + // so we don't allow it as an identifier + char('_').and(take_while1(is_identifier_tail)), + identifier_head.and(take_while(is_identifier_tail)), + ))) + .map(|s: &str| s.to_string()) + .parse(i) +} + +fn binding_name_token(i: &str) -> IResult<&str, String, VerboseError<&str>> { + terminated(preceded(char('@'), raw_identifier), multispace0).parse(i) +} + +fn kind_name_token(i: &str) -> IResult<&str, Kind, VerboseError<&str>> { + terminated(raw_identifier, multispace0) + .map(|id| { + TokenKind::try_from(id.as_str()) + .map(Kind::Token) + .or_else(|_| RuleKind::try_from(id.as_str()).map(Kind::Rule)) + .unwrap() // TODO + }) + .parse(i) +} + +fn field_name_token(i: &str) -> IResult<&str, FieldName, VerboseError<&str>> { + terminated(raw_identifier, token(':')) + .map(|id| FieldName::try_from(id.as_str()).unwrap()) + .parse(i) +} + +fn string_token(i: &str) -> IResult<&str, String, VerboseError<&str>> { + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + enum Fragment<'a> { + EscapedChar(char), + SwallowedWhitespace, + UnescapedSequence(&'a str), + } + + let escaped_char = preceded( + char('\\'), + alt(( + map_opt( + map_res( + preceded( + char('u'), + delimited( + char('{'), + // 1 to 6 hex digits + take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()), + char('}'), + ), + ), + // converted from hex + move |hex| u32::from_str_radix(hex, 16), + ), + // converted to a char + std::char::from_u32, + ), + value('\n', char('n')), + value('\r', char('r')), + value('\t', char('t')), + value('\u{08}', char('b')), + value('\u{0C}', char('f')), + value('\\', char('\\')), + value('"', char('"')), + )), + ) + .map(Fragment::EscapedChar); + + // any amount of whitespace, collapsed to nothing + let swallowed_whitespace = value( + Fragment::SwallowedWhitespace, + preceded(char('\\'), multispace1), + ); + + let unescaped_sequence = + verify(is_not("\"\\"), |s: &str| !s.is_empty()).map(Fragment::UnescapedSequence); + + let fragment = alt((unescaped_sequence, escaped_char, swallowed_whitespace)); + + delimited( + char('"'), + fold_many0(fragment, String::new, |mut string, fragment| { + match fragment { + Fragment::EscapedChar(c) => string.push(c), + Fragment::SwallowedWhitespace => {} + Fragment::UnescapedSequence(s) => string.push_str(s), + } + string + }), + char('"'), + ) + .parse(i) +} + +fn ellipsis_token(i: &str) -> IResult<&str, &str, VerboseError<&str>> { + terminated(tag("..."), multispace0).parse(i) +} + +fn token<'input>(c: char) -> impl Parser<&'input str, char, VerboseError<&'input str>> { + terminated(char(c), multispace0) +} diff --git a/crates/codegen/parser/runtime/src/query_parser_tests.rs b/crates/codegen/parser/runtime/src/query_parser_tests.rs new file mode 100644 index 0000000000..ebc317f3b5 --- /dev/null +++ b/crates/codegen/parser/runtime/src/query_parser_tests.rs @@ -0,0 +1,26 @@ +use super::query_model::Query; + +fn run_parser_test(input: &str, result: &str) { + assert_eq!(Query::parse(input).unwrap().unparse(), result); +} + +#[test] +fn test_parsing() { + run_parser_test( + r#"@root [_ ... [Identifier] ["abc\\\"\n\r\b\t\u{01abcd}"] ...]"#, + r#"@root [_ ... [Identifier] ["abc\\\"\n\r\b\t\u{1abcd}"] ...]"#, + ); +} + +// Test the error message on parse failure +#[test] +fn test_parsing_error() { + let result = Query::parse(r#"@root [_ ..."#); + match result { + Ok(_) => panic!("Expected error"), + Err(e) => assert_eq!( + e.to_string(), + "Parse error:\nexpected '(' at: [_ ...\nAlt at: [_ ...\n" + ), + } +} diff --git a/crates/codegen/parser/runtime/src/templates/kinds.rs.jinja2 b/crates/codegen/parser/runtime/src/templates/kinds.rs.jinja2 index c9aa935141..3e875fd504 100644 --- a/crates/codegen/parser/runtime/src/templates/kinds.rs.jinja2 +++ b/crates/codegen/parser/runtime/src/templates/kinds.rs.jinja2 @@ -13,6 +13,7 @@ use napi_derive::napi; strum_macros::Display, strum_macros::EnumString, )] +#[strum(use_phf)] #[cfg_attr(feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds"))] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum RuleKind { @@ -46,7 +47,7 @@ impl RuleKind { strum_macros::Display, strum_macros::EnumString, )] -#[strum(serialize_all = "snake_case")] +#[strum(use_phf, serialize_all = "snake_case")] #[cfg_attr(feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds"))] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum FieldName { @@ -76,6 +77,7 @@ pub enum FieldName { strum_macros::Display, strum_macros::EnumString, )] +#[strum(use_phf)] #[cfg_attr(feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds"))] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum TokenKind { diff --git a/crates/codegen/parser/runtime/src/templates/mod.rs.jinja2 b/crates/codegen/parser/runtime/src/templates/mod.rs.jinja2 index 4bb91487cf..750a653809 100644 --- a/crates/codegen/parser/runtime/src/templates/mod.rs.jinja2 +++ b/crates/codegen/parser/runtime/src/templates/mod.rs.jinja2 @@ -8,6 +8,9 @@ pub mod language; pub(crate) mod lexer; pub mod parse_error; pub mod parse_output; +pub mod query_engine; +pub mod query_model; +pub mod query_parser; pub mod text_index; #[cfg(feature = "slang_napi_interfaces")] diff --git a/crates/codegen/parser/runtime/src/visitor.rs b/crates/codegen/parser/runtime/src/visitor.rs deleted file mode 100644 index 8b13789179..0000000000 --- a/crates/codegen/parser/runtime/src/visitor.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/crates/solidity/outputs/cargo/crate/Cargo.toml b/crates/solidity/outputs/cargo/crate/Cargo.toml index 6dab111b05..60e677fc86 100644 --- a/crates/solidity/outputs/cargo/crate/Cargo.toml +++ b/crates/solidity/outputs/cargo/crate/Cargo.toml @@ -45,6 +45,7 @@ solidity_language = { workspace = true } # __REMOVE_THIS_LINE_DURING_CARG anyhow = { workspace = true, optional = true } ariadne = { workspace = true } clap = { workspace = true, optional = true } +nom = { workspace = true } semver = { workspace = true } serde = { workspace = true } serde_json = { workspace = true, optional = true } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/cursor.rs b/crates/solidity/outputs/cargo/crate/src/generated/cursor.rs index aa49275c2f..013f818725 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/cursor.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/cursor.rs @@ -28,9 +28,9 @@ impl PathRuleNode { /// A pointer to a [`Node`] in a CST, used by the [`Cursor`] to implement the traversal. #[derive(Clone, Debug, PartialEq, Eq)] -struct PathNode { +pub(super) struct PathNode { /// The node the cursor is currently pointing to. - node: Node, + pub(super) node: Node, /// The index of the current child node in the parent's children. // Required to go to the next/previous sibling. child_number: usize, @@ -66,7 +66,7 @@ pub struct Cursor { /// The list of ancestor rule nodes that the `current` node is a part of. path: Vec, /// The node the cursor is currently pointing to. - current: PathNode, + pub(super) current: PathNode, /// Whether the cursor is completed, i.e. at the root node as a result of traversal (or when `complete`d). /// If `true`, the cursor cannot be moved. is_completed: bool, diff --git a/crates/solidity/outputs/cargo/crate/src/generated/kinds.rs b/crates/solidity/outputs/cargo/crate/src/generated/kinds.rs index 39f05e33e8..06c0a099d1 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/kinds.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/kinds.rs @@ -15,6 +15,7 @@ use napi_derive::napi; strum_macros::Display, strum_macros::EnumString, )] +#[strum(use_phf)] #[cfg_attr(feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds"))] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum RuleKind { @@ -253,7 +254,7 @@ impl RuleKind { strum_macros::Display, strum_macros::EnumString, )] -#[strum(serialize_all = "snake_case")] +#[strum(use_phf, serialize_all = "snake_case")] #[cfg_attr(feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds"))] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum FieldName { @@ -402,6 +403,7 @@ pub enum FieldName { strum_macros::Display, strum_macros::EnumString, )] +#[strum(use_phf)] #[cfg_attr(feature = "slang_napi_interfaces", /* derives `Clone` and `Copy` */ napi(string_enum, namespace = "kinds"))] #[cfg_attr(not(feature = "slang_napi_interfaces"), derive(Clone, Copy))] pub enum TokenKind { diff --git a/crates/solidity/outputs/cargo/crate/src/generated/mod.rs b/crates/solidity/outputs/cargo/crate/src/generated/mod.rs index aa488c9b16..849da7c7e3 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/mod.rs @@ -10,6 +10,9 @@ pub mod language; pub(crate) mod lexer; pub mod parse_error; pub mod parse_output; +pub mod query_engine; +pub mod query_model; +pub mod query_parser; pub mod text_index; #[cfg(feature = "slang_napi_interfaces")] diff --git a/crates/solidity/outputs/cargo/crate/src/generated/query_engine.rs b/crates/solidity/outputs/cargo/crate/src/generated/query_engine.rs new file mode 100644 index 0000000000..b0ff3b4018 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/query_engine.rs @@ -0,0 +1,441 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::collections::HashMap; +use std::rc::Rc; + +use super::cst; +use super::cursor::Cursor; +use super::query_model::{ + AlternativesMatch, BindingMatch, Kind, NodeId, NodeMatch, OneOrMoreMatch, OptionalMatch, Query, + SequenceMatch, +}; + +impl Cursor { + pub fn query(self, queries: Vec) -> QueryIterator { + QueryIterator::new(self, queries) + } + + fn consume(&mut self) -> bool { + if self.is_completed() { + false + } else { + if !self.go_to_next_sibling() { + self.complete(); + } + true + } + } + + fn matches_query_node_id(&self, node_id: &NodeId) -> bool { + match &self.current.node { + cst::Node::Rule(rule) => match node_id { + NodeId::Anonymous => true, + NodeId::Kind { kind } => Kind::Rule(rule.kind) == *kind, + NodeId::String { .. } => false, + NodeId::Field { field } => Some(*field) == self.node_name(), + NodeId::FieldAndKind { field, kind } => { + Some(*field) == self.node_name() && Kind::Rule(rule.kind) == *kind + } + NodeId::FieldAndString { .. } => false, + }, + + cst::Node::Token(token) => match node_id { + NodeId::Anonymous => true, + NodeId::Kind { kind } => Kind::Token(token.kind) == *kind, + NodeId::String { string } => token.text == *string, + NodeId::Field { field } => Some(*field) == self.node_name(), + NodeId::FieldAndKind { field, kind } => { + Some(*field) == self.node_name() && Kind::Token(token.kind) == *kind + } + NodeId::FieldAndString { field, string } => { + Some(*field) == self.node_name() && token.text == *string + } + }, + } + } +} + +impl Query { + fn create_qecref(&self, cursor: Cursor) -> QECRef { + match self { + Query::Binding(r#match) => Box::new(BindingCombinator::new(r#match.clone(), cursor)), + Query::Node(r#match) => Box::new(NodeCombinator::new(r#match.clone(), cursor)), + Query::Sequence(r#match) => Box::new(SequenceCombinator::new(r#match.clone(), cursor)), + Query::Alternatives(r#match) => { + Box::new(AlternativesCombinator::new(r#match.clone(), cursor)) + } + Query::Optional(r#match) => Box::new(OptionalCombinator::new(r#match.clone(), cursor)), + Query::OneOrMore(r#match) => { + Box::new(OneOrMoreCombinator::new(r#match.clone(), cursor)) + } + Query::Ellipsis => Box::new(EllipsisCombinator::new(cursor)), + } + } +} + +pub struct QueryIterator { + cursor: Cursor, + queries: Vec, + query_number: usize, + combinator: QECRef, +} + +impl QueryIterator { + pub fn new(cursor: Cursor, queries: Vec) -> Self { + let query_number = 0; + let combinator = queries[query_number].create_qecref(cursor.clone()); + Self { + cursor, + queries, + query_number, + combinator, + } + } +} + +impl Iterator for QueryIterator { + type Item = (usize, HashMap>); + + fn next(&mut self) -> Option { + while self.query_number < self.queries.len() { + if self.combinator.next().is_some() { + let mut bindings = HashMap::new(); + self.combinator.accumulate_bindings(&mut bindings); + return Some((self.query_number, bindings)); + } + + self.query_number += 1; + if self.query_number < self.queries.len() { + self.combinator = + self.queries[self.query_number].create_qecref(self.cursor.clone()); + } + } + + None + } +} + +trait QueryEngineCombinator { + // None -> failed to match, you must backtrack. DO NOT call again + // Some(cursor) if cursor.is_complete -> matched, end of input + // Some(cursor) if !cursor.is_complete -> matched, more input to go + fn next(&mut self) -> Option; + fn accumulate_bindings(&self, bindings: &mut HashMap>); +} +type QECRef = Box; + +struct BindingCombinator { + r#match: Rc, + cursor: Cursor, + child: QECRef, +} + +impl BindingCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + let child = r#match.child.create_qecref(cursor.clone()); + Self { + r#match, + cursor, + child, + } + } +} + +impl QueryEngineCombinator for BindingCombinator { + fn next(&mut self) -> Option { + self.child.next() + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + bindings + .entry(self.r#match.name.clone()) + .or_default() + .push(self.cursor.clone()); + } +} + +struct NodeCombinator { + r#match: Rc, + child: Option, + cursor: Cursor, + is_initialised: bool, +} + +impl NodeCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + Self { + r#match, + child: None, + cursor, + is_initialised: false, + } + } +} + +impl QueryEngineCombinator for NodeCombinator { + fn next(&mut self) -> Option { + if self.cursor.is_completed() { + return None; + } + + if !self.is_initialised { + self.is_initialised = true; + + if !self.cursor.matches_query_node_id(&self.r#match.id) { + return None; + } + + if let Some(child) = self.r#match.child.as_ref() { + let mut child_cursor = self.cursor.clone(); + if !child_cursor.go_to_first_child() { + return None; + } + + self.child = Some(child.create_qecref(child_cursor)); + } else { + let mut return_cursor = self.cursor.clone(); + return_cursor.consume(); + return Some(return_cursor); + } + } + + if let Some(child) = self.child.as_mut() { + while let Some(cursor) = child.as_mut().next() { + if cursor.is_completed() { + let mut return_cursor = self.cursor.clone(); + return_cursor.consume(); + return Some(return_cursor); + } + } + self.child = None; + } + + None + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + if let Some(child) = self.child.as_ref() { + child.accumulate_bindings(bindings); + } + } +} + +struct SequenceCombinator { + r#match: Rc, + children: Vec, + cursor: Cursor, + is_initialised: bool, +} + +impl SequenceCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + Self { + r#match, + children: vec![], + cursor, + is_initialised: false, + } + } +} + +impl QueryEngineCombinator for SequenceCombinator { + fn next(&mut self) -> Option { + if !self.is_initialised { + self.is_initialised = true; + + let child_cursor = self.cursor.clone(); + let child = self.r#match.children[0].create_qecref(child_cursor); + self.children.push(child); + } + + while !self.children.is_empty() { + if let Some(child_cursor) = self.children.last_mut().unwrap().next() { + if self.children.len() == self.r#match.children.len() { + return Some(child_cursor); + } + + let child = self.r#match.children[self.children.len()].create_qecref(child_cursor); + self.children.push(child); + } else { + self.children.pop(); + } + } + + None + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + for child in &self.children { + child.accumulate_bindings(bindings); + } + } +} + +struct AlternativesCombinator { + r#match: Rc, + next_child_number: usize, + child: Option, + cursor: Cursor, +} + +impl AlternativesCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + Self { + r#match, + next_child_number: 0, + child: None, + cursor, + } + } +} + +impl QueryEngineCombinator for AlternativesCombinator { + fn next(&mut self) -> Option { + loop { + if self.child.is_none() { + match self.r#match.children.get(self.next_child_number) { + Some(child) => { + let child = child.create_qecref(self.cursor.clone()); + self.child = Some(child); + self.next_child_number += 1; + } + None => return None, + } + } + + match self.child.as_mut().unwrap().next() { + Some(cursor) => return Some(cursor), + None => self.child = None, + } + } + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + self.child.as_ref().unwrap().accumulate_bindings(bindings); + } +} + +struct OptionalCombinator { + r#match: Rc, + child: Option, + cursor: Cursor, + have_nonempty_match: bool, +} + +impl OptionalCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + Self { + r#match, + child: None, + cursor, + have_nonempty_match: false, + } + } +} + +impl QueryEngineCombinator for OptionalCombinator { + fn next(&mut self) -> Option { + if let Some(child) = self.child.as_mut() { + match child.next() { + result @ Some(_) => { + self.have_nonempty_match = true; + result + } + None => { + self.child = None; + None + } + } + } else { + let child_cursor = self.cursor.clone(); + let child = self.r#match.child.create_qecref(child_cursor); + self.child = Some(child); + Some(self.cursor.clone()) + } + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + if self.have_nonempty_match { + if let Some(child) = self.child.as_ref() { + child.accumulate_bindings(bindings); + } + } + } +} + +struct OneOrMoreCombinator { + r#match: Rc, + children: Vec, + cursor_for_next_repetition: Option, +} + +impl OneOrMoreCombinator { + fn new(r#match: Rc, cursor: Cursor) -> Self { + let cursor_for_next_repetition = Some(cursor); + Self { + r#match, + children: vec![], + cursor_for_next_repetition, + } + } +} + +impl QueryEngineCombinator for OneOrMoreCombinator { + fn next(&mut self) -> Option { + loop { + if let Some(cursor_for_next_repetition) = self.cursor_for_next_repetition.take() { + let next_child = self.r#match.child.create_qecref(cursor_for_next_repetition); + self.children.push(next_child); + } else { + let tail = self.children.last_mut().unwrap(); + if let Some(cursor) = tail.next() { + if !cursor.is_completed() { + self.cursor_for_next_repetition = Some(cursor.clone()); + } + return Some(cursor); + } + self.children.pop(); + if self.children.is_empty() { + return None; + } + } + } + } + + fn accumulate_bindings(&self, bindings: &mut HashMap>) { + for child in &self.children { + child.accumulate_bindings(bindings); + } + } +} + +struct EllipsisCombinator { + cursor: Cursor, + has_returned_initial_empty_value: bool, +} + +impl EllipsisCombinator { + fn new(cursor: Cursor) -> Self { + Self { + cursor, + has_returned_initial_empty_value: false, + } + } +} + +impl QueryEngineCombinator for EllipsisCombinator { + fn next(&mut self) -> Option { + if !self.has_returned_initial_empty_value { + self.has_returned_initial_empty_value = true; + return Some(self.cursor.clone()); + } + + if self.cursor.consume() { + return Some(self.cursor.clone()); + } + + None + } + + fn accumulate_bindings(&self, _bindings: &mut HashMap>) {} +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/query_model.rs b/crates/solidity/outputs/cargo/crate/src/generated/query_model.rs new file mode 100644 index 0000000000..0ae63a2c4d --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/query_model.rs @@ -0,0 +1,146 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::rc::Rc; + +use super::kinds::{FieldName, RuleKind, TokenKind}; + +#[derive(Clone)] +pub enum Query { + Binding(Rc), + Node(Rc), + Optional(Rc), + Alternatives(Rc), + Sequence(Rc), + OneOrMore(Rc), + Ellipsis, +} + +impl Query { + pub fn parse(text: &str) -> Result { + super::query_parser::parse_query(text) + } + + pub fn unparse(&self) -> String { + match self { + Self::Binding(binding) => { + format!("@{} {}", binding.name, binding.child.unparse()) + } + Self::Node(node) => { + if let Some(child) = &node.child { + format!("[{} {}]", node.id.unparse(), child.unparse()) + } else { + format!("[{}]", node.id.unparse()) + } + } + Self::Optional(optional) => { + format!("({})?", optional.child.unparse()) + } + Self::Alternatives(alternatives) => { + format!( + "({})", + alternatives + .children + .iter() + .map(|c| c.unparse()) + .collect::>() + .join(" | ") + ) + } + Self::Sequence(sequence) => sequence + .children + .iter() + .map(|c| c.unparse()) + .collect::>() + .join(" "), + Self::OneOrMore(one_or_more) => { + format!("({})+", one_or_more.child.unparse()) + } + Self::Ellipsis => "...".to_string(), + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Kind { + Rule(RuleKind), + Token(TokenKind), +} + +impl Kind { + fn unparse(self) -> String { + match self { + Kind::Rule(rule) => rule.to_string(), + Kind::Token(token) => token.to_string(), + } + } +} + +#[derive(Clone)] +pub enum NodeId { + Anonymous, + Kind { kind: Kind }, + String { string: String }, + Field { field: FieldName }, + FieldAndKind { field: FieldName, kind: Kind }, + FieldAndString { field: FieldName, string: String }, +} + +impl NodeId { + fn unparse(&self) -> String { + match self { + NodeId::Anonymous => "_".to_string(), + NodeId::Kind { kind } => kind.unparse(), + NodeId::String { string } => format!("\"{}\"", Self::escape_string(string)), + NodeId::Field { field } => field.to_string(), + NodeId::FieldAndKind { field, kind } => { + format!("{field}; {}", kind.unparse()) + } + NodeId::FieldAndString { field, string } => { + format!("{field}: \"{}\"", Self::escape_string(string)) + } + } + } + + fn escape_string(string: &str) -> String { + string + .chars() + .map(|c| match c { + '"' => "\\\"".to_string(), + '\\' => "\\\\".to_string(), + '\n' => "\\n".to_string(), + '\r' => "\\r".to_string(), + '\t' => "\\t".to_string(), + '\u{08}' => "\\b".to_string(), + '\u{0c}' => "\\f".to_string(), + _ if c.is_ascii_graphic() => c.to_string(), + _ => format!("\\u{{{:x}}}", c as u32), + }) + .collect::() + } +} + +pub struct BindingMatch { + pub name: String, + pub child: Query, +} + +pub struct NodeMatch { + pub id: NodeId, + pub child: Option, +} + +pub struct SequenceMatch { + pub children: Vec, +} + +pub struct AlternativesMatch { + pub children: Vec, +} + +pub struct OptionalMatch { + pub child: Query, +} + +pub struct OneOrMoreMatch { + pub child: Query, +} diff --git a/crates/solidity/outputs/cargo/crate/src/generated/query_parser.rs b/crates/solidity/outputs/cargo/crate/src/generated/query_parser.rs new file mode 100644 index 0000000000..87c5e44268 --- /dev/null +++ b/crates/solidity/outputs/cargo/crate/src/generated/query_parser.rs @@ -0,0 +1,259 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use std::rc::Rc; + +use nom::branch::alt; +use nom::bytes::complete::{is_not, tag, take_while, take_while1, take_while_m_n}; +use nom::character::complete::{char, multispace0, multispace1, satisfy}; +use nom::combinator::{all_consuming, map_opt, map_res, opt, recognize, value, verify}; +use nom::error::VerboseError; +use nom::multi::{fold_many0, many0, many1}; +use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::{Finish, IResult, Parser}; + +use super::kinds::{FieldName, RuleKind, TokenKind}; +use super::query_model::{ + AlternativesMatch, BindingMatch, Kind, NodeId, NodeMatch, OneOrMoreMatch, OptionalMatch, Query, + SequenceMatch, +}; + +pub(super) fn parse_query(input: &str) -> Result { + all_consuming(preceded( + multispace0, + opt(binding_name_token) + .and(alt(( + parse_node, + delimited( + token('('), + pair(parse_node, many1(preceded(token('|'), parse_node))), + token(')'), + ) + .map(|(first, rest)| { + let mut children = vec![first]; + children.extend(rest); + Query::Alternatives(Rc::new(AlternativesMatch { children })) + }), + ))) + .map(|(binding_name, child)| { + if let Some(name) = binding_name { + Query::Binding(Rc::new(BindingMatch { name, child })) + } else { + child + } + }), + )) + .parse(input) + .finish() + .map(|(_, query)| query) + .map_err(|e| e.to_string()) +} + +fn parse_node(i: &str) -> IResult<&str, Query, VerboseError<&str>> { + delimited( + token('['), + parse_node_id.and(many0(parse_match)), + token(']'), + ) + .map(|(id, mut children)| { + let child = if children.is_empty() { + None + } else if children.len() == 1 { + Some(children.pop().unwrap()) + } else { + Some(Query::Sequence(Rc::new(SequenceMatch { children }))) + }; + Query::Node(Rc::new(NodeMatch { id, child })) + }) + .parse(i) +} + +fn parse_node_id(input: &str) -> IResult<&str, NodeId, VerboseError<&str>> { + pub enum Tail { + Anonymous, + Kind(Kind), + String(String), + } + + opt(field_name_token) + .and(alt(( + token('_').map(|_| Tail::Anonymous), + kind_name_token.map(Tail::Kind), + string_token.map(Tail::String), + ))) + .map(|(field, tail)| match (field, tail) { + (None, Tail::Anonymous) => NodeId::Anonymous, + (None, Tail::Kind(kind)) => NodeId::Kind { kind }, + (None, Tail::String(string)) => NodeId::String { string }, + (Some(field), Tail::Anonymous) => NodeId::Field { field }, + (Some(field), Tail::Kind(kind)) => NodeId::FieldAndKind { field, kind }, + (Some(field), Tail::String(string)) => NodeId::FieldAndString { field, string }, + }) + .parse(input) +} + +#[derive(Clone)] +enum Quantifier { + ZeroOrOne, + ZeroOrMore, + OneOrMore, +} + +fn parse_match(input: &str) -> IResult<&str, Query, VerboseError<&str>> { + opt(binding_name_token) + .and(alt(( + parse_node, + pair( + delimited(token('('), many1(parse_match), token(')')), + parse_trailing_quantifier, + ) + .map(|(mut children, quantifier)| { + let child = if children.len() == 1 { + children.pop().unwrap() + } else { + Query::Sequence(Rc::new(SequenceMatch { children })) + }; + match quantifier { + Quantifier::ZeroOrOne => Query::Optional(Rc::new(OptionalMatch { child })), + Quantifier::ZeroOrMore => Query::Optional(Rc::new(OptionalMatch { + child: Query::OneOrMore(Rc::new(OneOrMoreMatch { child })), + })), + Quantifier::OneOrMore => Query::OneOrMore(Rc::new(OneOrMoreMatch { child })), + } + }), + delimited( + token('('), + pair(parse_match, many1(preceded(token('|'), parse_match))), + token(')'), + ) + .map(|(first, rest)| { + let mut children = vec![first]; + children.extend(rest); + Query::Alternatives(Rc::new(AlternativesMatch { children })) + }), + ellipsis_token.map(|_| Query::Ellipsis), + ))) + .map(|(binding, child)| { + if let Some(name) = binding { + Query::Binding(Rc::new(BindingMatch { name, child })) + } else { + child + } + }) + .parse(input) +} + +fn parse_trailing_quantifier(i: &str) -> IResult<&str, Quantifier, VerboseError<&str>> { + alt(( + value(Quantifier::ZeroOrOne, token('?')), + value(Quantifier::ZeroOrMore, token('*')), + value(Quantifier::OneOrMore, token('+')), + )) + .parse(i) +} + +fn raw_identifier(i: &str) -> IResult<&str, String, VerboseError<&str>> { + let identifier_head = satisfy(|c| c.is_alphabetic()); + let is_identifier_tail = |c: char| c == '_' || c.is_alphanumeric(); + recognize(alt(( + // single underscore is the anonymous syntax item, + // so we don't allow it as an identifier + char('_').and(take_while1(is_identifier_tail)), + identifier_head.and(take_while(is_identifier_tail)), + ))) + .map(|s: &str| s.to_string()) + .parse(i) +} + +fn binding_name_token(i: &str) -> IResult<&str, String, VerboseError<&str>> { + terminated(preceded(char('@'), raw_identifier), multispace0).parse(i) +} + +fn kind_name_token(i: &str) -> IResult<&str, Kind, VerboseError<&str>> { + terminated(raw_identifier, multispace0) + .map(|id| { + TokenKind::try_from(id.as_str()) + .map(Kind::Token) + .or_else(|_| RuleKind::try_from(id.as_str()).map(Kind::Rule)) + .unwrap() // TODO + }) + .parse(i) +} + +fn field_name_token(i: &str) -> IResult<&str, FieldName, VerboseError<&str>> { + terminated(raw_identifier, token(':')) + .map(|id| FieldName::try_from(id.as_str()).unwrap()) + .parse(i) +} + +fn string_token(i: &str) -> IResult<&str, String, VerboseError<&str>> { + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + enum Fragment<'a> { + EscapedChar(char), + SwallowedWhitespace, + UnescapedSequence(&'a str), + } + + let escaped_char = preceded( + char('\\'), + alt(( + map_opt( + map_res( + preceded( + char('u'), + delimited( + char('{'), + // 1 to 6 hex digits + take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit()), + char('}'), + ), + ), + // converted from hex + move |hex| u32::from_str_radix(hex, 16), + ), + // converted to a char + std::char::from_u32, + ), + value('\n', char('n')), + value('\r', char('r')), + value('\t', char('t')), + value('\u{08}', char('b')), + value('\u{0C}', char('f')), + value('\\', char('\\')), + value('"', char('"')), + )), + ) + .map(Fragment::EscapedChar); + + // any amount of whitespace, collapsed to nothing + let swallowed_whitespace = value( + Fragment::SwallowedWhitespace, + preceded(char('\\'), multispace1), + ); + + let unescaped_sequence = + verify(is_not("\"\\"), |s: &str| !s.is_empty()).map(Fragment::UnescapedSequence); + + let fragment = alt((unescaped_sequence, escaped_char, swallowed_whitespace)); + + delimited( + char('"'), + fold_many0(fragment, String::new, |mut string, fragment| { + match fragment { + Fragment::EscapedChar(c) => string.push(c), + Fragment::SwallowedWhitespace => {} + Fragment::UnescapedSequence(s) => string.push_str(s), + } + string + }), + char('"'), + ) + .parse(i) +} + +fn ellipsis_token(i: &str) -> IResult<&str, &str, VerboseError<&str>> { + terminated(tag("..."), multispace0).parse(i) +} + +fn token<'input>(c: char) -> impl Parser<&'input str, char, VerboseError<&'input str>> { + terminated(char(c), multispace0) +} diff --git a/crates/solidity/outputs/cargo/crate/src/main.rs b/crates/solidity/outputs/cargo/crate/src/main.rs index 6b3097f084..54dfb99241 100644 --- a/crates/solidity/outputs/cargo/crate/src/main.rs +++ b/crates/solidity/outputs/cargo/crate/src/main.rs @@ -13,7 +13,7 @@ use slang_solidity::language::Language; // This is a known issue, and we should remove this hack once there is a better solution from Cargo. // https://github.com/rust-lang/cargo/issues/1982 mod supress_api_dependencies { - use {ariadne as _, serde as _, strum as _, strum_macros as _, thiserror as _}; + use {ariadne as _, nom as _, serde as _, strum as _, strum_macros as _, thiserror as _}; } #[derive(ClapParser, Debug)] diff --git a/crates/solidity/outputs/npm/crate/Cargo.toml b/crates/solidity/outputs/npm/crate/Cargo.toml index 23645a4fa4..2ad579a655 100644 --- a/crates/solidity/outputs/npm/crate/Cargo.toml +++ b/crates/solidity/outputs/npm/crate/Cargo.toml @@ -27,6 +27,7 @@ napi-build = { workspace = true } ariadne = { workspace = true } napi = { workspace = true } napi-derive = { workspace = true } +nom = { workspace = true } semver = { workspace = true } serde = { workspace = true } slang_solidity = { workspace = true } diff --git a/crates/solidity/outputs/npm/crate/src/generated/napi/napi_ast_selectors.rs b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_ast_selectors.rs new file mode 100644 index 0000000000..782ed8ed7f --- /dev/null +++ b/crates/solidity/outputs/npm/crate/src/generated/napi/napi_ast_selectors.rs @@ -0,0 +1,2958 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +#![allow(clippy::too_many_lines)] + +use std::rc::Rc; + +use napi::{Env, JsObject}; +use napi_derive::napi; + +use crate::napi::napi_cst::{RuleNode, ToJS}; +use crate::napi::{RuleKind, RustNamedNode, RustNode, RustRuleNode, TokenKind}; + +// +// Sequences: +// + +#[napi( + namespace = "ast_internal", + ts_return_type = "Array", + catch_unwind +)] +pub fn select_sequence( + #[napi(ts_arg_type = "cst.RuleNode")] node: &RuleNode, + env: Env, +) -> Result>> { + let mut selector = Selector::new(node, env); + + let result = match node.kind() { + RuleKind::SourceUnit => selector.source_unit()?, + RuleKind::PragmaDirective => selector.pragma_directive()?, + RuleKind::ABICoderPragma => selector.abi_coder_pragma()?, + RuleKind::ExperimentalPragma => selector.experimental_pragma()?, + RuleKind::VersionPragma => selector.version_pragma()?, + RuleKind::VersionPragmaOrExpression => selector.version_pragma_or_expression()?, + RuleKind::VersionPragmaRangeExpression => selector.version_pragma_range_expression()?, + RuleKind::VersionPragmaPrefixExpression => selector.version_pragma_prefix_expression()?, + RuleKind::ImportDirective => selector.import_directive()?, + RuleKind::PathImport => selector.path_import()?, + RuleKind::NamedImport => selector.named_import()?, + RuleKind::ImportDeconstruction => selector.import_deconstruction()?, + RuleKind::ImportDeconstructionSymbol => selector.import_deconstruction_symbol()?, + RuleKind::ImportAlias => selector.import_alias()?, + RuleKind::UsingDirective => selector.using_directive()?, + RuleKind::UsingDeconstruction => selector.using_deconstruction()?, + RuleKind::UsingDeconstructionSymbol => selector.using_deconstruction_symbol()?, + RuleKind::UsingAlias => selector.using_alias()?, + RuleKind::ContractDefinition => selector.contract_definition()?, + RuleKind::InheritanceSpecifier => selector.inheritance_specifier()?, + RuleKind::InheritanceType => selector.inheritance_type()?, + RuleKind::InterfaceDefinition => selector.interface_definition()?, + RuleKind::LibraryDefinition => selector.library_definition()?, + RuleKind::StructDefinition => selector.struct_definition()?, + RuleKind::StructMember => selector.struct_member()?, + RuleKind::EnumDefinition => selector.enum_definition()?, + RuleKind::ConstantDefinition => selector.constant_definition()?, + RuleKind::StateVariableDefinition => selector.state_variable_definition()?, + RuleKind::StateVariableDefinitionValue => selector.state_variable_definition_value()?, + RuleKind::FunctionDefinition => selector.function_definition()?, + RuleKind::ParametersDeclaration => selector.parameters_declaration()?, + RuleKind::Parameter => selector.parameter()?, + RuleKind::OverrideSpecifier => selector.override_specifier()?, + RuleKind::OverridePathsDeclaration => selector.override_paths_declaration()?, + RuleKind::ReturnsDeclaration => selector.returns_declaration()?, + RuleKind::ConstructorDefinition => selector.constructor_definition()?, + RuleKind::UnnamedFunctionDefinition => selector.unnamed_function_definition()?, + RuleKind::FallbackFunctionDefinition => selector.fallback_function_definition()?, + RuleKind::ReceiveFunctionDefinition => selector.receive_function_definition()?, + RuleKind::ModifierDefinition => selector.modifier_definition()?, + RuleKind::ModifierInvocation => selector.modifier_invocation()?, + RuleKind::EventDefinition => selector.event_definition()?, + RuleKind::EventParametersDeclaration => selector.event_parameters_declaration()?, + RuleKind::EventParameter => selector.event_parameter()?, + RuleKind::UserDefinedValueTypeDefinition => { + selector.user_defined_value_type_definition()? + } + RuleKind::ErrorDefinition => selector.error_definition()?, + RuleKind::ErrorParametersDeclaration => selector.error_parameters_declaration()?, + RuleKind::ErrorParameter => selector.error_parameter()?, + RuleKind::ArrayTypeName => selector.array_type_name()?, + RuleKind::FunctionType => selector.function_type()?, + RuleKind::MappingType => selector.mapping_type()?, + RuleKind::MappingKey => selector.mapping_key()?, + RuleKind::MappingValue => selector.mapping_value()?, + RuleKind::AddressType => selector.address_type()?, + RuleKind::Block => selector.block()?, + RuleKind::UncheckedBlock => selector.unchecked_block()?, + RuleKind::ExpressionStatement => selector.expression_statement()?, + RuleKind::AssemblyStatement => selector.assembly_statement()?, + RuleKind::AssemblyFlagsDeclaration => selector.assembly_flags_declaration()?, + RuleKind::TupleDeconstructionStatement => selector.tuple_deconstruction_statement()?, + RuleKind::TupleDeconstructionElement => selector.tuple_deconstruction_element()?, + RuleKind::TypedTupleMember => selector.typed_tuple_member()?, + RuleKind::UntypedTupleMember => selector.untyped_tuple_member()?, + RuleKind::VariableDeclarationStatement => selector.variable_declaration_statement()?, + RuleKind::VariableDeclarationValue => selector.variable_declaration_value()?, + RuleKind::IfStatement => selector.if_statement()?, + RuleKind::ElseBranch => selector.else_branch()?, + RuleKind::ForStatement => selector.for_statement()?, + RuleKind::WhileStatement => selector.while_statement()?, + RuleKind::DoWhileStatement => selector.do_while_statement()?, + RuleKind::ContinueStatement => selector.continue_statement()?, + RuleKind::BreakStatement => selector.break_statement()?, + RuleKind::ReturnStatement => selector.return_statement()?, + RuleKind::EmitStatement => selector.emit_statement()?, + RuleKind::DeleteStatement => selector.delete_statement()?, + RuleKind::TryStatement => selector.try_statement()?, + RuleKind::CatchClause => selector.catch_clause()?, + RuleKind::CatchClauseError => selector.catch_clause_error()?, + RuleKind::RevertStatement => selector.revert_statement()?, + RuleKind::ThrowStatement => selector.throw_statement()?, + RuleKind::AssignmentExpression => selector.assignment_expression()?, + RuleKind::ConditionalExpression => selector.conditional_expression()?, + RuleKind::OrExpression => selector.or_expression()?, + RuleKind::AndExpression => selector.and_expression()?, + RuleKind::EqualityExpression => selector.equality_expression()?, + RuleKind::ComparisonExpression => selector.comparison_expression()?, + RuleKind::BitwiseOrExpression => selector.bitwise_or_expression()?, + RuleKind::BitwiseXorExpression => selector.bitwise_xor_expression()?, + RuleKind::BitwiseAndExpression => selector.bitwise_and_expression()?, + RuleKind::ShiftExpression => selector.shift_expression()?, + RuleKind::AdditiveExpression => selector.additive_expression()?, + RuleKind::MultiplicativeExpression => selector.multiplicative_expression()?, + RuleKind::ExponentiationExpression => selector.exponentiation_expression()?, + RuleKind::PostfixExpression => selector.postfix_expression()?, + RuleKind::PrefixExpression => selector.prefix_expression()?, + RuleKind::FunctionCallExpression => selector.function_call_expression()?, + RuleKind::MemberAccessExpression => selector.member_access_expression()?, + RuleKind::IndexAccessExpression => selector.index_access_expression()?, + RuleKind::IndexAccessEnd => selector.index_access_end()?, + RuleKind::PositionalArgumentsDeclaration => selector.positional_arguments_declaration()?, + RuleKind::NamedArgumentsDeclaration => selector.named_arguments_declaration()?, + RuleKind::NamedArgumentGroup => selector.named_argument_group()?, + RuleKind::NamedArgument => selector.named_argument()?, + RuleKind::TypeExpression => selector.type_expression()?, + RuleKind::NewExpression => selector.new_expression()?, + RuleKind::TupleExpression => selector.tuple_expression()?, + RuleKind::TupleValue => selector.tuple_value()?, + RuleKind::ArrayExpression => selector.array_expression()?, + RuleKind::HexNumberExpression => selector.hex_number_expression()?, + RuleKind::DecimalNumberExpression => selector.decimal_number_expression()?, + RuleKind::YulBlock => selector.yul_block()?, + RuleKind::YulFunctionDefinition => selector.yul_function_definition()?, + RuleKind::YulParametersDeclaration => selector.yul_parameters_declaration()?, + RuleKind::YulReturnsDeclaration => selector.yul_returns_declaration()?, + RuleKind::YulVariableDeclarationStatement => { + selector.yul_variable_declaration_statement()? + } + RuleKind::YulVariableDeclarationValue => selector.yul_variable_declaration_value()?, + RuleKind::YulAssignmentStatement => selector.yul_assignment_statement()?, + RuleKind::YulIfStatement => selector.yul_if_statement()?, + RuleKind::YulLeaveStatement => selector.yul_leave_statement()?, + RuleKind::YulBreakStatement => selector.yul_break_statement()?, + RuleKind::YulContinueStatement => selector.yul_continue_statement()?, + RuleKind::YulForStatement => selector.yul_for_statement()?, + RuleKind::YulSwitchStatement => selector.yul_switch_statement()?, + RuleKind::YulDefaultCase => selector.yul_default_case()?, + RuleKind::YulValueCase => selector.yul_value_case()?, + RuleKind::YulFunctionCallExpression => selector.yul_function_call_expression()?, + _ => { + return Error::UnexpectedParent(node.kind()).into(); + } + }; + + selector.finalize()?; + Ok(result) +} + +impl Selector { + fn source_unit(&mut self) -> Result>> { + Ok(vec![self.try_select(|node| { + node.is_rule_with_kind(RuleKind::SourceUnitMembers) + })?]) + } +} + +impl Selector { + fn pragma_directive(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::PragmaKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Pragma))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn abi_coder_pragma(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::AbicoderKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + ]) + } +} + +impl Selector { + fn experimental_pragma(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ExperimentalKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ExperimentalFeature))?), + ]) + } +} + +impl Selector { + fn version_pragma(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::SolidityKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::VersionPragmaExpressions))?), + ]) + } +} + +impl Selector { + fn version_pragma_or_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::VersionPragmaExpression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::BarBar))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::VersionPragmaExpression))?), + ]) + } +} + +impl Selector { + fn version_pragma_range_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::VersionPragmaExpression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Minus))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::VersionPragmaExpression))?), + ]) + } +} + +impl Selector { + fn version_pragma_prefix_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::VersionPragmaExpression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Caret))?), + ]) + } +} + +impl Selector { + fn import_directive(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ImportKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ImportClause))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn path_import(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::AsciiStringLiteral))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ImportAlias))?, + ]) + } +} + +impl Selector { + fn named_import(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::Asterisk))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ImportAlias))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::FromKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::AsciiStringLiteral))?), + ]) + } +} + +impl Selector { + fn import_deconstruction(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + Some( + self.select(|node| node.is_rule_with_kind(RuleKind::ImportDeconstructionSymbols))?, + ), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::FromKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::AsciiStringLiteral))?), + ]) + } +} + +impl Selector { + fn import_deconstruction_symbol(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ImportAlias))?, + ]) + } +} + +impl Selector { + fn import_alias(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::AsKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + ]) + } +} + +impl Selector { + fn using_directive(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::UsingKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::UsingClause))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::ForKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::UsingTarget))?), + self.try_select(|node| node.is_token_with_kind(TokenKind::GlobalKeyword))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn using_deconstruction(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::UsingDeconstructionSymbols))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn using_deconstruction_symbol(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::IdentifierPath))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::UsingAlias))?, + ]) + } +} + +impl Selector { + fn using_alias(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::AsKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::UsingOperator))?), + ]) + } +} + +impl Selector { + fn contract_definition(&mut self) -> Result>> { + Ok(vec![ + self.try_select(|node| node.is_token_with_kind(TokenKind::AbstractKeyword))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::ContractKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::InheritanceSpecifier))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ContractMembers))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn inheritance_specifier(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::IsKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::InheritanceTypes))?), + ]) + } +} + +impl Selector { + fn inheritance_type(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::IdentifierPath))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ArgumentsDeclaration))?, + ]) + } +} + +impl Selector { + fn interface_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::InterfaceKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::InheritanceSpecifier))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::InterfaceMembers))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn library_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::LibraryKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::LibraryMembers))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn struct_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::StructKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::StructMembers))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn struct_member(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn enum_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::EnumKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::EnumMembers))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn constant_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::ConstantKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Equal))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn state_variable_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::StateVariableAttributes))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::StateVariableDefinitionValue))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn state_variable_definition_value(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::Equal))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn function_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::FunctionKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::FunctionName))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::FunctionAttributes))?, + self.try_select(|node| node.is_rule_with_kind(RuleKind::ReturnsDeclaration))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::FunctionBody))?), + ]) + } +} + +impl Selector { + fn parameters_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::Parameters))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn parameter(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::StorageLocation))?, + self.try_select(|node| node.is_token_with_kind(TokenKind::Identifier))?, + ]) + } +} + +impl Selector { + fn override_specifier(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OverrideKeyword))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::OverridePathsDeclaration))?, + ]) + } +} + +impl Selector { + fn override_paths_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::OverridePaths))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn returns_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ReturnsKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?), + ]) + } +} + +impl Selector { + fn constructor_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ConstructorKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ConstructorAttributes))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Block))?), + ]) + } +} + +impl Selector { + fn unnamed_function_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::FunctionKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::UnnamedFunctionAttributes))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::FunctionBody))?), + ]) + } +} + +impl Selector { + fn fallback_function_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::FallbackKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::FallbackFunctionAttributes))?, + self.try_select(|node| node.is_rule_with_kind(RuleKind::ReturnsDeclaration))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::FunctionBody))?), + ]) + } +} + +impl Selector { + fn receive_function_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ReceiveKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ReceiveFunctionAttributes))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::FunctionBody))?), + ]) + } +} + +impl Selector { + fn modifier_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ModifierKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?, + self.try_select(|node| node.is_rule_with_kind(RuleKind::ModifierAttributes))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::FunctionBody))?), + ]) + } +} + +impl Selector { + fn modifier_invocation(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::IdentifierPath))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ArgumentsDeclaration))?, + ]) + } +} + +impl Selector { + fn event_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::EventKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::EventParametersDeclaration))?), + self.try_select(|node| node.is_token_with_kind(TokenKind::AnonymousKeyword))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn event_parameters_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::EventParameters))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn event_parameter(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + self.try_select(|node| node.is_token_with_kind(TokenKind::IndexedKeyword))?, + self.try_select(|node| node.is_token_with_kind(TokenKind::Identifier))?, + ]) + } +} + +impl Selector { + fn user_defined_value_type_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::TypeKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::IsKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ElementaryType))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn error_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ErrorKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ErrorParametersDeclaration))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn error_parameters_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ErrorParameters))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn error_parameter(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + self.try_select(|node| node.is_token_with_kind(TokenKind::Identifier))?, + ]) + } +} + +impl Selector { + fn array_type_name(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBracket))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::Expression))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBracket))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + ]) + } +} + +impl Selector { + fn function_type(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::FunctionKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::FunctionTypeAttributes))?, + self.try_select(|node| node.is_rule_with_kind(RuleKind::ReturnsDeclaration))?, + ]) + } +} + +impl Selector { + fn mapping_type(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::MappingKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::MappingKey))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::EqualGreaterThan))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::MappingValue))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn mapping_key(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::MappingKeyType))?), + self.try_select(|node| node.is_token_with_kind(TokenKind::Identifier))?, + ]) + } +} + +impl Selector { + fn mapping_value(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + self.try_select(|node| node.is_token_with_kind(TokenKind::Identifier))?, + ]) + } +} + +impl Selector { + fn address_type(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::AddressKeyword))?), + self.try_select(|node| node.is_token_with_kind(TokenKind::PayableKeyword))?, + ]) + } +} + +impl Selector { + fn block(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::Statements))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn unchecked_block(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::UncheckedKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Block))?), + ]) + } +} + +impl Selector { + fn expression_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn assembly_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::AssemblyKeyword))?), + self.try_select(|node| node.is_token_with_kind(TokenKind::AsciiStringLiteral))?, + self.try_select(|node| node.is_rule_with_kind(RuleKind::AssemblyFlagsDeclaration))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulBlock))?), + ]) + } +} + +impl Selector { + fn assembly_flags_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::AssemblyFlags))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn tuple_deconstruction_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some( + self.select(|node| node.is_rule_with_kind(RuleKind::TupleDeconstructionElements))?, + ), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Equal))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn tuple_deconstruction_element(&mut self) -> Result>> { + Ok(vec![self.try_select(|node| { + node.is_rule_with_kind(RuleKind::TupleMember) + })?]) + } +} + +impl Selector { + fn typed_tuple_member(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::StorageLocation))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + ]) + } +} + +impl Selector { + fn untyped_tuple_member(&mut self) -> Result>> { + Ok(vec![ + self.try_select(|node| node.is_rule_with_kind(RuleKind::StorageLocation))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + ]) + } +} + +impl Selector { + fn variable_declaration_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::VariableDeclarationType))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::StorageLocation))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::VariableDeclarationValue))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn variable_declaration_value(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::Equal))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn if_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::IfKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Statement))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ElseBranch))?, + ]) + } +} + +impl Selector { + fn else_branch(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ElseKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Statement))?), + ]) + } +} + +impl Selector { + fn for_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ForKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ForStatementInitialization))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ForStatementCondition))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::Expression))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Statement))?), + ]) + } +} + +impl Selector { + fn while_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::WhileKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Statement))?), + ]) + } +} + +impl Selector { + fn do_while_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::DoKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Statement))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::WhileKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn continue_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ContinueKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn break_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::BreakKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn return_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ReturnKeyword))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::Expression))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn emit_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::EmitKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::IdentifierPath))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ArgumentsDeclaration))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn delete_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::DeleteKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn try_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::TryKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::ReturnsDeclaration))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Block))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::CatchClauses))?), + ]) + } +} + +impl Selector { + fn catch_clause(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::CatchKeyword))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::CatchClauseError))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Block))?), + ]) + } +} + +impl Selector { + fn catch_clause_error(&mut self) -> Result>> { + Ok(vec![ + self.try_select(|node| node.is_token_with_kind(TokenKind::Identifier))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ParametersDeclaration))?), + ]) + } +} + +impl Selector { + fn revert_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::RevertKeyword))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::IdentifierPath))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ArgumentsDeclaration))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn throw_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ThrowKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Semicolon))?), + ]) + } +} + +impl Selector { + fn assignment_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Equal))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn conditional_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::QuestionMark))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Colon))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn or_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::BarBar))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn and_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::AmpersandAmpersand))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn equality_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::EqualEqual))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn comparison_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::LessThan))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn bitwise_or_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Bar))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn bitwise_xor_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Caret))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn bitwise_and_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Ampersand))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn shift_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::LessThanLessThan))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn additive_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Plus))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn multiplicative_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Asterisk))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn exponentiation_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::AsteriskAsterisk))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn postfix_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::PlusPlus))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn prefix_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::PlusPlus))?), + ]) + } +} + +impl Selector { + fn function_call_expression(&mut self) -> Result>> { + Ok(vec![ + self.try_select(|node| node.is_rule_with_kind(RuleKind::FunctionCallOptions))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ArgumentsDeclaration))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn member_access_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::Period))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::MemberAccess))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn index_access_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBracket))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::Expression))?, + self.try_select(|node| node.is_rule_with_kind(RuleKind::IndexAccessEnd))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBracket))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn index_access_end(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::Colon))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::Expression))?, + ]) + } +} + +impl Selector { + fn positional_arguments_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::PositionalArguments))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn named_arguments_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::NamedArgumentGroup))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn named_argument_group(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::NamedArguments))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn named_argument(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::Colon))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?), + ]) + } +} + +impl Selector { + fn type_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::TypeKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn new_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::NewKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), + ]) + } +} + +impl Selector { + fn tuple_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::TupleValues))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn tuple_value(&mut self) -> Result>> { + Ok(vec![self.try_select(|node| { + node.is_rule_with_kind(RuleKind::Expression) + })?]) + } +} + +impl Selector { + fn array_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBracket))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::ArrayValues))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBracket))?), + ]) + } +} + +impl Selector { + fn hex_number_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::HexLiteral))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::NumberUnit))?, + ]) + } +} + +impl Selector { + fn decimal_number_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::DecimalLiteral))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::NumberUnit))?, + ]) + } +} + +impl Selector { + fn yul_block(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenBrace))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::YulStatements))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseBrace))?), + ]) + } +} + +impl Selector { + fn yul_function_definition(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::YulFunctionKeyword))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::YulIdentifier))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulParametersDeclaration))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::YulReturnsDeclaration))?, + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulBlock))?), + ]) + } +} + +impl Selector { + fn yul_parameters_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::YulParameters))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + ]) + } +} + +impl Selector { + fn yul_returns_declaration(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::MinusGreaterThan))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulReturnVariables))?), + ]) + } +} + +impl Selector { + fn yul_variable_declaration_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::YulLetKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulIdentifierPaths))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::YulVariableDeclarationValue))?, + ]) + } +} + +impl Selector { + fn yul_variable_declaration_value(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::ColonEqual))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulExpression))?), + ]) + } +} + +impl Selector { + fn yul_assignment_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulIdentifierPaths))?), + Some(self.select(|node| node.is_token_with_kind(TokenKind::ColonEqual))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulExpression))?), + ]) + } +} + +impl Selector { + fn yul_if_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::YulIfKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulExpression))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulBlock))?), + ]) + } +} + +impl Selector { + fn yul_leave_statement(&mut self) -> Result>> { + Ok(vec![Some(self.select(|node| { + node.is_token_with_kind(TokenKind::YulLeaveKeyword) + })?)]) + } +} + +impl Selector { + fn yul_break_statement(&mut self) -> Result>> { + Ok(vec![Some(self.select(|node| { + node.is_token_with_kind(TokenKind::YulBreakKeyword) + })?)]) + } +} + +impl Selector { + fn yul_continue_statement(&mut self) -> Result>> { + Ok(vec![Some(self.select(|node| { + node.is_token_with_kind(TokenKind::YulContinueKeyword) + })?)]) + } +} + +impl Selector { + fn yul_for_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::YulForKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulBlock))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulExpression))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulBlock))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulBlock))?), + ]) + } +} + +impl Selector { + fn yul_switch_statement(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::YulSwitchKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulExpression))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulSwitchCases))?), + ]) + } +} + +impl Selector { + fn yul_default_case(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::YulDefaultKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulBlock))?), + ]) + } +} + +impl Selector { + fn yul_value_case(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::YulCaseKeyword))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulLiteral))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulBlock))?), + ]) + } +} + +impl Selector { + fn yul_function_call_expression(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::OpenParen))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::YulArguments))?, + Some(self.select(|node| node.is_token_with_kind(TokenKind::CloseParen))?), + Some(self.select(|node| node.is_rule_with_kind(RuleKind::YulExpression))?), + ]) + } +} + +// +// Choices: +// + +#[napi(namespace = "ast_internal", ts_return_type = "cst.Node", catch_unwind)] +pub fn select_choice( + #[napi(ts_arg_type = "cst.RuleNode")] node: &RuleNode, + env: Env, +) -> Result { + let mut selector = Selector::new(node, env); + + let result = match node.kind() { + RuleKind::SourceUnitMember => selector.source_unit_member()?, + RuleKind::Pragma => selector.pragma()?, + RuleKind::ExperimentalFeature => selector.experimental_feature()?, + RuleKind::VersionPragmaExpression => selector.version_pragma_expression()?, + RuleKind::ImportClause => selector.import_clause()?, + RuleKind::UsingClause => selector.using_clause()?, + RuleKind::UsingOperator => selector.using_operator()?, + RuleKind::UsingTarget => selector.using_target()?, + RuleKind::ContractMember => selector.contract_member()?, + RuleKind::StateVariableAttribute => selector.state_variable_attribute()?, + RuleKind::FunctionName => selector.function_name()?, + RuleKind::FunctionAttribute => selector.function_attribute()?, + RuleKind::FunctionBody => selector.function_body()?, + RuleKind::ConstructorAttribute => selector.constructor_attribute()?, + RuleKind::UnnamedFunctionAttribute => selector.unnamed_function_attribute()?, + RuleKind::FallbackFunctionAttribute => selector.fallback_function_attribute()?, + RuleKind::ReceiveFunctionAttribute => selector.receive_function_attribute()?, + RuleKind::ModifierAttribute => selector.modifier_attribute()?, + RuleKind::TypeName => selector.type_name()?, + RuleKind::FunctionTypeAttribute => selector.function_type_attribute()?, + RuleKind::MappingKeyType => selector.mapping_key_type()?, + RuleKind::ElementaryType => selector.elementary_type()?, + RuleKind::Statement => selector.statement()?, + RuleKind::TupleMember => selector.tuple_member()?, + RuleKind::VariableDeclarationType => selector.variable_declaration_type()?, + RuleKind::StorageLocation => selector.storage_location()?, + RuleKind::ForStatementInitialization => selector.for_statement_initialization()?, + RuleKind::ForStatementCondition => selector.for_statement_condition()?, + RuleKind::Expression => selector.expression()?, + RuleKind::MemberAccess => selector.member_access()?, + RuleKind::FunctionCallOptions => selector.function_call_options()?, + RuleKind::ArgumentsDeclaration => selector.arguments_declaration()?, + RuleKind::NumberUnit => selector.number_unit()?, + RuleKind::StringExpression => selector.string_expression()?, + RuleKind::YulStatement => selector.yul_statement()?, + RuleKind::YulSwitchCase => selector.yul_switch_case()?, + RuleKind::YulExpression => selector.yul_expression()?, + RuleKind::YulLiteral => selector.yul_literal()?, + _ => { + return Error::UnexpectedParent(node.kind()).into(); + } + }; + + selector.finalize()?; + Ok(result) +} + +impl Selector { + fn source_unit_member(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::PragmaDirective, + RuleKind::ImportDirective, + RuleKind::ContractDefinition, + RuleKind::InterfaceDefinition, + RuleKind::LibraryDefinition, + RuleKind::StructDefinition, + RuleKind::EnumDefinition, + RuleKind::FunctionDefinition, + RuleKind::ConstantDefinition, + RuleKind::ErrorDefinition, + RuleKind::UserDefinedValueTypeDefinition, + RuleKind::UsingDirective, + RuleKind::EventDefinition, + ]) + }) + } +} + +impl Selector { + fn pragma(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::ABICoderPragma, + RuleKind::ExperimentalPragma, + RuleKind::VersionPragma, + ]) + }) + } +} + +impl Selector { + fn experimental_feature(&mut self) -> Result { + self.select(|node| { + node.is_token_with_kinds(&[TokenKind::Identifier, TokenKind::AsciiStringLiteral]) + }) + } +} + +impl Selector { + fn version_pragma_expression(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::VersionPragmaOrExpression, + RuleKind::VersionPragmaRangeExpression, + RuleKind::VersionPragmaPrefixExpression, + RuleKind::VersionPragmaSpecifier, + ]) + }) + } +} + +impl Selector { + fn import_clause(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::PathImport, + RuleKind::NamedImport, + RuleKind::ImportDeconstruction, + ]) + }) + } +} + +impl Selector { + fn using_clause(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::IdentifierPath, RuleKind::UsingDeconstruction]) + }) + } +} + +impl Selector { + fn using_operator(&mut self) -> Result { + self.select(|node| { + node.is_token_with_kinds(&[ + TokenKind::Ampersand, + TokenKind::Asterisk, + TokenKind::BangEqual, + TokenKind::Bar, + TokenKind::Caret, + TokenKind::EqualEqual, + TokenKind::GreaterThan, + TokenKind::GreaterThanEqual, + TokenKind::LessThan, + TokenKind::LessThanEqual, + TokenKind::Minus, + TokenKind::Percent, + TokenKind::Plus, + TokenKind::Slash, + TokenKind::Tilde, + ]) + }) + } +} + +impl Selector { + fn using_target(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kind(RuleKind::TypeName) + || node.is_token_with_kind(TokenKind::Asterisk) + }) + } +} + +impl Selector { + fn contract_member(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::UsingDirective, + RuleKind::FunctionDefinition, + RuleKind::ConstructorDefinition, + RuleKind::ReceiveFunctionDefinition, + RuleKind::FallbackFunctionDefinition, + RuleKind::UnnamedFunctionDefinition, + RuleKind::ModifierDefinition, + RuleKind::StructDefinition, + RuleKind::EnumDefinition, + RuleKind::EventDefinition, + RuleKind::StateVariableDefinition, + RuleKind::ErrorDefinition, + RuleKind::UserDefinedValueTypeDefinition, + ]) + }) + } +} + +impl Selector { + fn state_variable_attribute(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kind(RuleKind::OverrideSpecifier) + || node.is_token_with_kinds(&[ + TokenKind::ConstantKeyword, + TokenKind::InternalKeyword, + TokenKind::PrivateKeyword, + TokenKind::PublicKeyword, + TokenKind::ImmutableKeyword, + ]) + }) + } +} + +impl Selector { + fn function_name(&mut self) -> Result { + self.select(|node| { + node.is_token_with_kinds(&[ + TokenKind::Identifier, + TokenKind::FallbackKeyword, + TokenKind::ReceiveKeyword, + ]) + }) + } +} + +impl Selector { + fn function_attribute(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::ModifierInvocation, RuleKind::OverrideSpecifier]) + || node.is_token_with_kinds(&[ + TokenKind::ConstantKeyword, + TokenKind::ExternalKeyword, + TokenKind::InternalKeyword, + TokenKind::PayableKeyword, + TokenKind::PrivateKeyword, + TokenKind::PublicKeyword, + TokenKind::PureKeyword, + TokenKind::ViewKeyword, + TokenKind::VirtualKeyword, + ]) + }) + } +} + +impl Selector { + fn function_body(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kind(RuleKind::Block) || node.is_token_with_kind(TokenKind::Semicolon) + }) + } +} + +impl Selector { + fn constructor_attribute(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kind(RuleKind::ModifierInvocation) + || node.is_token_with_kinds(&[ + TokenKind::InternalKeyword, + TokenKind::PayableKeyword, + TokenKind::PublicKeyword, + ]) + }) + } +} + +impl Selector { + fn unnamed_function_attribute(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::ModifierInvocation, RuleKind::OverrideSpecifier]) + || node.is_token_with_kinds(&[ + TokenKind::ExternalKeyword, + TokenKind::PayableKeyword, + TokenKind::PureKeyword, + TokenKind::ViewKeyword, + ]) + }) + } +} + +impl Selector { + fn fallback_function_attribute(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::ModifierInvocation, RuleKind::OverrideSpecifier]) + || node.is_token_with_kinds(&[ + TokenKind::ExternalKeyword, + TokenKind::PayableKeyword, + TokenKind::PureKeyword, + TokenKind::ViewKeyword, + TokenKind::VirtualKeyword, + ]) + }) + } +} + +impl Selector { + fn receive_function_attribute(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::ModifierInvocation, RuleKind::OverrideSpecifier]) + || node.is_token_with_kinds(&[ + TokenKind::ExternalKeyword, + TokenKind::PayableKeyword, + TokenKind::VirtualKeyword, + ]) + }) + } +} + +impl Selector { + fn modifier_attribute(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kind(RuleKind::OverrideSpecifier) + || node.is_token_with_kind(TokenKind::VirtualKeyword) + }) + } +} + +impl Selector { + fn type_name(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::ArrayTypeName, + RuleKind::FunctionType, + RuleKind::MappingType, + RuleKind::ElementaryType, + RuleKind::IdentifierPath, + ]) + }) + } +} + +impl Selector { + fn function_type_attribute(&mut self) -> Result { + self.select(|node| { + node.is_token_with_kinds(&[ + TokenKind::InternalKeyword, + TokenKind::ExternalKeyword, + TokenKind::PrivateKeyword, + TokenKind::PublicKeyword, + TokenKind::PureKeyword, + TokenKind::ViewKeyword, + TokenKind::PayableKeyword, + ]) + }) + } +} + +impl Selector { + fn mapping_key_type(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::ElementaryType, RuleKind::IdentifierPath]) + }) + } +} + +impl Selector { + fn elementary_type(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kind(RuleKind::AddressType) + || node.is_token_with_kinds(&[ + TokenKind::BoolKeyword, + TokenKind::ByteKeyword, + TokenKind::StringKeyword, + TokenKind::PayableKeyword, + TokenKind::BytesKeyword, + TokenKind::IntKeyword, + TokenKind::UintKeyword, + TokenKind::FixedKeyword, + TokenKind::UfixedKeyword, + ]) + }) + } +} + +impl Selector { + fn statement(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::ExpressionStatement, + RuleKind::VariableDeclarationStatement, + RuleKind::TupleDeconstructionStatement, + RuleKind::IfStatement, + RuleKind::ForStatement, + RuleKind::WhileStatement, + RuleKind::DoWhileStatement, + RuleKind::ContinueStatement, + RuleKind::BreakStatement, + RuleKind::DeleteStatement, + RuleKind::ReturnStatement, + RuleKind::ThrowStatement, + RuleKind::EmitStatement, + RuleKind::TryStatement, + RuleKind::RevertStatement, + RuleKind::AssemblyStatement, + RuleKind::Block, + RuleKind::UncheckedBlock, + ]) + }) + } +} + +impl Selector { + fn tuple_member(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::TypedTupleMember, RuleKind::UntypedTupleMember]) + }) + } +} + +impl Selector { + fn variable_declaration_type(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kind(RuleKind::TypeName) + || node.is_token_with_kind(TokenKind::VarKeyword) + }) + } +} + +impl Selector { + fn storage_location(&mut self) -> Result { + self.select(|node| { + node.is_token_with_kinds(&[ + TokenKind::MemoryKeyword, + TokenKind::StorageKeyword, + TokenKind::CallDataKeyword, + ]) + }) + } +} + +impl Selector { + fn for_statement_initialization(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::ExpressionStatement, + RuleKind::VariableDeclarationStatement, + RuleKind::TupleDeconstructionStatement, + ]) || node.is_token_with_kind(TokenKind::Semicolon) + }) + } +} + +impl Selector { + fn for_statement_condition(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kind(RuleKind::ExpressionStatement) + || node.is_token_with_kind(TokenKind::Semicolon) + }) + } +} + +impl Selector { + fn expression(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::AssignmentExpression, + RuleKind::ConditionalExpression, + RuleKind::OrExpression, + RuleKind::AndExpression, + RuleKind::EqualityExpression, + RuleKind::ComparisonExpression, + RuleKind::BitwiseOrExpression, + RuleKind::BitwiseXorExpression, + RuleKind::BitwiseAndExpression, + RuleKind::ShiftExpression, + RuleKind::AdditiveExpression, + RuleKind::MultiplicativeExpression, + RuleKind::ExponentiationExpression, + RuleKind::PostfixExpression, + RuleKind::PrefixExpression, + RuleKind::FunctionCallExpression, + RuleKind::MemberAccessExpression, + RuleKind::IndexAccessExpression, + RuleKind::NewExpression, + RuleKind::TupleExpression, + RuleKind::TypeExpression, + RuleKind::ArrayExpression, + RuleKind::HexNumberExpression, + RuleKind::DecimalNumberExpression, + RuleKind::StringExpression, + RuleKind::ElementaryType, + ]) || node.is_token_with_kinds(&[ + TokenKind::TrueKeyword, + TokenKind::FalseKeyword, + TokenKind::Identifier, + ]) + }) + } +} + +impl Selector { + fn member_access(&mut self) -> Result { + self.select(|node| { + node.is_token_with_kinds(&[TokenKind::Identifier, TokenKind::AddressKeyword]) + }) + } +} + +impl Selector { + fn function_call_options(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::NamedArgumentGroups, RuleKind::NamedArgumentGroup]) + }) + } +} + +impl Selector { + fn arguments_declaration(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::PositionalArgumentsDeclaration, + RuleKind::NamedArgumentsDeclaration, + ]) + }) + } +} + +impl Selector { + fn number_unit(&mut self) -> Result { + self.select(|node| { + node.is_token_with_kinds(&[ + TokenKind::WeiKeyword, + TokenKind::GweiKeyword, + TokenKind::SzaboKeyword, + TokenKind::FinneyKeyword, + TokenKind::EtherKeyword, + TokenKind::SecondsKeyword, + TokenKind::MinutesKeyword, + TokenKind::HoursKeyword, + TokenKind::DaysKeyword, + TokenKind::WeeksKeyword, + TokenKind::YearsKeyword, + ]) + }) + } +} + +impl Selector { + fn string_expression(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::HexStringLiterals, + RuleKind::AsciiStringLiterals, + RuleKind::UnicodeStringLiterals, + ]) + }) + } +} + +impl Selector { + fn yul_statement(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::YulBlock, + RuleKind::YulFunctionDefinition, + RuleKind::YulVariableDeclarationStatement, + RuleKind::YulAssignmentStatement, + RuleKind::YulIfStatement, + RuleKind::YulForStatement, + RuleKind::YulSwitchStatement, + RuleKind::YulLeaveStatement, + RuleKind::YulBreakStatement, + RuleKind::YulContinueStatement, + RuleKind::YulExpression, + ]) + }) + } +} + +impl Selector { + fn yul_switch_case(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[RuleKind::YulDefaultCase, RuleKind::YulValueCase]) + }) + } +} + +impl Selector { + fn yul_expression(&mut self) -> Result { + self.select(|node| { + node.is_rule_with_kinds(&[ + RuleKind::YulFunctionCallExpression, + RuleKind::YulLiteral, + RuleKind::YulIdentifierPath, + ]) + }) + } +} + +impl Selector { + fn yul_literal(&mut self) -> Result { + self.select(|node| { + node.is_token_with_kinds(&[ + TokenKind::YulTrueKeyword, + TokenKind::YulFalseKeyword, + TokenKind::YulDecimalLiteral, + TokenKind::YulHexLiteral, + TokenKind::HexStringLiteral, + TokenKind::AsciiStringLiteral, + ]) + }) + } +} + +// +// Repeated: +// + +#[napi( + namespace = "ast_internal", + ts_return_type = "Array", + catch_unwind +)] +pub fn select_repeated( + #[napi(ts_arg_type = "cst.RuleNode")] node: &RuleNode, + env: Env, +) -> Result> { + let mut selector = Selector::new(node, env); + + let result = match node.kind() { + RuleKind::SourceUnitMembers => selector.source_unit_members()?, + RuleKind::VersionPragmaExpressions => selector.version_pragma_expressions()?, + RuleKind::ContractMembers => selector.contract_members()?, + RuleKind::InterfaceMembers => selector.interface_members()?, + RuleKind::LibraryMembers => selector.library_members()?, + RuleKind::StructMembers => selector.struct_members()?, + RuleKind::StateVariableAttributes => selector.state_variable_attributes()?, + RuleKind::FunctionAttributes => selector.function_attributes()?, + RuleKind::ConstructorAttributes => selector.constructor_attributes()?, + RuleKind::UnnamedFunctionAttributes => selector.unnamed_function_attributes()?, + RuleKind::FallbackFunctionAttributes => selector.fallback_function_attributes()?, + RuleKind::ReceiveFunctionAttributes => selector.receive_function_attributes()?, + RuleKind::ModifierAttributes => selector.modifier_attributes()?, + RuleKind::FunctionTypeAttributes => selector.function_type_attributes()?, + RuleKind::Statements => selector.statements()?, + RuleKind::CatchClauses => selector.catch_clauses()?, + RuleKind::NamedArgumentGroups => selector.named_argument_groups()?, + RuleKind::HexStringLiterals => selector.hex_string_literals()?, + RuleKind::AsciiStringLiterals => selector.ascii_string_literals()?, + RuleKind::UnicodeStringLiterals => selector.unicode_string_literals()?, + RuleKind::YulStatements => selector.yul_statements()?, + RuleKind::YulSwitchCases => selector.yul_switch_cases()?, + _ => { + return Error::UnexpectedParent(node.kind()).into(); + } + }; + + selector.finalize()?; + Ok(result) +} + +impl Selector { + fn source_unit_members(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::SourceUnitMember))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn version_pragma_expressions(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::VersionPragmaExpression))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn contract_members(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::ContractMember))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn interface_members(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::ContractMember))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn library_members(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::ContractMember))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn struct_members(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::StructMember))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn state_variable_attributes(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::StateVariableAttribute))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn function_attributes(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::FunctionAttribute))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn constructor_attributes(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::ConstructorAttribute))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn unnamed_function_attributes(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::UnnamedFunctionAttribute))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn fallback_function_attributes(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::FallbackFunctionAttribute))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn receive_function_attributes(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::ReceiveFunctionAttribute))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn modifier_attributes(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::ModifierAttribute))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn function_type_attributes(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::FunctionTypeAttribute))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn statements(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::Statement))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn catch_clauses(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::CatchClause))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn named_argument_groups(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::NamedArgumentGroup))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn hex_string_literals(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_token_with_kind(TokenKind::HexStringLiteral))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn ascii_string_literals(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_token_with_kind(TokenKind::AsciiStringLiteral))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn unicode_string_literals(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_token_with_kind(TokenKind::UnicodeStringLiteral))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn yul_statements(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::YulStatement))? + { + items.push(item); + } + + Ok(items) + } +} + +impl Selector { + fn yul_switch_cases(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_rule_with_kind(RuleKind::YulSwitchCase))? + { + items.push(item); + } + + Ok(items) + } +} + +// +// Separated: +// + +#[napi( + namespace = "ast_internal", + ts_return_type = "[Array, Array]", + catch_unwind +)] +pub fn select_separated( + #[napi(ts_arg_type = "cst.RuleNode")] node: &RuleNode, + env: Env, +) -> Result>> { + let mut selector = Selector::new(node, env); + + let result = match node.kind() { + RuleKind::VersionPragmaSpecifier => selector.version_pragma_specifier()?, + RuleKind::ImportDeconstructionSymbols => selector.import_deconstruction_symbols()?, + RuleKind::UsingDeconstructionSymbols => selector.using_deconstruction_symbols()?, + RuleKind::InheritanceTypes => selector.inheritance_types()?, + RuleKind::EnumMembers => selector.enum_members()?, + RuleKind::Parameters => selector.parameters()?, + RuleKind::OverridePaths => selector.override_paths()?, + RuleKind::EventParameters => selector.event_parameters()?, + RuleKind::ErrorParameters => selector.error_parameters()?, + RuleKind::AssemblyFlags => selector.assembly_flags()?, + RuleKind::TupleDeconstructionElements => selector.tuple_deconstruction_elements()?, + RuleKind::PositionalArguments => selector.positional_arguments()?, + RuleKind::NamedArguments => selector.named_arguments()?, + RuleKind::TupleValues => selector.tuple_values()?, + RuleKind::ArrayValues => selector.array_values()?, + RuleKind::IdentifierPath => selector.identifier_path()?, + RuleKind::YulParameters => selector.yul_parameters()?, + RuleKind::YulReturnVariables => selector.yul_return_variables()?, + RuleKind::YulArguments => selector.yul_arguments()?, + RuleKind::YulIdentifierPaths => selector.yul_identifier_paths()?, + RuleKind::YulIdentifierPath => selector.yul_identifier_path()?, + _ => { + return Error::UnexpectedParent(node.kind()).into(); + } + }; + + selector.finalize()?; + Ok(result) +} + +impl Selector { + fn version_pragma_specifier(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::VersionPragmaValue))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Period))? + { + separators.push(separator); + + separated + .push(self.select(|node| node.is_token_with_kind(TokenKind::VersionPragmaValue))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn import_deconstruction_symbols(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push( + self.select(|node| node.is_rule_with_kind(RuleKind::ImportDeconstructionSymbol))?, + ); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push( + self.select(|node| node.is_rule_with_kind(RuleKind::ImportDeconstructionSymbol))?, + ); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn using_deconstruction_symbols(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated + .push(self.select(|node| node.is_rule_with_kind(RuleKind::UsingDeconstructionSymbol))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push( + self.select(|node| node.is_rule_with_kind(RuleKind::UsingDeconstructionSymbol))?, + ); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn inheritance_types(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::InheritanceType))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::InheritanceType))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn enum_members(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn parameters(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::Parameter))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::Parameter))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn override_paths(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::IdentifierPath))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::IdentifierPath))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn event_parameters(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::EventParameter))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::EventParameter))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn error_parameters(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::ErrorParameter))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::ErrorParameter))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn assembly_flags(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::AsciiStringLiteral))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated + .push(self.select(|node| node.is_token_with_kind(TokenKind::AsciiStringLiteral))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn tuple_deconstruction_elements(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push( + self.select(|node| node.is_rule_with_kind(RuleKind::TupleDeconstructionElement))?, + ); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push( + self.select(|node| node.is_rule_with_kind(RuleKind::TupleDeconstructionElement))?, + ); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn positional_arguments(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn named_arguments(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::NamedArgument))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::NamedArgument))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn tuple_values(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::TupleValue))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::TupleValue))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn array_values(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::Expression))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn identifier_path(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Period))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::Identifier))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn yul_parameters(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::YulIdentifier))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::YulIdentifier))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn yul_return_variables(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::YulIdentifier))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::YulIdentifier))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn yul_arguments(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::YulExpression))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::YulExpression))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn yul_identifier_paths(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_rule_with_kind(RuleKind::YulIdentifierPath))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Comma))? + { + separators.push(separator); + + separated + .push(self.select(|node| node.is_rule_with_kind(RuleKind::YulIdentifierPath))?); + } + + Ok(vec![separated, separators]) + } +} + +impl Selector { + fn yul_identifier_path(&mut self) -> Result>> { + let mut separated = vec![]; + let mut separators = vec![]; + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::YulIdentifier))?); + + while let Some(separator) = + self.try_select(|node| node.is_token_with_kind(TokenKind::Period))? + { + separators.push(separator); + + separated.push(self.select(|node| node.is_token_with_kind(TokenKind::YulIdentifier))?); + } + + Ok(vec![separated, separators]) + } +} + +// +// Common: +// + +struct Selector { + env: Env, + node: Rc, + index: usize, +} + +impl Selector { + fn new(node: &RuleNode, env: Env) -> Self { + Self { + env, + node: node.0.clone(), + index: 0, + } + } + + fn select(&mut self, filter: impl FnOnce(&RustNode) -> bool) -> Result { + match self.try_select(filter)? { + Some(node) => Ok(node), + None => Error::MissingChild(self.index).into(), + } + } + + fn try_select(&mut self, filter: impl FnOnce(&RustNode) -> bool) -> Result> { + while let Some(child) = self.node.children.get(self.index) { + match child { + RustNamedNode { + name: _, + node: RustNode::Rule(rule), + } if rule.kind.is_trivia() => { + // skip trivia, since it's not part of the AST + self.index += 1; + continue; + } + RustNamedNode { + name: _, + node: RustNode::Token(token), + } if matches!(token.kind, TokenKind::SKIPPED) => { + return Error::SkippedToken(self.index).into(); + } + node if filter(node) => { + self.index += 1; + return Ok(Some(node.to_js(&self.env))); + } + _ => { + break; + } + } + } + + Ok(None) + } + + fn finalize(mut self) -> Result<()> { + if self.try_select(|_| true)?.is_some() { + return Error::UnexpectedTrailing(self.index - 1).into(); + } + + Ok(()) + } +} + +type Result = std::result::Result; + +#[derive(Debug, thiserror::Error)] +enum Error { + // Should not theoretically happen, since we're only called from our own generated AST types. + #[error("Unexpected parent node with RuleKind '{0}'.")] + UnexpectedParent(RuleKind), + + // Should not theoretically happen, since we're only called from our own generated AST types. + #[error("Unexpected trailing children at index '{0}'.")] + UnexpectedTrailing(usize), + + // Should not theoretically happen, unless AST error recovery was changed. + #[error("Missing child node at index '{0}'.")] + MissingChild(usize), + + // Can happen if the user decided to use an incorrect/incomplete CST node. + #[error("Unexpected SKIPPED token at index '{0}'. Creating AST types from incorrect/incomplete CST nodes is not supported yet.")] + SkippedToken(usize), +} + +impl From for Result { + fn from(error: Error) -> Self { + Err(napi::Error::from_reason(error.to_string())) + } +} diff --git a/package-lock.json b/package-lock.json index f769fb46f3..522f6d9dfb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,6 +78,150 @@ "@nomicfoundation/slang-win32-x64-msvc": "0.13.1" } }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-darwin-arm64": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-darwin-arm64/-/slang-darwin-arm64-0.12.0.tgz", + "integrity": "sha512-FCZA8rghL8rICf3xZFD74ZhEx7xLJw2SanNVCx+tiYJXfCcoKTpAMlj3bRSlDNri7weEo+/UUDRKKMK695Allw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-darwin-x64": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-darwin-x64/-/slang-darwin-x64-0.12.0.tgz", + "integrity": "sha512-hgOIcn6ZjRdBwPq2ZQHc2EOUyOWGlFxL1wlUPkoMr3gJFmzHpetqJ9pwkEKTUKhrnBc8FAtQYwbniyHcXin32g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-linux-arm64-gnu": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-arm64-gnu/-/slang-linux-arm64-gnu-0.12.0.tgz", + "integrity": "sha512-/nlMW7Qgtffc32NR+Bcil52GMAqoALyBUF/U70mINlOmHghfv7Z6znt17bZ4h2IR//xK9PYcpjoMafY044sj2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-linux-arm64-musl": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-arm64-musl/-/slang-linux-arm64-musl-0.12.0.tgz", + "integrity": "sha512-n75FdDrVH4X7ZPUYa3C2oiqnGyWBjpLbKHtvgi951gDV4osCsLtzSAZbm40o0t8837AGU+gb2mksBRJbx+Gusg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-linux-x64-gnu": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-x64-gnu/-/slang-linux-x64-gnu-0.12.0.tgz", + "integrity": "sha512-nQcrHdiEQOqBpa8Uj3X8WKdhbPigFzB4logIXUqu2si0s0JPAn4PETw23H/+ul/PXkQE+lGQQCdrwSChDquYkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-linux-x64-musl": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-linux-x64-musl/-/slang-linux-x64-musl-0.12.0.tgz", + "integrity": "sha512-L0yKk25RxpwKH0vZ3qPsUgHnjpjcGYUedG4PPrk3PU5TgPvFjyMXuvwvjZcLMGFWJelQV37QipXbfRSyALLmSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-win32-arm64-msvc": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-arm64-msvc/-/slang-win32-arm64-msvc-0.12.0.tgz", + "integrity": "sha512-Zecx/ZmZ3uffDNyuqeCdeDvnEZXMcVLLbsjf3RT+C8x2j3Li4YJpdf3fszGvdhaq+S7tIeCS2JP+KbgtOadXjQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-win32-ia32-msvc": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-ia32-msvc/-/slang-win32-ia32-msvc-0.12.0.tgz", + "integrity": "sha512-w8Y2WENBlB9XzeaiBiE3VbxLPpXHm9/dZvKXq7o/3yfvRedKjbHHJoEH0ubfXFHXDfADh+7Va/B0o8ja/sHkNQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "crates/solidity/outputs/npm/package/target/npm/main/node_modules/@nomicfoundation/slang-win32-x64-msvc": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/slang-win32-x64-msvc/-/slang-win32-x64-msvc-0.12.0.tgz", + "integrity": "sha512-YnPv5ZYcUD1HVa3WEFcjd+xnlsNKBtfzMRLHRTOF344ZoJvmQ5HsNKD/nmPtaRA7SwAVvm7bwZ7JCzO/6bUIzw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "crates/solidity/outputs/npm/tests": { "name": "@slang-private/solidity-npm-tests", "devDependencies": {