diff --git a/.changeset/fluffy-elephants-beg.md b/.changeset/fluffy-elephants-beg.md index 0a4403c509..2f0f5baf98 100644 --- a/.changeset/fluffy-elephants-beg.md +++ b/.changeset/fluffy-elephants-beg.md @@ -2,4 +2,4 @@ "@nomicfoundation/slang": minor --- -rename `parser/Parser.supportedVersions()` API to `utils/LanguageFacts.supportedVersions()`. +split `parser/Parser.supportedVersions()` into a new `utils/LanguageFacts` API, with `allVersions()`, `earliestVersion()`, and `latestVersion()` methods. diff --git a/.changeset/new-bikes-hear.md b/.changeset/new-bikes-hear.md new file mode 100644 index 0000000000..68fcafa9a2 --- /dev/null +++ b/.changeset/new-bikes-hear.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": minor +--- + +split `Parser.parse()` API into `parse_file_contents()` and `parse_nonterminal()`. diff --git a/.changeset/shiny-feet-shop.md b/.changeset/shiny-feet-shop.md new file mode 100644 index 0000000000..84d6076129 --- /dev/null +++ b/.changeset/shiny-feet-shop.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": minor +--- + +rename `Query.parse()` to `Query.create()`, and provide exact `TextRange` for any errors it returns. diff --git a/.changeset/tame-tools-walk.md b/.changeset/tame-tools-walk.md new file mode 100644 index 0000000000..f481356b42 --- /dev/null +++ b/.changeset/tame-tools-walk.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": minor +--- + +add `TerminalKindExtensions.is_identifier()` API to distinguish terminals like Solidity's `Identifier` and Yul's `YulIdentifier`. diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/file.rs b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/file.rs index a5a7df7862..793252a454 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/file.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/file.rs @@ -4,20 +4,25 @@ use std::rc::Rc; use metaslang_cst::text_index::TextIndex; use crate::cst::{Cursor, NonterminalNode}; +use crate::parser::{ParseError, ParseOutput}; #[derive(Clone)] pub struct File { id: String, tree: Rc, + errors: Vec, resolved_imports: BTreeMap, } impl File { - pub(super) fn new(id: String, tree: Rc) -> Self { + pub(super) fn create(id: String, parse_output: ParseOutput) -> Self { + let ParseOutput { tree, errors } = parse_output; + Self { id, tree, + errors, resolved_imports: BTreeMap::new(), } @@ -31,8 +36,12 @@ impl File { &self.tree } + pub fn errors(&self) -> &Vec { + &self.errors + } + pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).create_cursor(TextIndex::ZERO) } pub(super) fn resolve_import(&mut self, import_path: &Cursor, destination_file_id: String) { diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/internal_builder.rs b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/internal_builder.rs index 14ccb1ff35..b1eb3b01de 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/internal_builder.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/internal_builder.rs @@ -39,11 +39,11 @@ impl InternalCompilationBuilder { }; } - let parse_output = self.parser.parse(Parser::ROOT_KIND, contents); + let parse_output = self.parser.parse_file_contents(contents); let import_paths = self.imports.extract(parse_output.create_tree_cursor()); - let file = File::new(id.clone(), Rc::clone(parse_output.tree())); + let file = File::create(id.clone(), parse_output); self.files.insert(id, file); AddFileResponse { import_paths } @@ -72,7 +72,7 @@ impl InternalCompilationBuilder { .map(|(id, file)| (id.to_owned(), Rc::new(file.to_owned()))) .collect(); - CompilationUnit::new(language_version, files) + CompilationUnit::create(language_version, files) } } diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs index e909b5882d..221cf1fa4c 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/compilation/unit.rs @@ -17,7 +17,7 @@ pub struct CompilationUnit { } impl CompilationUnit { - pub(super) fn new(language_version: Version, files: BTreeMap>) -> Self { + pub(super) fn create(language_version: Version, files: BTreeMap>) -> Self { Self { language_version, files, diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/cst/generated/terminal_kind.rs b/crates/codegen/runtime/cargo/crate/src/runtime/cst/generated/terminal_kind.rs index 9365a9392c..58ae2f9994 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/cst/generated/terminal_kind.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/cst/generated/terminal_kind.rs @@ -28,12 +28,4 @@ pub enum TerminalKind { Stub3, } -impl crate::cst::TerminalKindExtensions for TerminalKind { - fn is_trivia(&self) -> bool { - false - } - - fn is_valid(&self) -> bool { - !matches!(self, Self::UNRECOGNIZED | Self::MISSING) - } -} +impl crate::cst::TerminalKindExtensions for TerminalKind {} diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/cst/terminal_kind.rs.jinja2 b/crates/codegen/runtime/cargo/crate/src/runtime/cst/terminal_kind.rs.jinja2 index e351a1ab42..4f10b9a418 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/cst/terminal_kind.rs.jinja2 +++ b/crates/codegen/runtime/cargo/crate/src/runtime/cst/terminal_kind.rs.jinja2 @@ -44,20 +44,27 @@ pub enum TerminalKind { } impl crate::cst::TerminalKindExtensions for TerminalKind { - fn is_trivia(&self) -> bool { - {%- if rendering_in_stubs -%} - false - {%- else -%} + {%- if not rendering_in_stubs -%} + fn is_identifier(self) -> bool { matches!( self, - {%- for variant in model.kinds.trivia_scanner_names -%} + {%- for variant in model.kinds.identifier_terminals -%} | Self::{{ variant }} {%- endfor -%} ) - {%- endif -%} - } + } - fn is_valid(&self) -> bool { - !matches!(self, Self::UNRECOGNIZED | Self::MISSING) - } + fn is_trivia(self) -> bool { + matches!( + self, + {%- for variant in model.kinds.trivia_terminals -%} + | Self::{{ variant }} + {%- endfor -%} + ) + } + + fn is_valid(self) -> bool { + !matches!(self, Self::UNRECOGNIZED | Self::MISSING) + } + {%- endif -%} } diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/generated/parser.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/generated/parser.rs index bc7976769f..a26b035af9 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/generated/parser.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/generated/parser.rs @@ -41,12 +41,10 @@ pub enum ParserInitializationError { } impl Parser { - pub const ROOT_KIND: NonterminalKind = NonterminalKind::Stub1; - pub fn create( language_version: Version, ) -> std::result::Result { - if LanguageFacts::SUPPORTED_VERSIONS + if LanguageFacts::ALL_VERSIONS .binary_search(&language_version) .is_ok() { @@ -62,7 +60,10 @@ impl Parser { &self.language_version } - pub fn parse(&self, kind: NonterminalKind, input: &str) -> ParseOutput { + pub fn parse_file_contents(&self, input: &str) -> ParseOutput { + self.parse_nonterminal(NonterminalKind::Stub1, input) + } + pub fn parse_nonterminal(&self, kind: NonterminalKind, input: &str) -> ParseOutput { unreachable!("Attempting to parse in stubs: {kind}: {input}") } } diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_error.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_error.rs index 8b73456e96..505905dba5 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_error.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_error.rs @@ -25,7 +25,7 @@ impl ParseError { } impl ParseError { - pub(crate) fn new( + pub(crate) fn create( text_range: TextRange, mut terminals_that_would_have_allowed_more_progress: Vec, ) -> Self { diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_output.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_output.rs index d395732cd2..73ca37cc7f 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_output.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parse_output.rs @@ -24,6 +24,6 @@ impl ParseOutput { /// Creates a cursor that starts at the root of the parse tree. pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).create_cursor(TextIndex::ZERO) } } diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser.rs.jinja2 b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser.rs.jinja2 index ec4b39e366..22809eed6a 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser.rs.jinja2 +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser.rs.jinja2 @@ -48,10 +48,8 @@ pub enum ParserInitializationError { } impl Parser { - pub const ROOT_KIND: NonterminalKind = NonterminalKind::{{ model.kinds.root_kind }}; - pub fn create(language_version: Version) -> std::result::Result { - if LanguageFacts::SUPPORTED_VERSIONS.binary_search(&language_version).is_ok() { + if LanguageFacts::ALL_VERSIONS.binary_search(&language_version).is_ok() { Ok(Self { {%- if not rendering_in_stubs -%} {%- for version in model.breaking_language_versions %} @@ -70,7 +68,25 @@ impl Parser { &self.language_version } - {%- if not rendering_in_stubs -%} + pub fn parse_file_contents(&self, input: &str) -> ParseOutput { + self.parse_nonterminal(NonterminalKind::{{ model.kinds.root_kind }}, input) + } + + {%- if rendering_in_stubs -%} + + pub fn parse_nonterminal(&self, kind: NonterminalKind, input: &str) -> ParseOutput { + unreachable!("Attempting to parse in stubs: {kind}: {input}") + } + + {%- else -%} + + pub fn parse_nonterminal(&self, kind: NonterminalKind, input: &str) -> ParseOutput { + match kind { + {%- for parser_name, _ in model.parser.parser_functions -%} + NonterminalKind::{{ parser_name }} => Self::{{ parser_name | snake_case }}.parse(self, input, kind), + {%- endfor -%} + } + } /******************************************** * Parser Functions @@ -101,18 +117,6 @@ impl Parser { {% endfor %} {% endif %} - - pub fn parse(&self, kind: NonterminalKind, input: &str) -> ParseOutput { - {%- if rendering_in_stubs -%} - unreachable!("Attempting to parse in stubs: {kind}: {input}") - {%- else -%} - match kind { - {%- for parser_name, _ in model.parser.parser_functions -%} - NonterminalKind::{{ parser_name }} => Self::{{ parser_name | snake_case }}.parse(self, input, kind), - {%- endfor -%} - } - {%- endif -%} - } } impl Lexer for Parser { diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/choice_helper.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/choice_helper.rs index a514e7b89e..b6464b294d 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/choice_helper.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/choice_helper.rs @@ -138,7 +138,7 @@ pub fn total_not_skipped_span(result: &ParserResult) -> usize { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .filter_map(|edge| match edge.node { diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_function.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_function.rs index b0611c7cdc..d146c8377a 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_function.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_function.rs @@ -89,8 +89,8 @@ where let node = Node::terminal(kind, input.to_string()); children.push(Edge::anonymous(node)); ParseOutput { - tree: Rc::new(NonterminalNode::new(topmost_kind, children)), - errors: vec![ParseError::new( + tree: NonterminalNode::create(topmost_kind, children), + errors: vec![ParseError::create( start..start + input.into(), no_match.expected_terminals, )], @@ -147,13 +147,13 @@ where let start_index = stream.text_index_at(start); let mut errors = stream.into_errors(); - errors.push(ParseError::new( + errors.push(ParseError::create( start_index..input.into(), expected_terminals, )); ParseOutput { - tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), + tree: NonterminalNode::create(topmost_node.kind, new_children), errors, } } else { @@ -164,7 +164,7 @@ where debug_assert_eq!( errors.is_empty(), Rc::clone(&tree) - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() .all(|edge| edge .as_terminal() diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_result.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_result.rs index f24a1abd25..5f46195246 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_result.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/parser_result.rs @@ -132,7 +132,7 @@ impl Match { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .all(|edge| { @@ -213,7 +213,7 @@ impl IncompleteMatch { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .try_fold(0u8, |mut acc, edge| { diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/recovery.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/recovery.rs index cec55a393c..a7606ab5d4 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/recovery.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/recovery.rs @@ -88,7 +88,10 @@ impl ParserResult { let skipped = input.content(skipped_range.utf8()); - input.emit(ParseError::new(skipped_range, expected_terminals.clone())); + input.emit(ParseError::create( + skipped_range, + expected_terminals.clone(), + )); ParserResult::SkippedUntil(SkippedUntil { nodes, diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/separated_helper.rs b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/separated_helper.rs index e1455a8155..c2635870fd 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/separated_helper.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/parser/parser_support/separated_helper.rs @@ -60,7 +60,7 @@ impl SeparatedHelper { kind, input.content(skipped_range.utf8()), ))); - input.emit(ParseError::new( + input.emit(ParseError::create( skipped_range, incomplete.expected_terminals, )); diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/utils/generated/language_facts.rs b/crates/codegen/runtime/cargo/crate/src/runtime/utils/generated/language_facts.rs index 12af5c1f2e..9446377974 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/utils/generated/language_facts.rs +++ b/crates/codegen/runtime/cargo/crate/src/runtime/utils/generated/language_facts.rs @@ -5,7 +5,9 @@ use semver::Version; pub struct LanguageFacts; impl LanguageFacts { - pub const NAME: &'static str = "CodegenRuntime"; + pub const ALL_VERSIONS: &'static [Version] = &[Version::new(0, 0, 0)]; - pub const SUPPORTED_VERSIONS: &'static [Version] = &[]; + pub const EARLIEST_VERSION: Version = Version::new(0, 0, 0); + + pub const LATEST_VERSION: Version = Version::new(0, 0, 0); } diff --git a/crates/codegen/runtime/cargo/crate/src/runtime/utils/language_facts.rs.jinja2 b/crates/codegen/runtime/cargo/crate/src/runtime/utils/language_facts.rs.jinja2 index fe91f6ae7f..25061098d3 100644 --- a/crates/codegen/runtime/cargo/crate/src/runtime/utils/language_facts.rs.jinja2 +++ b/crates/codegen/runtime/cargo/crate/src/runtime/utils/language_facts.rs.jinja2 @@ -3,11 +3,17 @@ use semver::Version; pub struct LanguageFacts; impl LanguageFacts { - pub const NAME: &'static str = "{{ model.language_name }}"; - - pub const SUPPORTED_VERSIONS: &'static [Version] = &[ + pub const ALL_VERSIONS: &'static [Version] = &[ {% for version in model.all_language_versions %} Version::new({{ version | split(pat=".") | join(sep=", ") }}), {% endfor %} ]; + + pub const EARLIEST_VERSION: Version = Version::new( + {{ model.all_language_versions | first() | split(pat=".") | join(sep=", ") }} + ); + + pub const LATEST_VERSION: Version = Version::new( + {{ model.all_language_versions | last() | split(pat=".") | join(sep=", ") }} + ); } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/config.json.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/config.json.jinja2 index 3444eb9169..15037ce589 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/config.json.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/config.json.jinja2 @@ -170,16 +170,6 @@ "as_getter": true } }, - "nomic-foundation:slang:parser:parse-error.text-range()": { - "Function": { - "as_getter": true - } - }, - "nomic-foundation:slang:parser:parse-error.message()": { - "Function": { - "as_getter": true - } - }, "nomic-foundation:slang:parser:parse-output.tree()": { "Function": { "as_getter": true diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/generated/config.json b/crates/codegen/runtime/cargo/wasm/src/runtime/generated/config.json index 3444eb9169..15037ce589 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/generated/config.json +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/generated/config.json @@ -170,16 +170,6 @@ "as_getter": true } }, - "nomic-foundation:slang:parser:parse-error.text-range()": { - "Function": { - "as_getter": true - } - }, - "nomic-foundation:slang:parser:parse-error.message()": { - "Function": { - "as_getter": true - } - }, "nomic-foundation:slang:parser:parse-output.tree()": { "Function": { "as_getter": true diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 index d1586c4fdb..60ef790715 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/bindings.wit.jinja2 @@ -4,12 +4,16 @@ interface bindings { /// A giant graph that contains name binding information for all source files within the compilation unit. /// It stores cursors to all definitions and references, and can resolve the edges between them. resource binding-graph { - /// If the provided cursor points at a definition `Identifier`, it will return the - /// corresponding definition. Otherwise, it will return `undefined`. + /// Tries to resolve the identifier terminal pointed at by the provided cursor to a definition. + /// If successful, returns the definition. Otherwise, returns `undefined`. + /// + /// For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. definition-at: func(cursor: borrow) -> option; - /// If the provided cursor points at a reference `Identifier`, it will return the - /// corresponding reference. Otherwise, it will return `undefined`. + /// Tries to resolve the identifier terminal pointed at by the provided cursor to a reference. + /// If successful, returns the reference. Otherwise, returns `undefined`. + /// + /// For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. reference-at: func(cursor: borrow) -> option; } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/compilation.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/compilation.wit.jinja2 index 542e2b398e..454e9f5e21 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/compilation.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/compilation.wit.jinja2 @@ -1,6 +1,7 @@ interface compilation { use bindings.{binding-graph}; use cst.{nonterminal-node, cursor}; + use parser.{parse-error}; /// A builder for creating compilation units. /// Allows incrementally building a transitive list of all files and their imports. @@ -62,6 +63,9 @@ interface compilation { /// Returns the syntax tree of this file. tree: func() -> nonterminal-node; + /// Returns a list of all errors encountered during parsing this file. + errors: func() -> list; + /// Creates a cursor for traversing the syntax tree of this file. create-tree-cursor: func() -> cursor; } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/cst.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/cst.wit.jinja2 index 741baffed6..c1ae1632ad 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/cst.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/cst.wit.jinja2 @@ -56,9 +56,11 @@ interface cst { //// Useful extension methods for working with terminals and terminal kinds. resource terminal-kind-extensions { - /// Returns true if the terminal is a trivia token. i.e. whitespace, comments, etc... + /// Returns `true` if the terminal is an identifier token. + is-identifier: static func(kind: terminal-kind) -> bool; + /// Returns `true` if the terminal is a trivia token. i.e. whitespace, comments, etc... is-trivia: static func(kind: terminal-kind) -> bool; - /// Returns true if the terminal is a valid token in the language grammar. + /// Returns `true` if the terminal is a valid token in the language grammar. is-valid: static func(kind: terminal-kind) -> bool; } @@ -203,7 +205,7 @@ interface cst { /// Moves to the last child of the current node. go-to-last-child: func() -> bool; /// Moves to the nth child of the current node. - go-to-nth-child: func(child-number: u32) -> bool; + go-to-nth-child: func(child-index: u32) -> bool; /// Moves to the next sibling node. go-to-next-sibling: func() -> bool; @@ -245,23 +247,21 @@ interface cst { resource query { /// Parses a query string into a query object. /// Throws an error if the query syntax is invalid. - parse: static func(text: string) -> result; + create: static func(text: string) -> result; } /// Represents an error that occurred while parsing a query. record query-error { - /// The error message describing what went wrong. + /// A human-readable message describing what went wrong. message: string, - /// The line number where the error occurred. - line: u32, - /// The column number where the error occurred. - column: u32, + /// The text range where the error occurred in the query code. + text-range: text-range, } - /// Represents a match found by executing a query. + /// Represents a match found by executing queries on a cursor. record query-match { /// The index of the query that produced this match. - query-number: u32, + query-index: u32, /// List of captured nodes and their names from the query. captures: list>>, } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit index 1721afc82d..e6fbb0073b 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/bindings.wit @@ -6,12 +6,16 @@ interface bindings { /// A giant graph that contains name binding information for all source files within the compilation unit. /// It stores cursors to all definitions and references, and can resolve the edges between them. resource binding-graph { - /// If the provided cursor points at a definition `Identifier`, it will return the - /// corresponding definition. Otherwise, it will return `undefined`. + /// Tries to resolve the identifier terminal pointed at by the provided cursor to a definition. + /// If successful, returns the definition. Otherwise, returns `undefined`. + /// + /// For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. definition-at: func(cursor: borrow) -> option; - /// If the provided cursor points at a reference `Identifier`, it will return the - /// corresponding reference. Otherwise, it will return `undefined`. + /// Tries to resolve the identifier terminal pointed at by the provided cursor to a reference. + /// If successful, returns the reference. Otherwise, returns `undefined`. + /// + /// For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. reference-at: func(cursor: borrow) -> option; } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/compilation.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/compilation.wit index ea64aab4ac..b3918e9681 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/compilation.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/compilation.wit @@ -3,6 +3,7 @@ interface compilation { use bindings.{binding-graph}; use cst.{nonterminal-node, cursor}; + use parser.{parse-error}; /// A builder for creating compilation units. /// Allows incrementally building a transitive list of all files and their imports. @@ -64,6 +65,9 @@ interface compilation { /// Returns the syntax tree of this file. tree: func() -> nonterminal-node; + /// Returns a list of all errors encountered during parsing this file. + errors: func() -> list; + /// Creates a cursor for traversing the syntax tree of this file. create-tree-cursor: func() -> cursor; } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/cst.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/cst.wit index 1f293bb59c..d06072d9dd 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/cst.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/cst.wit @@ -31,9 +31,11 @@ interface cst { //// Useful extension methods for working with terminals and terminal kinds. resource terminal-kind-extensions { - /// Returns true if the terminal is a trivia token. i.e. whitespace, comments, etc... + /// Returns `true` if the terminal is an identifier token. + is-identifier: static func(kind: terminal-kind) -> bool; + /// Returns `true` if the terminal is a trivia token. i.e. whitespace, comments, etc... is-trivia: static func(kind: terminal-kind) -> bool; - /// Returns true if the terminal is a valid token in the language grammar. + /// Returns `true` if the terminal is a valid token in the language grammar. is-valid: static func(kind: terminal-kind) -> bool; } @@ -182,7 +184,7 @@ interface cst { /// Moves to the last child of the current node. go-to-last-child: func() -> bool; /// Moves to the nth child of the current node. - go-to-nth-child: func(child-number: u32) -> bool; + go-to-nth-child: func(child-index: u32) -> bool; /// Moves to the next sibling node. go-to-next-sibling: func() -> bool; @@ -224,23 +226,21 @@ interface cst { resource query { /// Parses a query string into a query object. /// Throws an error if the query syntax is invalid. - parse: static func(text: string) -> result; + create: static func(text: string) -> result; } /// Represents an error that occurred while parsing a query. record query-error { - /// The error message describing what went wrong. + /// A human-readable message describing what went wrong. message: string, - /// The line number where the error occurred. - line: u32, - /// The column number where the error occurred. - column: u32, + /// The text range where the error occurred in the query code. + text-range: text-range, } - /// Represents a match found by executing a query. + /// Represents a match found by executing queries on a cursor. record query-match { /// The index of the query that produced this match. - query-number: u32, + query-index: u32, /// List of captured nodes and their names from the query. captures: list>>, } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/parser.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/parser.wit index 6eca8e01ae..8834d77de3 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/parser.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/parser.wit @@ -6,27 +6,26 @@ interface parser { /// A parser instance that can parse source code into syntax trees. /// Each parser is configured for a specific language version and grammar. resource parser { - /// Returns the root nonterminal kind for this parser's grammar. - /// This represents the starting point for parsing a complete source file. - root-kind: static func() -> nonterminal-kind; - /// Creates a new parser instance for the specified language version. create: static func(language-version: string) -> result; /// Returns the language version this parser instance is configured for. language-version: func() -> string; - /// Parses the input string starting from the specified nonterminal kind. - parse: func(kind: nonterminal-kind, input: string) -> parse-output; + /// Parses the input string into a complete source file. + parse-file-contents: func(input: string) -> parse-output; + + /// Parses the input string into a nonterminal with the specified kind. + parse-nonterminal: func(kind: nonterminal-kind, input: string) -> parse-output; } - /// Contains information about where the error occurred and what went wrong. - resource parse-error { - /// Returns the text range where the error occurred in the source code. - text-range: func() -> text-range; + /// Represents an error that occurred while parsing source code. + record parse-error { + /// A human-readable message describing what went wrong. + message: string, - /// Returns a human-readable message describing the parsing error. - message: func() -> string; + /// The text range where the error occurred in the source code. + text-range: text-range, } /// The output of a parsing operation. @@ -37,7 +36,7 @@ interface parser { tree: func() -> nonterminal-node; /// Returns a list of all parsing errors encountered. - /// An empty list indicates successful parsing with no errors. + /// An empty list indicates a successful parse with no errors. errors: func() -> list; /// Returns whether the parse was completely successful with no errors. diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/utils.wit b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/utils.wit index 9bb93e160f..86c9d20bd0 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/utils.wit +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/generated/utils.wit @@ -4,6 +4,12 @@ interface utils { /// Provides information about the supported language versions and the grammar. resource language-facts { /// Returns a list of language versions supported by Slang, sorted ascendingly. - supported-versions: static func() -> list; + all-versions: static func() -> list; + + /// Returns the earliest language version supported by Slang. + earliest-version: static func() -> string; + + /// Returns the latest language version supported by Slang. + latest-version: static func() -> string; } } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/parser.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/parser.wit.jinja2 index ebe1e15d83..32786e734b 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/parser.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/parser.wit.jinja2 @@ -4,27 +4,26 @@ interface parser { /// A parser instance that can parse source code into syntax trees. /// Each parser is configured for a specific language version and grammar. resource parser { - /// Returns the root nonterminal kind for this parser's grammar. - /// This represents the starting point for parsing a complete source file. - root-kind: static func() -> nonterminal-kind; - /// Creates a new parser instance for the specified language version. create: static func(language-version: string) -> result; /// Returns the language version this parser instance is configured for. language-version: func() -> string; - /// Parses the input string starting from the specified nonterminal kind. - parse: func(kind: nonterminal-kind, input: string) -> parse-output; + /// Parses the input string into a complete source file. + parse-file-contents: func(input: string) -> parse-output; + + /// Parses the input string into a nonterminal with the specified kind. + parse-nonterminal: func(kind: nonterminal-kind, input: string) -> parse-output; } - /// Contains information about where the error occurred and what went wrong. - resource parse-error { - /// Returns the text range where the error occurred in the source code. - text-range: func() -> text-range; + /// Represents an error that occurred while parsing source code. + record parse-error { + /// A human-readable message describing what went wrong. + message: string, - /// Returns a human-readable message describing the parsing error. - message: func() -> string; + /// The text range where the error occurred in the source code. + text-range: text-range, } /// The output of a parsing operation. @@ -35,7 +34,7 @@ interface parser { tree: func() -> nonterminal-node; /// Returns a list of all parsing errors encountered. - /// An empty list indicates successful parsing with no errors. + /// An empty list indicates a successful parse with no errors. errors: func() -> list; /// Returns whether the parse was completely successful with no errors. diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/utils.wit.jinja2 b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/utils.wit.jinja2 index 7becc47d08..bae12ad423 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/interface/utils.wit.jinja2 +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/interface/utils.wit.jinja2 @@ -2,6 +2,12 @@ interface utils { /// Provides information about the supported language versions and the grammar. resource language-facts { /// Returns a list of language versions supported by Slang, sorted ascendingly. - supported-versions: static func() -> list; + all-versions: static func() -> list; + + /// Returns the earliest language version supported by Slang. + earliest-version: static func() -> string; + + /// Returns the latest language version supported by Slang. + latest-version: static func() -> string; } } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs index 38b6e130ca..17cdfb74ca 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/compilation/mod.rs @@ -14,6 +14,7 @@ mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Cursor, NonterminalNode, }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::ParseError; } mod rust { @@ -116,6 +117,10 @@ define_rc_wrapper! { File { self._borrow_ffi().tree().to_owned()._into_ffi() } + fn errors(&self) -> Vec { + self._borrow_ffi().errors().iter().map(|e| e.clone()._into_ffi()).collect() + } + fn create_tree_cursor(&self) -> ffi::Cursor { self._borrow_ffi().create_tree_cursor()._into_ffi() } diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/cst/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/cst/mod.rs index 0f93bf33a1..9bfd8973e2 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/cst/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/cst/mod.rs @@ -63,12 +63,16 @@ enum_to_enum!(TerminalKind); pub struct TerminalKindExtensionsWrapper; impl ffi::GuestTerminalKindExtensions for TerminalKindExtensionsWrapper { + fn is_identifier(kind: ffi::TerminalKind) -> bool { + crate::rust_crate::cst::TerminalKindExtensions::is_identifier(kind._from_ffi()) + } + fn is_trivia(kind: ffi::TerminalKind) -> bool { - crate::rust_crate::cst::TerminalKindExtensions::is_trivia(&kind._from_ffi()) + crate::rust_crate::cst::TerminalKindExtensions::is_trivia(kind._from_ffi()) } fn is_valid(kind: ffi::TerminalKind) -> bool { - crate::rust_crate::cst::TerminalKindExtensions::is_valid(&kind._from_ffi()) + crate::rust_crate::cst::TerminalKindExtensions::is_valid(kind._from_ffi()) } } @@ -96,6 +100,16 @@ impl IntoFFI for rust::Node { } } +impl FromFFI for ffi::Node { + #[inline] + fn _from_ffi(self) -> rust::Node { + match self { + ffi::Node::Nonterminal(node) => rust::Node::Nonterminal(node._from_ffi()), + ffi::Node::Terminal(node) => rust::Node::Terminal(node._from_ffi()), + } + } +} + //================================================ // // resource nonterminal-node @@ -132,7 +146,7 @@ define_rc_wrapper! { NonterminalNode { } fn create_cursor(&self, text_offset: ffi::TextIndex) -> ffi::Cursor { - std::rc::Rc::clone(self._borrow_ffi()).cursor_with_offset(text_offset._from_ffi())._into_ffi() + std::rc::Rc::clone(self._borrow_ffi()).create_cursor(text_offset._from_ffi())._into_ffi() } } } @@ -188,6 +202,16 @@ impl IntoFFI for rust::Edge { } } +impl FromFFI for ffi::Edge { + #[inline] + fn _from_ffi(self) -> rust::Edge { + rust::Edge { + label: self.label.map(FromFFI::_from_ffi), + node: self.node._from_ffi(), + } + } +} + //================================================ // // resource cursor @@ -275,8 +299,8 @@ define_refcell_wrapper! { Cursor { self._borrow_mut_ffi().go_to_last_child() } - fn go_to_nth_child(&self, child_number: u32) -> bool { - self._borrow_mut_ffi().go_to_nth_child(child_number as usize) + fn go_to_nth_child(&self, child_index: u32) -> bool { + self._borrow_mut_ffi().go_to_nth_child(child_index as usize) } fn go_to_next_sibling(&self) -> bool { @@ -353,8 +377,8 @@ define_refcell_wrapper! { AncestorsIterator { //================================================ define_wrapper! { Query { - fn parse(text: String) -> Result { - rust::Query::parse(&text).map_err(IntoFFI::_into_ffi).map(IntoFFI::_into_ffi) + fn create(text: String) -> Result { + rust::Query::create(&text).map_err(IntoFFI::_into_ffi).map(IntoFFI::_into_ffi) } } } @@ -369,8 +393,7 @@ impl IntoFFI for rust::QueryError { fn _into_ffi(self) -> ffi::QueryError { ffi::QueryError { message: self.message, - line: self.line.try_into().unwrap(), - column: self.column.try_into().unwrap(), + text_range: self.text_range._into_ffi(), } } } @@ -397,7 +420,7 @@ impl IntoFFI for rust::QueryMatch { #[inline] fn _into_ffi(self) -> ffi::QueryMatch { ffi::QueryMatch { - query_number: self.query_number.try_into().unwrap(), + query_index: self.query_index.try_into().unwrap(), captures: self .captures .into_iter() diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/parser/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/parser/mod.rs index c783de47bd..92ae87337e 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/parser/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/parser/mod.rs @@ -4,11 +4,11 @@ use crate::wasm_crate::utils::{define_wrapper, FromFFI, IntoFFI}; mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ - Cursor, NonterminalNode, TextRange, + Cursor, NonterminalNode, }; pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::{ - Guest, GuestParseError, GuestParseOutput, GuestParser, NonterminalKind, ParseError, - ParseErrorBorrow, ParseOutput, ParseOutputBorrow, Parser, ParserBorrow, + Guest, GuestParseOutput, GuestParser, NonterminalKind, ParseError, ParseOutput, + ParseOutputBorrow, Parser, ParserBorrow, }; } @@ -18,7 +18,6 @@ mod rust { impl ffi::Guest for crate::wasm_crate::World { type Parser = ParserWrapper; - type ParseError = ParseErrorWrapper; type ParseOutput = ParseOutputWrapper; } @@ -29,10 +28,6 @@ impl ffi::Guest for crate::wasm_crate::World { //================================================ define_wrapper! { Parser { - fn root_kind() -> ffi::NonterminalKind { - rust::Parser::ROOT_KIND._into_ffi() - } - fn create(language_version: String) -> Result { semver::Version::parse(&language_version) .map_err(|_| format!("Invalid semantic version: '{language_version}'")) @@ -44,26 +39,30 @@ define_wrapper! { Parser { self._borrow_ffi().language_version().to_string() } - fn parse(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { - self._borrow_ffi().parse(kind._from_ffi(), &input)._into_ffi() + fn parse_file_contents(&self, input: String) -> ffi::ParseOutput { + self._borrow_ffi().parse_file_contents(&input)._into_ffi() + } + + fn parse_nonterminal(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { + self._borrow_ffi().parse_nonterminal(kind._from_ffi(), &input)._into_ffi() } } } //================================================ // -// resource parse-error +// record parse-error // //================================================ -define_wrapper! { ParseError { - fn text_range(&self) -> ffi::TextRange { - self._borrow_ffi().text_range()._into_ffi() +impl IntoFFI for rust::ParseError { + #[inline] + fn _into_ffi(self) -> ffi::ParseError { + ffi::ParseError { + message: self.message(), + text_range: self.text_range()._into_ffi(), + } } - - fn message(&self) -> String { - self._borrow_ffi().message() - } -} } +} //================================================ // diff --git a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/utils/mod.rs b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/utils/mod.rs index a621d61d36..5340f73d1c 100644 --- a/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/utils/mod.rs +++ b/crates/codegen/runtime/cargo/wasm/src/runtime/wrappers/utils/mod.rs @@ -1,3 +1,5 @@ +use semver::Version; + use crate::wasm_crate::utils::define_wrapper; mod ffi { @@ -21,10 +23,18 @@ impl ffi::Guest for crate::wasm_crate::World { //================================================ define_wrapper! { LanguageFacts { - fn supported_versions() -> Vec { - rust::LanguageFacts::SUPPORTED_VERSIONS + fn all_versions() -> Vec { + rust::LanguageFacts::ALL_VERSIONS .iter() - .map(|v| v.to_string()) + .map(Version::to_string) .collect() } + + fn earliest_version() -> String { + rust::LanguageFacts::EARLIEST_VERSION.to_string() + } + + fn latest_version() -> String { + rust::LanguageFacts::LATEST_VERSION.to_string() + } } } diff --git a/crates/codegen/runtime/generator/src/kinds/mod.rs b/crates/codegen/runtime/generator/src/kinds/mod.rs index 216a70fc02..4914d2376d 100644 --- a/crates/codegen/runtime/generator/src/kinds/mod.rs +++ b/crates/codegen/runtime/generator/src/kinds/mod.rs @@ -46,8 +46,10 @@ pub struct KindsModel { nonterminal_kinds: BTreeSet, /// Defines the `TerminalKind` enum variants. terminal_kinds: BTreeSet, + /// Defines `TerminalKind::is_identifier` method. + identifier_terminals: BTreeSet, /// Defines `TerminalKind::is_trivia` method. - trivia_scanner_names: BTreeSet, + trivia_terminals: BTreeSet, /// Defines `EdgeLabel` enum variants. labels: BTreeSet, /// Predefined labels for edges. @@ -63,7 +65,8 @@ impl Default for KindsModel { Self { nonterminal_kinds: BTreeSet::default(), terminal_kinds: BTreeSet::default(), - trivia_scanner_names: BTreeSet::default(), + identifier_terminals: BTreeSet::default(), + trivia_terminals: BTreeSet::default(), labels: BTreeSet::default(), predefined_labels: PredefinedLabel::VARIANTS, lexical_contexts: BTreeSet::default(), @@ -108,7 +111,15 @@ impl KindsModel { } } - let trivia_scanner_names = language + let identifier_terminals = language + .items() + .filter_map(|item| match item { + Item::Keyword { item } => Some(item.identifier.clone()), + _ => None, + }) + .collect(); + + let trivia_terminals = language .items() .filter_map(|item| match item { Item::Trivia { item } => Some(item.name.clone()), @@ -149,7 +160,8 @@ impl KindsModel { KindsModel { nonterminal_kinds, terminal_kinds, - trivia_scanner_names, + identifier_terminals, + trivia_terminals, labels, lexical_contexts, root_kind, diff --git a/crates/codegen/runtime/generator/src/lib.rs b/crates/codegen/runtime/generator/src/lib.rs index 1c47a92c6f..b0d42bfb1a 100644 --- a/crates/codegen/runtime/generator/src/lib.rs +++ b/crates/codegen/runtime/generator/src/lib.rs @@ -94,8 +94,8 @@ impl Default for RuntimeModel { Self { slang_version: Version::new(0, 0, 0), language_name: "CodegenRuntime".to_string(), - all_language_versions: BTreeSet::default(), - breaking_language_versions: BTreeSet::default(), + all_language_versions: BTreeSet::from([Version::new(0, 0, 0)]), + breaking_language_versions: BTreeSet::from([Version::new(0, 0, 0)]), ast: AstModel::default(), bindings: BindingsModel::default(), diff --git a/crates/codegen/runtime/npm/package/src/runtime/parser/index.mts b/crates/codegen/runtime/npm/package/src/runtime/parser/index.mts index ec10da8744..45a5bf5efa 100644 --- a/crates/codegen/runtime/npm/package/src/runtime/parser/index.mts +++ b/crates/codegen/runtime/npm/package/src/runtime/parser/index.mts @@ -5,8 +5,6 @@ export const Parser = wasm.parser.Parser; /** {@inheritDoc wasm.parser.Parser} */ export type Parser = wasm.parser.Parser; -/** {@inheritDoc wasm.parser.ParseError} */ -export const ParseError = wasm.parser.ParseError; /** {@inheritDoc wasm.parser.ParseError} */ export type ParseError = wasm.parser.ParseError; diff --git a/crates/codegen/runtime/npm/package/wasm/generated/codegen_runtime_cargo_wasm.component.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/codegen_runtime_cargo_wasm.component.d.ts index 959f0ad174..0e3bde1a8b 100644 --- a/crates/codegen/runtime/npm/package/wasm/generated/codegen_runtime_cargo_wasm.component.d.ts +++ b/crates/codegen/runtime/npm/package/wasm/generated/codegen_runtime_cargo_wasm.component.d.ts @@ -3,12 +3,12 @@ import { NomicFoundationSlangCst } from "./interfaces/nomic-foundation-slang-cst.js"; import { NomicFoundationSlangAst } from "./interfaces/nomic-foundation-slang-ast.js"; import { NomicFoundationSlangBindings } from "./interfaces/nomic-foundation-slang-bindings.js"; -import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangParser } from "./interfaces/nomic-foundation-slang-parser.js"; +import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangUtils } from "./interfaces/nomic-foundation-slang-utils.js"; export * as cst from "./interfaces/nomic-foundation-slang-cst.js"; export * as ast from "./interfaces/nomic-foundation-slang-ast.js"; export * as bindings from "./interfaces/nomic-foundation-slang-bindings.js"; -export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as parser from "./interfaces/nomic-foundation-slang-parser.js"; +export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as utils from "./interfaces/nomic-foundation-slang-utils.js"; diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts index 9cfdd7498c..9c05d8998f 100644 --- a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts @@ -38,13 +38,17 @@ export enum BindingLocationType { */ export class BindingGraph { /** - * If the provided cursor points at a definition `Identifier`, it will return the - * corresponding definition. Otherwise, it will return `undefined`. + * Tries to resolve the identifier terminal pointed at by the provided cursor to a definition. + * If successful, returns the definition. Otherwise, returns `undefined`. + * + * For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. */ definitionAt(cursor: Cursor): Definition | undefined; /** - * If the provided cursor points at a reference `Identifier`, it will return the - * corresponding reference. Otherwise, it will return `undefined`. + * Tries to resolve the identifier terminal pointed at by the provided cursor to a reference. + * If successful, returns the reference. Otherwise, returns `undefined`. + * + * For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. */ referenceAt(cursor: Cursor): Reference | undefined; } diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts index c08b1eed29..61ed78a016 100644 --- a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts @@ -11,6 +11,8 @@ import type { NonterminalNode } from "./nomic-foundation-slang-cst.js"; export { NonterminalNode }; import type { Cursor } from "./nomic-foundation-slang-cst.js"; export { Cursor }; +import type { ParseError } from "./nomic-foundation-slang-parser.js"; +export { ParseError }; /** * Contains information about imports found in an added source file. */ @@ -65,6 +67,10 @@ export class File { * Returns the syntax tree of this file. */ get tree(): NonterminalNode; + /** + * Returns a list of all errors encountered during parsing this file. + */ + errors(): ParseError[]; /** * Creates a cursor for traversing the syntax tree of this file. */ diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts index dc47a9de9e..ee3c02d908 100644 --- a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts @@ -143,30 +143,13 @@ export interface Edge { node: Node; } /** - * Represents an error that occurred while parsing a query. - */ -export interface QueryError { - /** - * The error message describing what went wrong. - */ - message: string; - /** - * The line number where the error occurred. - */ - line: number; - /** - * The column number where the error occurred. - */ - column: number; -} -/** - * Represents a match found by executing a query. + * Represents a match found by executing queries on a cursor. */ export interface QueryMatch { /** * The index of the query that produced this match. */ - queryNumber: number; + queryIndex: number; /** * List of captured nodes and their names from the query. */ @@ -215,6 +198,19 @@ export interface TextRange { */ end: TextIndex; } +/** + * Represents an error that occurred while parsing a query. + */ +export interface QueryError { + /** + * A human-readable message describing what went wrong. + */ + message: string; + /** + * The text range where the error occurred in the query code. + */ + textRange: TextRange; +} /** * Iterator over all ancestors of the current node, starting with the immediate parent, and moving upwards, ending with the root node. @@ -320,7 +316,7 @@ export class Cursor { /** * Moves to the nth child of the current node. */ - goToNthChild(childNumber: number): boolean; + goToNthChild(childIndex: number): boolean; /** * Moves to the next sibling node. */ @@ -448,7 +444,7 @@ export class Query { * Parses a query string into a query object. * Throws an error if the query syntax is invalid. */ - static parse(text: string): Query; + static create(text: string): Query; } /** @@ -470,11 +466,15 @@ export class QueryMatchIterator { */ export class TerminalKindExtensions { /** - * Returns true if the terminal is a trivia token. i.e. whitespace, comments, etc... + * Returns `true` if the terminal is an identifier token. + */ + static isIdentifier(kind: TerminalKind): boolean; + /** + * Returns `true` if the terminal is a trivia token. i.e. whitespace, comments, etc... */ static isTrivia(kind: TerminalKind): boolean; /** - * Returns true if the terminal is a valid token in the language grammar. + * Returns `true` if the terminal is a valid token in the language grammar. */ static isValid(kind: TerminalKind): boolean; } diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts index 07fe4156a6..8382b6ed99 100644 --- a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts @@ -2,7 +2,6 @@ export namespace NomicFoundationSlangParser { export { Parser }; - export { ParseError }; export { ParseOutput }; } import type { Cursor } from "./nomic-foundation-slang-cst.js"; @@ -13,19 +12,18 @@ import type { NonterminalKind } from "./nomic-foundation-slang-cst.js"; export { NonterminalKind }; import type { TextRange } from "./nomic-foundation-slang-cst.js"; export { TextRange }; - /** - * Contains information about where the error occurred and what went wrong. + * Represents an error that occurred while parsing source code. */ -export class ParseError { +export interface ParseError { /** - * Returns the text range where the error occurred in the source code. + * A human-readable message describing what went wrong. */ - get textRange(): TextRange; + message: string; /** - * Returns a human-readable message describing the parsing error. + * The text range where the error occurred in the source code. */ - get message(): string; + textRange: TextRange; } /** @@ -40,7 +38,7 @@ export class ParseOutput { get tree(): NonterminalNode; /** * Returns a list of all parsing errors encountered. - * An empty list indicates successful parsing with no errors. + * An empty list indicates a successful parse with no errors. */ errors(): ParseError[]; /** @@ -60,11 +58,6 @@ export class ParseOutput { * Each parser is configured for a specific language version and grammar. */ export class Parser { - /** - * Returns the root nonterminal kind for this parser's grammar. - * This represents the starting point for parsing a complete source file. - */ - static rootKind(): NonterminalKind; /** * Creates a new parser instance for the specified language version. */ @@ -74,7 +67,11 @@ export class Parser { */ get languageVersion(): string; /** - * Parses the input string starting from the specified nonterminal kind. + * Parses the input string into a complete source file. + */ + parseFileContents(input: string): ParseOutput; + /** + * Parses the input string into a nonterminal with the specified kind. */ - parse(kind: NonterminalKind, input: string): ParseOutput; + parseNonterminal(kind: NonterminalKind, input: string): ParseOutput; } diff --git a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts index 0a3e19de1c..9010760119 100644 --- a/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts +++ b/crates/codegen/runtime/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts @@ -11,5 +11,13 @@ export class LanguageFacts { /** * Returns a list of language versions supported by Slang, sorted ascendingly. */ - static supportedVersions(): string[]; + static allVersions(): string[]; + /** + * Returns the earliest language version supported by Slang. + */ + static earliestVersion(): string; + /** + * Returns the latest language version supported by Slang. + */ + static latestVersion(): string; } diff --git a/crates/metaslang/cst/generated/public_api.txt b/crates/metaslang/cst/generated/public_api.txt index 3d9b7a7426..3430ddd159 100644 --- a/crates/metaslang/cst/generated/public_api.txt +++ b/crates/metaslang/cst/generated/public_api.txt @@ -26,7 +26,7 @@ pub fn metaslang_cst::cursor::Cursor::go_to_next_sibling(&mut self) -> bool pub fn metaslang_cst::cursor::Cursor::go_to_next_terminal(&mut self) -> bool pub fn metaslang_cst::cursor::Cursor::go_to_next_terminal_with_kind(&mut self, kind: ::TerminalKind) -> bool pub fn metaslang_cst::cursor::Cursor::go_to_next_terminal_with_kinds(&mut self, kinds: &[::TerminalKind]) -> bool -pub fn metaslang_cst::cursor::Cursor::go_to_nth_child(&mut self, child_number: usize) -> bool +pub fn metaslang_cst::cursor::Cursor::go_to_nth_child(&mut self, child_index: usize) -> bool pub fn metaslang_cst::cursor::Cursor::go_to_parent(&mut self) -> bool pub fn metaslang_cst::cursor::Cursor::go_to_previous(&mut self) -> bool pub fn metaslang_cst::cursor::Cursor::go_to_previous_sibling(&mut self) -> bool @@ -80,8 +80,9 @@ pub type metaslang_cst::kinds::KindTypes::NonterminalKind: metaslang_cst::kinds: pub type metaslang_cst::kinds::KindTypes::TerminalKind: metaslang_cst::kinds::TerminalKindExtensions pub trait metaslang_cst::kinds::NonterminalKindExtensions: metaslang_cst::kinds::BaseKind pub trait metaslang_cst::kinds::TerminalKindExtensions: metaslang_cst::kinds::BaseKind -pub fn metaslang_cst::kinds::TerminalKindExtensions::is_trivia(&self) -> bool -pub fn metaslang_cst::kinds::TerminalKindExtensions::is_valid(&self) -> bool +pub fn metaslang_cst::kinds::TerminalKindExtensions::is_identifier(self) -> bool +pub fn metaslang_cst::kinds::TerminalKindExtensions::is_trivia(self) -> bool +pub fn metaslang_cst::kinds::TerminalKindExtensions::is_valid(self) -> bool pub mod metaslang_cst::nodes pub enum metaslang_cst::nodes::Node pub metaslang_cst::nodes::Node::Nonterminal(alloc::rc::Rc>) @@ -94,7 +95,7 @@ pub fn metaslang_cst::nodes::Node::as_terminal(&self) -> core::option::Option pub fn metaslang_cst::nodes::Node::as_terminal_with_kind(&self, kind: ::TerminalKind) -> core::option::Option<&alloc::rc::Rc>> pub fn metaslang_cst::nodes::Node::as_terminal_with_kinds(&self, kinds: &[::TerminalKind]) -> core::option::Option<&alloc::rc::Rc>> pub fn metaslang_cst::nodes::Node::children(&self) -> &[metaslang_cst::nodes::Edge] -pub fn metaslang_cst::nodes::Node::cursor_with_offset(self, text_offset: metaslang_cst::text_index::TextIndex) -> metaslang_cst::cursor::Cursor +pub fn metaslang_cst::nodes::Node::create_cursor(self, text_offset: metaslang_cst::text_index::TextIndex) -> metaslang_cst::cursor::Cursor pub fn metaslang_cst::nodes::Node::descendants(self) -> metaslang_cst::cursor::CursorIterator pub fn metaslang_cst::nodes::Node::id(&self) -> usize pub fn metaslang_cst::nodes::Node::into_nonterminal(self) -> core::option::Option>> @@ -149,12 +150,11 @@ pub metaslang_cst::nodes::NonterminalNode::kind: metaslang_cst::nodes::NonterminalNode pub fn metaslang_cst::nodes::NonterminalNode::children(self: &alloc::rc::Rc) -> &[metaslang_cst::nodes::Edge] -pub fn metaslang_cst::nodes::NonterminalNode::cursor_with_offset(self: alloc::rc::Rc, text_offset: metaslang_cst::text_index::TextIndex) -> metaslang_cst::cursor::Cursor +pub fn metaslang_cst::nodes::NonterminalNode::create(kind: ::NonterminalKind, children: alloc::vec::Vec>) -> alloc::rc::Rc +pub fn metaslang_cst::nodes::NonterminalNode::create_cursor(self: alloc::rc::Rc, text_offset: metaslang_cst::text_index::TextIndex) -> metaslang_cst::cursor::Cursor pub fn metaslang_cst::nodes::NonterminalNode::descendants(self: alloc::rc::Rc) -> metaslang_cst::cursor::CursorIterator pub fn metaslang_cst::nodes::NonterminalNode::id(self: &alloc::rc::Rc) -> usize pub fn metaslang_cst::nodes::NonterminalNode::unparse(&self) -> alloc::string::String -impl metaslang_cst::nodes::NonterminalNode -pub fn metaslang_cst::nodes::NonterminalNode::new(kind: ::NonterminalKind, children: alloc::vec::Vec>) -> Self impl core::clone::Clone for metaslang_cst::nodes::NonterminalNode where ::NonterminalKind: core::clone::Clone pub fn metaslang_cst::nodes::NonterminalNode::clone(&self) -> metaslang_cst::nodes::NonterminalNode impl core::cmp::Eq for metaslang_cst::nodes::NonterminalNode where ::NonterminalKind: core::cmp::Eq @@ -170,7 +170,8 @@ pub metaslang_cst::nodes::TerminalNode::kind: metaslang_cst::nodes::TerminalNode pub fn metaslang_cst::nodes::TerminalNode::children(self: &alloc::rc::Rc) -> &[metaslang_cst::nodes::Edge] -pub fn metaslang_cst::nodes::TerminalNode::cursor_with_offset(self: alloc::rc::Rc, text_offset: metaslang_cst::text_index::TextIndex) -> metaslang_cst::cursor::Cursor +pub fn metaslang_cst::nodes::TerminalNode::create(kind: ::TerminalKind, text: alloc::string::String) -> alloc::rc::Rc +pub fn metaslang_cst::nodes::TerminalNode::create_cursor(self: alloc::rc::Rc, text_offset: metaslang_cst::text_index::TextIndex) -> metaslang_cst::cursor::Cursor pub fn metaslang_cst::nodes::TerminalNode::descendants(self: alloc::rc::Rc) -> metaslang_cst::cursor::CursorIterator pub fn metaslang_cst::nodes::TerminalNode::id(self: &alloc::rc::Rc) -> usize pub fn metaslang_cst::nodes::TerminalNode::unparse(&self) -> alloc::string::String @@ -203,7 +204,7 @@ pub struct metaslang_cst::query::Query pub metaslang_cst::query::Query::ast_node: ASTNode pub metaslang_cst::query::Query::capture_quantifiers: alloc::collections::btree::map::BTreeMap impl metaslang_cst::query::Query -pub fn metaslang_cst::query::Query::parse(text: &str) -> core::result::Result +pub fn metaslang_cst::query::Query::create(text: &str) -> core::result::Result impl core::clone::Clone for metaslang_cst::query::Query pub fn metaslang_cst::query::Query::clone(&self) -> metaslang_cst::query::Query impl core::fmt::Debug for metaslang_cst::query::Query @@ -211,9 +212,8 @@ pub fn metaslang_cst::query::Query::fmt(&self, f: &mut core::fmt::Formatter<' impl core::fmt::Display for metaslang_cst::query::Query pub fn metaslang_cst::query::Query::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub struct metaslang_cst::query::QueryError -pub metaslang_cst::query::QueryError::column: usize -pub metaslang_cst::query::QueryError::line: usize pub metaslang_cst::query::QueryError::message: alloc::string::String +pub metaslang_cst::query::QueryError::text_range: metaslang_cst::text_index::TextRange impl core::clone::Clone for metaslang_cst::query::QueryError pub fn metaslang_cst::query::QueryError::clone(&self) -> metaslang_cst::query::QueryError impl core::error::Error for metaslang_cst::query::QueryError @@ -224,7 +224,7 @@ pub fn metaslang_cst::query::QueryError::fmt(&self, f: &mut core::fmt::Formatter pub struct metaslang_cst::query::QueryMatch pub metaslang_cst::query::QueryMatch::captures: alloc::collections::btree::map::BTreeMap>> pub metaslang_cst::query::QueryMatch::queries: alloc::rc::Rc>> -pub metaslang_cst::query::QueryMatch::query_number: usize +pub metaslang_cst::query::QueryMatch::query_index: usize pub metaslang_cst::query::QueryMatch::root_cursor: metaslang_cst::cursor::Cursor impl metaslang_cst::query::QueryMatch pub fn metaslang_cst::query::QueryMatch::capture(&self, name: &str) -> core::option::Option<(metaslang_cst::query::CaptureQuantifier, impl core::iter::traits::iterator::Iterator>)> diff --git a/crates/metaslang/cst/src/cursor.rs b/crates/metaslang/cst/src/cursor.rs index ce8f810156..ddd01c3cd2 100644 --- a/crates/metaslang/cst/src/cursor.rs +++ b/crates/metaslang/cst/src/cursor.rs @@ -11,7 +11,7 @@ use crate::text_index::{TextIndex, TextRange}; struct PathAncestor { parent: Option>>, nonterminal_node: Rc>, - child_number: usize, + child_index: usize, text_offset: TextIndex, } @@ -26,7 +26,7 @@ pub struct Cursor { 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, + child_index: usize, /// Text offset that corresponds to the beginning of the currently pointed to node. text_offset: TextIndex, /// Whether the cursor is completed, i.e. at the root node as a result of traversal (or when `complete`d). @@ -40,7 +40,7 @@ impl Cursor { Some(Rc::new(PathAncestor { parent: self.parent.clone(), nonterminal_node: Rc::clone(nonterminal_node), - child_number: self.child_number, + child_index: self.child_index, text_offset: self.text_offset, })) } else { @@ -51,17 +51,17 @@ impl Cursor { fn set_from_ancestor_node(&mut self, ancestor: &Rc>) { self.parent = ancestor.parent.clone(); self.node = Node::::Nonterminal(Rc::clone(&ancestor.nonterminal_node)); - self.child_number = ancestor.child_number; + self.child_index = ancestor.child_index; self.text_offset = ancestor.text_offset; } } impl Cursor { - pub(crate) fn new(node: Node, text_offset: TextIndex) -> Self { + pub(crate) fn create(node: Node, text_offset: TextIndex) -> Self { Self { parent: None, node, - child_number: 0, + child_index: 0, text_offset, is_completed: false, } @@ -94,7 +94,7 @@ impl Cursor { is_completed: false, parent: None, node: self.node.clone(), - child_number: 0, + child_index: 0, text_offset: self.text_offset, } } @@ -111,7 +111,7 @@ impl Cursor { pub fn label(&self) -> Option { self.parent.as_ref().and_then(|parent| { - let this = &parent.nonterminal_node.children[self.child_number]; + let this = &parent.nonterminal_node.children[self.child_index]; this.label }) @@ -248,7 +248,7 @@ impl Cursor { if let Some(new_child) = new_parent.nonterminal_node.children.first().cloned() { self.parent = Some(new_parent); self.node = new_child.node; - self.child_number = 0; + self.child_index = 0; return true; } @@ -267,10 +267,10 @@ impl Cursor { if let Some(new_parent) = self.as_ancestor_node() { if let Some(new_child) = new_parent.nonterminal_node.children.last().cloned() { - self.child_number = new_parent.nonterminal_node.children.len() - 1; + self.child_index = new_parent.nonterminal_node.children.len() - 1; self.node = new_child.node; // Remember: range is not inclusive - for sibling in &new_parent.nonterminal_node.children[..self.child_number] { + for sibling in &new_parent.nonterminal_node.children[..self.child_index] { self.text_offset += sibling.text_len(); } self.parent = Some(new_parent); @@ -285,7 +285,7 @@ impl Cursor { /// Attempts to go to current node's nth child. /// /// Returns `false` if the cursor is finished or there's no child to go to. - pub fn go_to_nth_child(&mut self, child_number: usize) -> bool { + pub fn go_to_nth_child(&mut self, child_index: usize) -> bool { if self.is_completed { return false; } @@ -294,13 +294,13 @@ impl Cursor { if let Some(new_child) = new_parent .nonterminal_node .children - .get(child_number) + .get(child_index) .cloned() { - self.child_number = child_number; + self.child_index = child_index; self.node = new_child.node; // Remember: range is not inclusive - for sibling in &new_parent.nonterminal_node.children[..self.child_number] { + for sibling in &new_parent.nonterminal_node.children[..self.child_index] { self.text_offset += sibling.text_len(); } self.parent = Some(new_parent); @@ -321,10 +321,10 @@ impl Cursor { } if let Some(parent) = &self.parent { - let new_child_number = self.child_number + 1; + let new_child_number = self.child_index + 1; if let Some(new_child) = parent.nonterminal_node.children.get(new_child_number) { self.text_offset += self.node.text_len(); - self.child_number = new_child_number; + self.child_index = new_child_number; self.node = new_child.node.clone(); return true; @@ -343,14 +343,14 @@ impl Cursor { } if let Some(parent) = &self.parent { - if self.child_number > 0 { - let new_child_number = self.child_number - 1; + if self.child_index > 0 { + let new_child_number = self.child_index - 1; let new_child = &parent.nonterminal_node.children[new_child_number]; - self.child_number = new_child_number; + self.child_index = new_child_number; self.node = new_child.node.clone(); // Remember: range is not inclusive self.text_offset = parent.text_offset; - for sibling in &parent.nonterminal_node.children[..self.child_number] { + for sibling in &parent.nonterminal_node.children[..self.child_index] { self.text_offset += sibling.text_len(); } diff --git a/crates/metaslang/cst/src/kinds.rs b/crates/metaslang/cst/src/kinds.rs index efd0ab01d4..9e14d3db57 100644 --- a/crates/metaslang/cst/src/kinds.rs +++ b/crates/metaslang/cst/src/kinds.rs @@ -29,12 +29,16 @@ where } pub trait TerminalKindExtensions: BaseKind { - fn is_trivia(&self) -> bool { + fn is_identifier(self) -> bool { + false + } + + fn is_trivia(self) -> bool { false } /// Returns whether the terminal is valid, i.e. does not represent missing or invalid syntax. - fn is_valid(&self) -> bool { + fn is_valid(self) -> bool { true } } diff --git a/crates/metaslang/cst/src/nodes.rs b/crates/metaslang/cst/src/nodes.rs index 10ad1602ea..861e7211cf 100644 --- a/crates/metaslang/cst/src/nodes.rs +++ b/crates/metaslang/cst/src/nodes.rs @@ -36,18 +36,6 @@ pub struct Edge { pub node: Node, } -impl NonterminalNode { - pub fn new(kind: T::NonterminalKind, children: Vec>) -> Self { - let text_len = children.iter().map(|edge| edge.text_len()).sum(); - - NonterminalNode { - kind, - text_len, - children, - } - } -} - impl Edge { /// Creates an anonymous node (without a label). pub fn anonymous(node: Node) -> Self { @@ -65,11 +53,11 @@ impl std::ops::Deref for Edge { impl Node { pub fn nonterminal(kind: T::NonterminalKind, children: Vec>) -> Self { - Self::Nonterminal(Rc::new(NonterminalNode::new(kind, children))) + Self::Nonterminal(NonterminalNode::create(kind, children)) } pub fn terminal(kind: T::TerminalKind, text: String) -> Self { - Self::Terminal(Rc::new(TerminalNode { kind, text })) + Self::Terminal(TerminalNode::create(kind, text)) } /// Returns a unique identifier of the node. It is not reproducable over parses @@ -105,12 +93,12 @@ impl Node { /// Returns an iterator over all descendants of the current node in pre-order traversal. pub fn descendants(self) -> CursorIterator { - Cursor::new(self, TextIndex::ZERO).descendants() + Cursor::create(self, TextIndex::ZERO).descendants() } /// Creates a [`Cursor`] that starts at the current node as the root and a given initial `text_offset`. - pub fn cursor_with_offset(self, text_offset: TextIndex) -> Cursor { - Cursor::new(self, text_offset) + pub fn create_cursor(self, text_offset: TextIndex) -> Cursor { + Cursor::create(self, text_offset) } /// Reconstructs the original source code from the node and its sub-tree. @@ -221,6 +209,16 @@ impl From>> for Node { } impl NonterminalNode { + pub fn create(kind: T::NonterminalKind, children: Vec>) -> Rc { + let text_len = children.iter().map(|edge| edge.text_len()).sum(); + + Rc::new(Self { + kind, + text_len, + children, + }) + } + /// Returns a unique identifier of the node. It is not reproducable over parses /// and cannot be used in a persistent/serialised sense. pub fn id(self: &Rc) -> usize { @@ -238,8 +236,8 @@ impl NonterminalNode { } /// Creates a [`Cursor`] that starts at the current node as the root and a given initial `text_offset`. - pub fn cursor_with_offset(self: Rc, text_offset: TextIndex) -> Cursor { - Node::Nonterminal(self).cursor_with_offset(text_offset) + pub fn create_cursor(self: Rc, text_offset: TextIndex) -> Cursor { + Node::Nonterminal(self).create_cursor(text_offset) } /// Reconstructs the original source code from the node and its sub-tree. @@ -260,6 +258,10 @@ impl NonterminalNode { } impl TerminalNode { + pub fn create(kind: T::TerminalKind, text: String) -> Rc { + Rc::new(Self { kind, text }) + } + /// Returns a unique identifier of the node. It is not reproducable over parses /// and cannot be used in a persistent/serialised sense. pub fn id(self: &Rc) -> usize { @@ -277,8 +279,8 @@ impl TerminalNode { } /// Creates a [`Cursor`] that starts at the current node as the root and a given initial `text_offset`. - pub fn cursor_with_offset(self: Rc, text_offset: TextIndex) -> Cursor { - Node::Terminal(self).cursor_with_offset(text_offset) + pub fn create_cursor(self: Rc, text_offset: TextIndex) -> Cursor { + Node::Terminal(self).create_cursor(text_offset) } /// Reconstructs the original source code from the node and its sub-tree. diff --git a/crates/metaslang/cst/src/query/engine.rs b/crates/metaslang/cst/src/query/engine.rs index a49681ee7c..3b08b0c045 100644 --- a/crates/metaslang/cst/src/query/engine.rs +++ b/crates/metaslang/cst/src/query/engine.rs @@ -147,7 +147,7 @@ impl ASTNode { pub struct QueryMatch { pub queries: Rc>>, - pub query_number: usize, + pub query_index: usize, pub root_cursor: Cursor, // These correspond to the capture definitions in the query pub captures: BTreeMap>>, @@ -155,7 +155,7 @@ pub struct QueryMatch { impl QueryMatch { pub fn query(&self) -> &Query { - &self.queries[self.query_number] + &self.queries[self.query_index] } pub fn capture_names(&self) -> impl Iterator { @@ -197,7 +197,7 @@ impl QueryMatch { pub struct QueryMatchIterator { queries: Rc>>, cursor: Cursor, - query_number: usize, + query_index: usize, matcher: Option>, } @@ -206,24 +206,24 @@ impl QueryMatchIterator { Self { queries: Rc::new(queries), cursor, - query_number: 0, + query_index: 0, matcher: None, } } fn advance_to_next_possible_matching_query(&mut self) { while !self.cursor.is_completed() { - while self.query_number < self.queries.len() { - let ast_node = &self.queries[self.query_number].ast_node; + while self.query_index < self.queries.len() { + let ast_node = &self.queries[self.query_index].ast_node; if ast_node.can_match(&self.cursor) { // The first matcher in the query should allow implicit matches self.matcher = Some(ast_node.create_matcher(self.cursor.clone(), false)); return; }; - self.query_number += 1; + self.query_index += 1; } self.cursor.go_to_next(); - self.query_number = 0; + self.query_index = 0; } } } @@ -240,11 +240,11 @@ impl Iterator for QueryMatchIterator { return Some(QueryMatch { queries: Rc::clone(&self.queries), root_cursor: self.cursor.clone(), - query_number: self.query_number, + query_index: self.query_index, captures, }); } - self.query_number += 1; + self.query_index += 1; } self.advance_to_next_possible_matching_query(); diff --git a/crates/metaslang/cst/src/query/model.rs b/crates/metaslang/cst/src/query/model.rs index c97a40b19a..6a593d6d58 100644 --- a/crates/metaslang/cst/src/query/model.rs +++ b/crates/metaslang/cst/src/query/model.rs @@ -4,6 +4,7 @@ use std::rc::Rc; use crate::kinds::{BaseKind, KindTypes, NodeKind}; use crate::query::{CaptureQuantifier, QueryError}; +use crate::text_index::TextIndex; #[derive(Clone, Debug)] pub struct Query { @@ -12,7 +13,7 @@ pub struct Query { } impl Query { - pub fn parse(text: &str) -> Result { + pub fn create(text: &str) -> Result { fn collect_capture_quantifiers( ast_node: &ASTNode, quantifier: CaptureQuantifier, @@ -24,8 +25,7 @@ impl Query { if capture_quantifiers.contains_key(&capture.name) { return Err(QueryError { message: format!("Capture name '{}' used more than once", capture.name), - line: 0, - column: 0, + text_range: TextIndex::ZERO..TextIndex::ZERO, }); } capture_quantifiers.insert(capture.name.clone(), quantifier); @@ -69,8 +69,7 @@ impl Query { return Err(QueryError { message: "Quantification over quantification is not allowed" .to_string(), - line: 0, - column: 0, + text_range: TextIndex::ZERO..TextIndex::ZERO, }) } }; diff --git a/crates/metaslang/cst/src/query/parser.rs b/crates/metaslang/cst/src/query/parser.rs index e8460eb013..c4c0c97fb8 100644 --- a/crates/metaslang/cst/src/query/parser.rs +++ b/crates/metaslang/cst/src/query/parser.rs @@ -18,7 +18,7 @@ use super::model::{ OptionalASTNode, SequenceASTNode, }; use crate::kinds::{BaseKind, KindTypes, NodeKind, TerminalKindExtensions}; -use crate::text_index::TextIndex; +use crate::text_index::{TextIndex, TextRange}; // ---------------------------------------------------------------------------- // Parse errors @@ -26,8 +26,7 @@ use crate::text_index::TextIndex; #[derive(Clone, Debug, Error)] pub struct QueryError { pub message: String, - pub line: usize, - pub column: usize, + pub text_range: TextRange, } impl std::fmt::Display for QueryError { @@ -128,36 +127,20 @@ pub(super) fn parse_query(input: &str) -> Result, Query .parse(input) .finish() .map(|(_, query)| query) - .map_err(|e| { - let text_index = compute_row_and_column(e.errors[0].0, input); - QueryError { - message: e.to_string(), - line: text_index.line, - column: text_index.column, - } + .map_err(|e| QueryError { + message: e.to_string(), + text_range: compute_error_location(input, e.errors[0].0), }) } -fn compute_row_and_column(target: &str, input: &str) -> TextIndex { - let target_offset = input.offset(target); - let mut text_index = TextIndex::ZERO; - let mut from_iter = input.chars(); - let Some(mut c) = from_iter.next() else { - return text_index; - }; - let mut next_c = from_iter.next(); - loop { - if text_index.utf8 >= target_offset { - break; - } - text_index.advance(c, next_c.as_ref()); - c = match next_c { - Some(ch) => ch, - None => break, - }; - next_c = from_iter.next(); - } - text_index +fn compute_error_location(input: &str, target: &str) -> TextRange { + let mut start = TextIndex::ZERO; + start.advance_str(&input[..input.offset(target)]); + + let mut end = start; + end.advance_str(target); + + TextRange { start, end } } fn parse_matcher_alternatives( diff --git a/crates/metaslang/graph_builder/src/execution/lazy.rs b/crates/metaslang/graph_builder/src/execution/lazy.rs index 9b589607bb..fc9cba7a3c 100644 --- a/crates/metaslang/graph_builder/src/execution/lazy.rs +++ b/crates/metaslang/graph_builder/src/execution/lazy.rs @@ -108,7 +108,7 @@ impl ast::File { .collect(); let matches = tree.clone().query(queries); for mat in matches { - let stanza = &self.stanzas[mat.query_number]; + let stanza = &self.stanzas[mat.query_index]; visit(stanza, mat)?; } Ok(()) diff --git a/crates/metaslang/graph_builder/src/parser.rs b/crates/metaslang/graph_builder/src/parser.rs index 85c4a87a82..5ddaceba0a 100644 --- a/crates/metaslang/graph_builder/src/parser.rs +++ b/crates/metaslang/graph_builder/src/parser.rs @@ -13,6 +13,7 @@ use std::str::Chars; use metaslang_cst::kinds::KindTypes; use metaslang_cst::query::CaptureQuantifier::{self, One, OneOrMore, ZeroOrMore, ZeroOrOne}; use metaslang_cst::query::{Query, QueryError}; +use metaslang_cst::text_index::TextIndex; use regex::Regex; use thiserror::Error; @@ -93,8 +94,8 @@ impl std::fmt::Display for DisplayParseErrorPretty<'_> { ParseError::InvalidRegex(_, location) => *location, ParseError::InvalidRegexCapture(location) => *location, ParseError::QueryError(err) => Location { - row: err.line, - column: err.column, + row: err.text_range.start.line, + column: err.text_range.start.column, }, ParseError::UnexpectedCharacter(_, _, location) => *location, ParseError::UnexpectedEOF(location) => *location, @@ -364,23 +365,29 @@ impl<'a> Parser<'a> { } fn parse_query(&mut self) -> Result, ParseError> { - let location = self.location; let query_start = self.offset; self.skip_query()?; let query_end = self.offset; + let query_source = &self.source[query_start..query_end]; - let query = Query::parse(query_source).map_err(|mut e| { - // the column of the first row of a query pattern must be shifted by the whitespace - // that was already consumed - if e.line == 0 { - // must come before we update e.row! - e.column += location.column; - } - e.line += location.row; - // TODO: we should advance the other offsets, but this parser only tracks utf8 - // e.offset += query_start; + + let query = Query::create(query_source).map_err(|mut e| { + let start_offset = query_start + e.text_range.start.utf8; + let end_offset = query_start + e.text_range.end.utf8; + + e.text_range.start = TextIndex::ZERO; + e.text_range + .start + .advance_str(&self.source[0..start_offset]); + + e.text_range.end = e.text_range.start; + e.text_range + .end + .advance_str(&self.source[start_offset..end_offset]); + e })?; + Ok(query) } diff --git a/crates/metaslang/graph_builder/tests/functions.rs b/crates/metaslang/graph_builder/tests/functions.rs index ff0c719040..cc037dfde9 100644 --- a/crates/metaslang/graph_builder/tests/functions.rs +++ b/crates/metaslang/graph_builder/tests/functions.rs @@ -57,7 +57,7 @@ fn execute(dsl_source: &str) -> Result { let config = ExecutionConfig::new(&functions, &globals); let tree = metaslang_cst::nodes::Node::::terminal(DummyKind::Module, "pass".to_owned()); - let cursor = tree.cursor_with_offset(metaslang_cst::text_index::TextIndex::ZERO); + let cursor = tree.create_cursor(metaslang_cst::text_index::TextIndex::ZERO); let graph = file.execute(&cursor, &config, &NoCancellation)?; let result = graph.pretty_print().to_string(); Ok(result) diff --git a/crates/metaslang/graph_builder/tests/graph.rs b/crates/metaslang/graph_builder/tests/graph.rs index 772be57300..1a8d7b9b4e 100644 --- a/crates/metaslang/graph_builder/tests/graph.rs +++ b/crates/metaslang/graph_builder/tests/graph.rs @@ -77,7 +77,7 @@ fn can_iterate_graph_edges() { fn can_display_graph() { let tree = metaslang_cst::nodes::Node::::terminal(DummyKind::Module, "pass".to_owned()); - let cursor = tree.cursor_with_offset(metaslang_cst::text_index::TextIndex::ZERO); + let cursor = tree.create_cursor(metaslang_cst::text_index::TextIndex::ZERO); let mut graph = Graph::::new(); let root = graph.add_syntax_node(cursor); diff --git a/crates/metaslang/graph_builder/tests/parser.rs b/crates/metaslang/graph_builder/tests/parser.rs index a8c4c3cf28..02a4b5f5d6 100644 --- a/crates/metaslang/graph_builder/tests/parser.rs +++ b/crates/metaslang/graph_builder/tests/parser.rs @@ -1584,9 +1584,10 @@ fn query_parse_errors_have_file_location() { Err(e) => panic!("Unexpected error: {e}"), }; assert_eq!(err.message, "Parse error:\n'NonExistingNode' is not a valid node kind at: NonExistingNode ] ]\n \n"); - assert_eq!(err.line, 2, "expected row 2, got {}", err.line); - assert_eq!(err.column, 19, "expected column 19, got {}", err.column); - // assert_eq!(err.offset, 48, "expected offset 48, got {}", err.offset); + assert_eq!( + format!("{:?}", err.text_range), + "TextIndex { utf8: 50, utf16: 50, line: 2, column: 19 }..TextIndex { utf8: 78, utf16: 78, line: 3, column: 8 }", + ); } #[test] @@ -1606,9 +1607,10 @@ fn multiline_query_parse_errors_have_file_location() { Err(e) => panic!("Unexpected error: {e}"), }; assert_eq!(err.message, "Parse error:\n'NonExistingNode' is not a valid node kind at: NonExistingNode ] ]\n )\n \n"); - assert_eq!(err.line, 5, "expected row 5, got {}", err.line); - assert_eq!(err.column, 23, "expected column 23, got {}", err.column); - // assert_eq!(err.offset, 112, "expected offset 112, got {}", err.offset); + assert_eq!( + format!("{:?}", err.text_range), + "TextIndex { utf8: 112, utf16: 112, line: 5, column: 23 }..TextIndex { utf8: 150, utf16: 150, line: 7, column: 8 }", + ); } #[test] diff --git a/crates/solidity/outputs/cargo/cli/src/parse.rs b/crates/solidity/outputs/cargo/cli/src/parse.rs index aaa93302d9..c410c14497 100644 --- a/crates/solidity/outputs/cargo/cli/src/parse.rs +++ b/crates/solidity/outputs/cargo/cli/src/parse.rs @@ -33,7 +33,7 @@ impl ParseCommand { let input = fs::read_to_string(&file_path).unwrap(); let parser = Parser::create(version).unwrap(); - let parse_output = parser.parse(Parser::ROOT_KIND, &input); + let parse_output = parser.parse_file_contents(&input); if !parse_output.is_valid() { const COLOR: bool = true; diff --git a/crates/solidity/outputs/cargo/crate/generated/public_api.txt b/crates/solidity/outputs/cargo/crate/generated/public_api.txt index 7103f279aa..d469e5b22e 100644 --- a/crates/solidity/outputs/cargo/crate/generated/public_api.txt +++ b/crates/solidity/outputs/cargo/crate/generated/public_api.txt @@ -36,6 +36,7 @@ pub fn slang_solidity::compilation::CompilationUnit::language_version(&self) -> pub struct slang_solidity::compilation::File impl slang_solidity::compilation::File pub fn slang_solidity::compilation::File::create_tree_cursor(&self) -> slang_solidity::cst::Cursor +pub fn slang_solidity::compilation::File::errors(&self) -> &alloc::vec::Vec pub fn slang_solidity::compilation::File::id(&self) -> &str pub fn slang_solidity::compilation::File::tree(&self) -> &alloc::rc::Rc impl core::clone::Clone for slang_solidity::compilation::File @@ -891,8 +892,9 @@ impl core::str::traits::FromStr for slang_solidity::cst::TerminalKind pub type slang_solidity::cst::TerminalKind::Err = strum::ParseError pub fn slang_solidity::cst::TerminalKind::from_str(s: &str) -> core::result::Result::Err> impl metaslang_cst::kinds::TerminalKindExtensions for slang_solidity::cst::TerminalKind -pub fn slang_solidity::cst::TerminalKind::is_trivia(&self) -> bool -pub fn slang_solidity::cst::TerminalKind::is_valid(&self) -> bool +pub fn slang_solidity::cst::TerminalKind::is_identifier(self) -> bool +pub fn slang_solidity::cst::TerminalKind::is_trivia(self) -> bool +pub fn slang_solidity::cst::TerminalKind::is_valid(self) -> bool impl serde::ser::Serialize for slang_solidity::cst::TerminalKind pub fn slang_solidity::cst::TerminalKind::serialize<__S>(&self, __serializer: __S) -> core::result::Result<<__S as serde::ser::Serializer>::Ok, <__S as serde::ser::Serializer>::Error> where __S: serde::ser::Serializer impl<'_derivative_strum> core::convert::From<&'_derivative_strum slang_solidity::cst::TerminalKind> for &'static str @@ -965,14 +967,15 @@ pub fn slang_solidity::parser::ParseOutput::fmt(&self, f: &mut core::fmt::Format impl core::marker::StructuralPartialEq for slang_solidity::parser::ParseOutput pub struct slang_solidity::parser::Parser impl slang_solidity::parser::Parser -pub const slang_solidity::parser::Parser::ROOT_KIND: slang_solidity::cst::NonterminalKind pub fn slang_solidity::parser::Parser::create(language_version: semver::Version) -> core::result::Result pub fn slang_solidity::parser::Parser::language_version(&self) -> &semver::Version -pub fn slang_solidity::parser::Parser::parse(&self, kind: slang_solidity::cst::NonterminalKind, input: &str) -> slang_solidity::parser::ParseOutput +pub fn slang_solidity::parser::Parser::parse_file_contents(&self, input: &str) -> slang_solidity::parser::ParseOutput +pub fn slang_solidity::parser::Parser::parse_nonterminal(&self, kind: slang_solidity::cst::NonterminalKind, input: &str) -> slang_solidity::parser::ParseOutput impl core::fmt::Debug for slang_solidity::parser::Parser pub fn slang_solidity::parser::Parser::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result pub mod slang_solidity::utils pub struct slang_solidity::utils::LanguageFacts impl slang_solidity::utils::LanguageFacts -pub const slang_solidity::utils::LanguageFacts::NAME: &'static str -pub const slang_solidity::utils::LanguageFacts::SUPPORTED_VERSIONS: &'static [semver::Version] +pub const slang_solidity::utils::LanguageFacts::ALL_VERSIONS: &'static [semver::Version] +pub const slang_solidity::utils::LanguageFacts::EARLIEST_VERSION: semver::Version +pub const slang_solidity::utils::LanguageFacts::LATEST_VERSION: semver::Version diff --git a/crates/solidity/outputs/cargo/crate/src/extensions/bindings/mod.rs b/crates/solidity/outputs/cargo/crate/src/extensions/bindings/mod.rs index 63a1a8ccaa..84cc9cacf4 100644 --- a/crates/solidity/outputs/cargo/crate/src/extensions/bindings/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/extensions/bindings/mod.rs @@ -14,10 +14,10 @@ pub fn add_built_ins( ) -> Result<(), ParserInitializationError> { let source = get_built_ins_contents(&version); let parser = Parser::create(version)?; - let parse_output = parser.parse(Parser::ROOT_KIND, source); + let parse_output = parser.parse_file_contents(source); let built_ins_cursor = transform(&Node::Nonterminal(Rc::clone(parse_output.tree()))) - .cursor_with_offset(TextIndex::ZERO); + .create_cursor(TextIndex::ZERO); builder.add_system_file("built_ins.sol", built_ins_cursor); Ok(()) diff --git a/crates/solidity/outputs/cargo/crate/src/extensions/compilation/mod.rs b/crates/solidity/outputs/cargo/crate/src/extensions/compilation/mod.rs index 0ba82a945c..f61a275bf4 100644 --- a/crates/solidity/outputs/cargo/crate/src/extensions/compilation/mod.rs +++ b/crates/solidity/outputs/cargo/crate/src/extensions/compilation/mod.rs @@ -25,7 +25,7 @@ impl ImportPathsExtractor { ]", ] .into_iter() - .map(|text| Query::parse(text).unwrap()) + .map(|text| Query::create(text).unwrap()) .collect(), } } @@ -94,7 +94,7 @@ mod tests { fn run(source: &str, expected: &[&str]) { let parser = Parser::create(Version::new(0, 8, 0)).unwrap(); - let parse_output = parser.parse(Parser::ROOT_KIND, source); + let parse_output = parser.parse_file_contents(source); let imports = super::ImportPathsExtractor::new(); diff --git a/crates/solidity/outputs/cargo/crate/src/generated/compilation/file.rs b/crates/solidity/outputs/cargo/crate/src/generated/compilation/file.rs index 2f5fd5bcc3..7a5bf8ed41 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/compilation/file.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/compilation/file.rs @@ -6,20 +6,25 @@ use std::rc::Rc; use metaslang_cst::text_index::TextIndex; use crate::cst::{Cursor, NonterminalNode}; +use crate::parser::{ParseError, ParseOutput}; #[derive(Clone)] pub struct File { id: String, tree: Rc, + errors: Vec, resolved_imports: BTreeMap, } impl File { - pub(super) fn new(id: String, tree: Rc) -> Self { + pub(super) fn create(id: String, parse_output: ParseOutput) -> Self { + let ParseOutput { tree, errors } = parse_output; + Self { id, tree, + errors, resolved_imports: BTreeMap::new(), } @@ -33,8 +38,12 @@ impl File { &self.tree } + pub fn errors(&self) -> &Vec { + &self.errors + } + pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).create_cursor(TextIndex::ZERO) } pub(super) fn resolve_import(&mut self, import_path: &Cursor, destination_file_id: String) { diff --git a/crates/solidity/outputs/cargo/crate/src/generated/compilation/internal_builder.rs b/crates/solidity/outputs/cargo/crate/src/generated/compilation/internal_builder.rs index a0c2ec5e73..c10f90ceae 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/compilation/internal_builder.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/compilation/internal_builder.rs @@ -41,11 +41,11 @@ impl InternalCompilationBuilder { }; } - let parse_output = self.parser.parse(Parser::ROOT_KIND, contents); + let parse_output = self.parser.parse_file_contents(contents); let import_paths = self.imports.extract(parse_output.create_tree_cursor()); - let file = File::new(id.clone(), Rc::clone(parse_output.tree())); + let file = File::create(id.clone(), parse_output); self.files.insert(id, file); AddFileResponse { import_paths } @@ -74,7 +74,7 @@ impl InternalCompilationBuilder { .map(|(id, file)| (id.to_owned(), Rc::new(file.to_owned()))) .collect(); - CompilationUnit::new(language_version, files) + CompilationUnit::create(language_version, files) } } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs b/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs index 4e92751737..312aef257a 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/compilation/unit.rs @@ -19,7 +19,7 @@ pub struct CompilationUnit { } impl CompilationUnit { - pub(super) fn new(language_version: Version, files: BTreeMap>) -> Self { + pub(super) fn create(language_version: Version, files: BTreeMap>) -> Self { Self { language_version, files, diff --git a/crates/solidity/outputs/cargo/crate/src/generated/cst/generated/terminal_kind.rs b/crates/solidity/outputs/cargo/crate/src/generated/cst/generated/terminal_kind.rs index 9de6e34dd0..bd7921302d 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/cst/generated/terminal_kind.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/cst/generated/terminal_kind.rs @@ -2543,7 +2543,11 @@ pub enum TerminalKind { } impl crate::cst::TerminalKindExtensions for TerminalKind { - fn is_trivia(&self) -> bool { + fn is_identifier(self) -> bool { + matches!(self, |Self::Identifier| Self::YulIdentifier) + } + + fn is_trivia(self) -> bool { matches!(self, |Self::EndOfLine| Self::MultiLineComment | Self::MultiLineNatSpecComment | Self::SingleLineComment @@ -2551,7 +2555,7 @@ impl crate::cst::TerminalKindExtensions for TerminalKind { | Self::Whitespace) } - fn is_valid(&self) -> bool { + fn is_valid(self) -> bool { !matches!(self, Self::UNRECOGNIZED | Self::MISSING) } } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/generated/parser.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/generated/parser.rs index 1b2e858edf..f651ebb699 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/generated/parser.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/generated/parser.rs @@ -76,12 +76,10 @@ pub enum ParserInitializationError { } impl Parser { - pub const ROOT_KIND: NonterminalKind = NonterminalKind::SourceUnit; - pub fn create( language_version: Version, ) -> std::result::Result { - if LanguageFacts::SUPPORTED_VERSIONS + if LanguageFacts::ALL_VERSIONS .binary_search(&language_version) .is_ok() { @@ -131,6109 +129,1652 @@ impl Parser { pub fn language_version(&self) -> &Version { &self.language_version - } /******************************************** - * Parser Functions - ********************************************/ - - #[allow(unused_assignments, unused_parens)] - fn abicoder_pragma(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::AbicoderKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::AbicoderKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Version, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::AbicoderPragma) - } - - #[allow(unused_assignments, unused_parens)] - fn additive_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::AdditiveExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn address_type(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::AddressKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::AddressKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::PayableKeyword, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::PayableKeyword, - ), - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::AddressType) - } - - #[allow(unused_assignments, unused_parens)] - fn and_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::AndExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn arguments_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.positional_arguments_declaration(input); - choice.consider(input, result)?; - let result = self.named_arguments_declaration(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::ArgumentsDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn array_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBracket); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBracket, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBracket, - ), - )?; - seq.elem( - self.array_values(input) - .with_label(EdgeLabel::Items) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBracket, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBracket, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBracket, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ArrayExpression) - } - - #[allow(unused_assignments, unused_parens)] - fn array_type_name(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.type_name(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::TypeName => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::ArrayTypeName => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn array_values(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.expression(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::ArrayValues) - } - - #[allow(unused_assignments, unused_parens)] - fn assembly_flags(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.string_literal(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::AssemblyFlags) - } - - #[allow(unused_assignments, unused_parens)] - fn assembly_flags_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.assembly_flags(input) - .with_label(EdgeLabel::Flags) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::AssemblyFlagsDeclaration) } - #[allow(unused_assignments, unused_parens)] - fn assembly_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::AssemblyKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::AssemblyKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Label, - OptionalHelper::transform(self.string_literal(input)), - )?; - seq.elem_labeled( - EdgeLabel::Flags, - OptionalHelper::transform(self.assembly_flags_declaration(input)), - )?; - seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::AssemblyStatement) + pub fn parse_file_contents(&self, input: &str) -> ParseOutput { + self.parse_nonterminal(NonterminalKind::SourceUnit, input) } - - #[allow(unused_assignments, unused_parens)] - fn assignment_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::AssignmentExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn bitwise_and_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::BitwiseAndExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn bitwise_or_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::BitwiseOrExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn bitwise_xor_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::BitwiseXorExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn block(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.statements(input) - .with_label(EdgeLabel::Statements) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::Block) - } - - #[allow(unused_assignments, unused_parens)] - fn break_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - self.parse_terminal_with_trivia::( - input, - TerminalKind::BreakKeyword, - ) - .with_label(EdgeLabel::BreakKeyword) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::BreakStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn call_options(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_2 { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.named_argument(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - ) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::CallOptions) - } - - #[allow(unused_assignments, unused_parens)] - fn call_options_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::CallOptionsExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn catch_clause(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::CatchKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CatchKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Error, - OptionalHelper::transform(self.catch_clause_error(input)), - )?; - seq.elem_labeled(EdgeLabel::Body, self.block(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::CatchClause) - } - - #[allow(unused_assignments, unused_parens)] - fn catch_clause_error(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Name, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - ), - )?; - seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::CatchClauseError) - } - - #[allow(unused_assignments, unused_parens)] - fn catch_clauses(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - OneOrMoreHelper::run(input, |input| { - self.catch_clause(input).with_label(EdgeLabel::Item) - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::CatchClauses) - } - - #[allow(unused_assignments, unused_parens)] - fn comparison_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::ComparisonExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn conditional_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::ConditionalExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn constant_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_7_4 { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - seq.elem_labeled( - EdgeLabel::ConstantKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ConstantKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Equal, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Equal, - ), - )?; - seq.elem_labeled(EdgeLabel::Value, self.expression(input))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ConstantDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn constructor_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_4_22 { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.modifier_invocation(input); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::InternalKeyword, - ); - choice.consider(input, result)?; - if self.version_is_at_least_0_6_0 && !self.version_is_at_least_0_6_7 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::OverrideKeyword, - ); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PayableKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PublicKeyword, - ); - choice.consider(input, result)?; - if self.version_is_at_least_0_6_0 && !self.version_is_at_least_0_6_7 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::VirtualKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ConstructorAttribute) - } - - #[allow(unused_assignments, unused_parens)] - fn constructor_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_4_22 { - ZeroOrMoreHelper::run(input, |input| { - self.constructor_attribute(input) - .with_label(EdgeLabel::Item) - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ConstructorAttributes) - } - - #[allow(unused_assignments, unused_parens)] - fn constructor_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_4_22 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ConstructorKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ConstructorKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; - seq.elem_labeled(EdgeLabel::Attributes, self.constructor_attributes(input))?; - seq.elem_labeled(EdgeLabel::Body, self.block(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ConstructorDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn continue_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - self.parse_terminal_with_trivia::( - input, - TerminalKind::ContinueKeyword, - ) - .with_label(EdgeLabel::ContinueKeyword) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ContinueStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn contract_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - if self.version_is_at_least_0_6_0 { - seq.elem_labeled( - EdgeLabel::AbstractKeyword, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::AbstractKeyword, - ), - ), - )?; - } - seq.elem_labeled( - EdgeLabel::ContractKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ContractKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Inheritance, - OptionalHelper::transform(self.inheritance_specifier(input)), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.contract_members(input) - .with_label(EdgeLabel::Members) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }))?; - seq.finish() - }) - .with_kind(NonterminalKind::ContractDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn contract_member(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.using_directive(input); - choice.consider(input, result)?; - let result = self.function_definition(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_4_22 { - let result = self.constructor_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_6_0 { - let result = self.receive_function_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_6_0 { - let result = self.fallback_function_definition(input); - choice.consider(input, result)?; - } - if !self.version_is_at_least_0_6_0 { - let result = self.unnamed_function_definition(input); - choice.consider(input, result)?; - } - let result = self.modifier_definition(input); - choice.consider(input, result)?; - let result = self.struct_definition(input); - choice.consider(input, result)?; - let result = self.enum_definition(input); - choice.consider(input, result)?; - let result = self.event_definition(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_8_4 { - let result = self.error_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_8 { - let result = self.user_defined_value_type_definition(input); - choice.consider(input, result)?; - } - let result = self.state_variable_definition(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::ContractMember) - } - - #[allow(unused_assignments, unused_parens)] - fn contract_members(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.contract_member(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::ContractMembers) - } - - #[allow(unused_assignments, unused_parens)] - fn decimal_number_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Literal, - self.parse_terminal_with_trivia::( - input, - TerminalKind::DecimalLiteral, - ), - )?; - seq.elem_labeled( - EdgeLabel::Unit, - OptionalHelper::transform(self.number_unit(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::DecimalNumberExpression) - } - - #[allow(unused_assignments, unused_parens)] - fn do_while_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::DoKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::DoKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; - seq.elem_labeled( - EdgeLabel::WhileKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::WhileKeyword, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.expression(input) - .with_label(EdgeLabel::Condition) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::DoWhileStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn elementary_type(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::BoolKeyword, - ); - choice.consider(input, result)?; - if !self.version_is_at_least_0_8_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ByteKeyword, - ); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::StringKeyword, - ); - choice.consider(input, result)?; - let result = self.address_type(input); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::BytesKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::IntKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::UintKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::FixedKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::UfixedKeyword, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::ElementaryType) - } - - #[allow(unused_assignments, unused_parens)] - fn else_branch(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ElseKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ElseKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::ElseBranch) - } - - #[allow(unused_assignments, unused_parens)] - fn emit_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_4_21 { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::EmitKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::EmitKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Event, self.identifier_path(input))?; - seq.elem_labeled(EdgeLabel::Arguments, self.arguments_declaration(input))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::EmitStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn enum_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::EnumKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::EnumKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.enum_members(input) - .with_label(EdgeLabel::Members) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }))?; - seq.finish() - }) - .with_kind(NonterminalKind::EnumDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn enum_members(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| { - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Comma, - EdgeLabel::Separator, - )) - .with_kind(NonterminalKind::EnumMembers) - } - - #[allow(unused_assignments, unused_parens)] - fn equality_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::EqualityExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn error_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_4 { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ErrorKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ErrorKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Members, - self.error_parameters_declaration(input), - )?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ErrorDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn error_parameter(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_4 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - seq.elem_labeled( - EdgeLabel::Name, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ErrorParameter) - } - - #[allow(unused_assignments, unused_parens)] - fn error_parameters(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_4 { - OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.error_parameter(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - )) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ErrorParameters) - } - - #[allow(unused_assignments, unused_parens)] - fn error_parameters_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_4 { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.error_parameters(input) - .with_label(EdgeLabel::Parameters) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ErrorParametersDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn event_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::EventKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::EventKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Parameters, - self.event_parameters_declaration(input), - )?; - seq.elem_labeled( - EdgeLabel::AnonymousKeyword, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::AnonymousKeyword, - ), - ), - )?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::EventDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn event_parameter(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - seq.elem_labeled( - EdgeLabel::IndexedKeyword, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::IndexedKeyword, - ), - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::EventParameter) - } - - #[allow(unused_assignments, unused_parens)] - fn event_parameters(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.event_parameter(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - )) - .with_kind(NonterminalKind::EventParameters) - } - - #[allow(unused_assignments, unused_parens)] - fn event_parameters_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.event_parameters(input) - .with_label(EdgeLabel::Parameters) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::EventParametersDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn experimental_feature(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ); - choice.consider(input, result)?; - let result = self.string_literal(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::ExperimentalFeature) - } - - #[allow(unused_assignments, unused_parens)] - fn experimental_pragma(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ExperimentalKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ExperimentalKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Feature, self.experimental_feature(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::ExperimentalPragma) - } - - #[allow(unused_assignments, unused_parens)] - fn exponentiation_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::ExponentiationExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let parse_left_assignment_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::AssignmentExpression, - 1u8, - 1u8 + 1, - ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Equal, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::BarEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::PlusEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::MinusEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::CaretEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::SlashEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::PercentEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::AsteriskEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::AmpersandEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::LessThanLessThanEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThanGreaterThanEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThanGreaterThanGreaterThanEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - choice.finish(input) - }), - ) - }; - let parse_postfix_conditional_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_postfix_operator( - NonterminalKind::ConditionalExpression, - 3u8, - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::QuestionMark, - self.parse_terminal_with_trivia::( - input, - TerminalKind::QuestionMark, - ), - )?; - seq.elem_labeled(EdgeLabel::TrueExpression, self.expression(input))?; - seq.elem_labeled( - EdgeLabel::Colon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Colon, - ), - )?; - seq.elem_labeled(EdgeLabel::FalseExpression, self.expression(input))?; - seq.finish() - }), - ) - }; - let parse_left_or_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::OrExpression, - 5u8, - 5u8 + 1, - self.parse_terminal_with_trivia::( - input, - TerminalKind::BarBar, - ) - .with_label(EdgeLabel::Operator), - ) - }; - let parse_left_and_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::AndExpression, - 7u8, - 7u8 + 1, - self.parse_terminal_with_trivia::( - input, - TerminalKind::AmpersandAmpersand, - ) - .with_label(EdgeLabel::Operator), - ) - }; - let parse_left_equality_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::EqualityExpression, - 9u8, - 9u8 + 1, - ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::EqualEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::BangEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - choice.finish(input) - }), - ) - }; - let parse_left_comparison_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::ComparisonExpression, - 11u8, - 11u8 + 1, - ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::LessThan, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThan, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::LessThanEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThanEqual, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - choice.finish(input) - }), - ) - }; - let parse_left_bitwise_or_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::BitwiseOrExpression, - 13u8, - 13u8 + 1, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Bar, - ) - .with_label(EdgeLabel::Operator), - ) - }; - let parse_left_bitwise_xor_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::BitwiseXorExpression, - 15u8, - 15u8 + 1, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Caret, - ) - .with_label(EdgeLabel::Operator), - ) - }; - let parse_left_bitwise_and_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::BitwiseAndExpression, - 17u8, - 17u8 + 1, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Ampersand, - ) - .with_label(EdgeLabel::Operator), - ) - }; - let parse_left_shift_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::ShiftExpression, - 19u8, - 19u8 + 1, - ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::LessThanLessThan, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThanGreaterThan, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThanGreaterThanGreaterThan, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - choice.finish(input) - }), - ) - }; - let parse_left_additive_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::AdditiveExpression, - 21u8, - 21u8 + 1, - ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Plus, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Minus, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - choice.finish(input) - }), - ) - }; - let parse_left_multiplicative_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::MultiplicativeExpression, - 23u8, - 23u8 + 1, - ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Asterisk, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Slash, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Percent, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - choice.finish(input) - }), - ) - }; - let parse_left_exponentiation_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::ExponentiationExpression, - 25u8, - 25u8 + 1, - ChoiceHelper::run(input, |mut choice, input| { - if !self.version_is_at_least_0_8_0 { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::AsteriskAsterisk, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - } - choice.finish(input) - }), - ) - }; - let parse_right_exponentiation_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_binary_operator( - NonterminalKind::ExponentiationExpression, - 27u8 + 1, - 27u8, - ChoiceHelper::run(input, |mut choice, input| { - if self.version_is_at_least_0_8_0 { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::AsteriskAsterisk, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - } - choice.finish(input) - }), - ) - }; - let parse_postfix_postfix_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_postfix_operator( - NonterminalKind::PostfixExpression, - 29u8, - ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::PlusPlus, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::MinusMinus, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - choice.finish(input) - }), - ) - }; - let parse_prefix_prefix_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_prefix_operator( - NonterminalKind::PrefixExpression, - 31u8, - ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::PlusPlus, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::MinusMinus, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Tilde, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Bang, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Minus, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::Plus, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - } - let result = self - .parse_terminal_with_trivia::( - input, - TerminalKind::DeleteKeyword, - ) - .with_label(EdgeLabel::Operator); - choice.consider(input, result)?; - choice.finish(input) - }), - ) - }; - let parse_postfix_function_call_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_postfix_operator( - NonterminalKind::FunctionCallExpression, - 33u8, - self.arguments_declaration(input) - .with_label(EdgeLabel::Arguments), - ) - }; - let parse_postfix_call_options_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_postfix_operator( - NonterminalKind::CallOptionsExpression, - 35u8, - ChoiceHelper::run(input, |mut choice, input| { - if self.version_is_at_least_0_6_2 { - let result = SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq . elem (self . call_options (input) . with_label (EdgeLabel :: Options) . recover_until_with_nested_delims :: < _ , LexicalContextType :: Default > (input , self , TerminalKind :: CloseBrace , TerminalAcceptanceThreshold (2u8) ,)) ? ; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }); - choice.consider(input, result)?; - } - choice.finish(input) - }), - ) - }; - let parse_postfix_member_access_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_postfix_operator( - NonterminalKind::MemberAccessExpression, - 37u8, - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Period, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Period, - ), - )?; - seq.elem_labeled( - EdgeLabel::Member, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.finish() - }), - ) - }; - let parse_postfix_index_access_expression = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_postfix_operator( - NonterminalKind::IndexAccessExpression, - 39u8, - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBracket); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBracket, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBracket, - ), - )?; - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Start, - OptionalHelper::transform(self.expression(input)), - )?; - seq.elem_labeled( - EdgeLabel::End, - OptionalHelper::transform(self.index_access_end(input)), - )?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBracket, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBracket, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBracket, - ), - )?; - seq.finish() - }), - ) - }; - let prefix_operator_parser = |input: &mut ParserContext<'_>| { - ChoiceHelper::run(input, |mut choice, input| { - let result = parse_prefix_prefix_expression(input); - choice.consider(input, result)?; - choice.finish(input) - }) - }; - let primary_expression_parser = |input: &mut ParserContext<'_>| { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.new_expression(input); - choice.consider(input, result)?; - let result = self.tuple_expression(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_5_3 { - let result = self.type_expression(input); - choice.consider(input, result)?; - } - let result = self.array_expression(input); - choice.consider(input, result)?; - let result = self.hex_number_expression(input); - choice.consider(input, result)?; - let result = self.decimal_number_expression(input); - choice.consider(input, result)?; - let result = self.string_expression(input); - choice.consider(input, result)?; - let result = self.elementary_type(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_6_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PayableKeyword, - ); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ThisKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::SuperKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::TrueKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::FalseKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - }; - let postfix_operator_parser = |input: &mut ParserContext<'_>| { - ChoiceHelper::run(input, |mut choice, input| { - let result = parse_postfix_conditional_expression(input); - choice.consider(input, result)?; - let result = parse_postfix_postfix_expression(input); - choice.consider(input, result)?; - let result = parse_postfix_function_call_expression(input); - choice.consider(input, result)?; - let result = parse_postfix_call_options_expression(input); - choice.consider(input, result)?; - let result = parse_postfix_member_access_expression(input); - choice.consider(input, result)?; - let result = parse_postfix_index_access_expression(input); - choice.consider(input, result)?; - choice.finish(input) - }) - }; - let binary_operand_parser = |input: &mut ParserContext<'_>| { - SequenceHelper::run(|mut seq| { - seq.elem(ZeroOrMoreHelper::run(input, prefix_operator_parser))?; - seq.elem(primary_expression_parser(input))?; - seq.elem(ZeroOrMoreHelper::run(input, postfix_operator_parser))?; - seq.finish() - }) - }; - let binary_operator_parser = |input: &mut ParserContext<'_>| { - ChoiceHelper::run(input, |mut choice, input| { - let result = parse_left_assignment_expression(input); - choice.consider(input, result)?; - let result = parse_left_or_expression(input); - choice.consider(input, result)?; - let result = parse_left_and_expression(input); - choice.consider(input, result)?; - let result = parse_left_equality_expression(input); - choice.consider(input, result)?; - let result = parse_left_comparison_expression(input); - choice.consider(input, result)?; - let result = parse_left_bitwise_or_expression(input); - choice.consider(input, result)?; - let result = parse_left_bitwise_xor_expression(input); - choice.consider(input, result)?; - let result = parse_left_bitwise_and_expression(input); - choice.consider(input, result)?; - let result = parse_left_shift_expression(input); - choice.consider(input, result)?; - let result = parse_left_additive_expression(input); - choice.consider(input, result)?; - let result = parse_left_multiplicative_expression(input); - choice.consider(input, result)?; - let result = parse_left_exponentiation_expression(input); - choice.consider(input, result)?; - let result = parse_right_exponentiation_expression(input); - choice.consider(input, result)?; - choice.finish(input) - }) - }; - let linear_expression_parser = |input: &mut ParserContext<'_>| { - SequenceHelper::run(|mut seq| { - seq.elem(binary_operand_parser(input))?; - seq.elem(ZeroOrMoreHelper::run(input, |input| { - SequenceHelper::run(|mut seq| { - seq.elem(binary_operator_parser(input))?; - seq.elem(binary_operand_parser(input))?; - seq.finish() - }) - }))?; - seq.finish() - }) - }; - PrecedenceHelper::reduce_precedence_result( - NonterminalKind::Expression, - linear_expression_parser(input), - ) - .with_kind(NonterminalKind::Expression) - } - - #[allow(unused_assignments, unused_parens)] - fn expression_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - self.expression(input) - .with_label(EdgeLabel::Expression) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ExpressionStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn fallback_function_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.modifier_invocation(input); - choice.consider(input, result)?; - let result = self.override_specifier(input); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ExternalKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PayableKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PureKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ViewKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::VirtualKeyword, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::FallbackFunctionAttribute) - } - - #[allow(unused_assignments, unused_parens)] - fn fallback_function_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - ZeroOrMoreHelper::run(input, |input| { - self.fallback_function_attribute(input) - .with_label(EdgeLabel::Item) - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::FallbackFunctionAttributes) - } - - #[allow(unused_assignments, unused_parens)] - fn fallback_function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::FallbackKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::FallbackKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; - seq.elem_labeled( - EdgeLabel::Attributes, - self.fallback_function_attributes(input), - )?; - seq.elem_labeled( - EdgeLabel::Returns, - OptionalHelper::transform(self.returns_declaration(input)), - )?; - seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::FallbackFunctionDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn for_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ForKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ForKeyword, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Initialization, - self.for_statement_initialization(input), - )?; - seq.elem_labeled( - EdgeLabel::Condition, - self.for_statement_condition(input), - )?; - seq.elem_labeled( - EdgeLabel::Iterator, - OptionalHelper::transform(self.expression(input)), - )?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }))?; - seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::ForStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn for_statement_condition(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.expression_statement(input); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::ForStatementCondition) - } - - #[allow(unused_assignments, unused_parens)] - fn for_statement_initialization(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.tuple_deconstruction_statement(input); - choice.consider(input, result)?; - let result = self.variable_declaration_statement(input); - choice.consider(input, result)?; - let result = self.expression_statement(input); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::ForStatementInitialization) - } - - #[allow(unused_assignments, unused_parens)] - fn function_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.modifier_invocation(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_6_0 { - let result = self.override_specifier(input); - choice.consider(input, result)?; - } - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ConstantKeyword, - ); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ExternalKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::InternalKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PayableKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PrivateKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PublicKeyword, - ); - choice.consider(input, result)?; - if self.version_is_at_least_0_4_16 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PureKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_4_16 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ViewKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_6_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::VirtualKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::FunctionAttribute) - } - - #[allow(unused_assignments, unused_parens)] - fn function_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.function_attribute(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::FunctionAttributes) - } - - #[allow(unused_assignments, unused_parens)] - fn function_body(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.block(input); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::FunctionBody) - } - - #[allow(unused_assignments, unused_parens)] - fn function_call_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::FunctionCallExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::FunctionKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::FunctionKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Name, self.function_name(input))?; - seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; - seq.elem_labeled(EdgeLabel::Attributes, self.function_attributes(input))?; - seq.elem_labeled( - EdgeLabel::Returns, - OptionalHelper::transform(self.returns_declaration(input)), - )?; - seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::FunctionDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn function_name(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::FallbackKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ReceiveKeyword, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::FunctionName) - } - - #[allow(unused_assignments, unused_parens)] - fn function_type(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::FunctionKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::FunctionKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; - seq.elem_labeled(EdgeLabel::Attributes, self.function_type_attributes(input))?; - seq.elem_labeled( - EdgeLabel::Returns, - OptionalHelper::transform(self.returns_declaration(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::FunctionType) - } - - #[allow(unused_assignments, unused_parens)] - fn function_type_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::InternalKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ExternalKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PrivateKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PublicKeyword, - ); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ConstantKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_4_16 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PureKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_4_16 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ViewKeyword, - ); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PayableKeyword, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::FunctionTypeAttribute) - } - - #[allow(unused_assignments, unused_parens)] - fn function_type_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.function_type_attribute(input) - .with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::FunctionTypeAttributes) - } - - #[allow(unused_assignments, unused_parens)] - fn hex_number_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Literal, - self.parse_terminal_with_trivia::( - input, - TerminalKind::HexLiteral, - ), - )?; - if !self.version_is_at_least_0_5_0 { - seq.elem_labeled( - EdgeLabel::Unit, - OptionalHelper::transform(self.number_unit(input)), - )?; - } - seq.finish() - }) - .with_kind(NonterminalKind::HexNumberExpression) - } - - #[allow(unused_assignments, unused_parens)] - fn hex_string_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::SingleQuotedHexStringLiteral, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::DoubleQuotedHexStringLiteral, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::HexStringLiteral) - } - - #[allow(unused_assignments, unused_parens)] - fn hex_string_literals(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_5_14 { - OneOrMoreHelper::run(input, |input| { - self.hex_string_literal(input).with_label(EdgeLabel::Item) - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::HexStringLiterals) - } - - #[allow(unused_assignments, unused_parens)] - fn identifier_path(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| { - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Period, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::IdentifierPath) - } - - #[allow(unused_assignments, unused_parens)] - fn if_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::IfKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::IfKeyword, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.expression(input) - .with_label(EdgeLabel::Condition) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }))?; - seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; - seq.elem_labeled( - EdgeLabel::ElseBranch, - OptionalHelper::transform(self.else_branch(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::IfStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn import_alias(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::AsKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::AsKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Identifier, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ImportAlias) - } - - #[allow(unused_assignments, unused_parens)] - fn import_clause(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.path_import(input); - choice.consider(input, result)?; - let result = self.named_import(input); - choice.consider(input, result)?; - let result = self.import_deconstruction(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::ImportClause) - } - - #[allow(unused_assignments, unused_parens)] - fn import_deconstruction(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.import_deconstruction_symbols(input) - .with_label(EdgeLabel::Symbols) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }))?; - seq.elem_labeled( - EdgeLabel::FromKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::FromKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Path, self.string_literal(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::ImportDeconstruction) - } - - #[allow(unused_assignments, unused_parens)] - fn import_deconstruction_symbol(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Alias, - OptionalHelper::transform(self.import_alias(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ImportDeconstructionSymbol) - } - - #[allow(unused_assignments, unused_parens)] - fn import_deconstruction_symbols(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| { - self.import_deconstruction_symbol(input) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Comma, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::ImportDeconstructionSymbols) - } - - #[allow(unused_assignments, unused_parens)] - fn import_directive(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ImportKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ImportKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Clause, self.import_clause(input))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ImportDirective) - } - - #[allow(unused_assignments, unused_parens)] - fn index_access_end(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Colon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Colon, - ), - )?; - seq.elem_labeled( - EdgeLabel::End, - OptionalHelper::transform(self.expression(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::IndexAccessEnd) - } - - #[allow(unused_assignments, unused_parens)] - fn index_access_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::IndexAccessExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn inheritance_specifier(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::IsKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::IsKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Types, self.inheritance_types(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::InheritanceSpecifier) - } - - #[allow(unused_assignments, unused_parens)] - fn inheritance_type(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.identifier_path(input))?; - seq.elem_labeled( - EdgeLabel::Arguments, - OptionalHelper::transform(self.arguments_declaration(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::InheritanceType) - } - - #[allow(unused_assignments, unused_parens)] - fn inheritance_types(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.inheritance_type(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::InheritanceTypes) - } - - #[allow(unused_assignments, unused_parens)] - fn interface_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::InterfaceKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::InterfaceKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Inheritance, - OptionalHelper::transform(self.inheritance_specifier(input)), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.interface_members(input) - .with_label(EdgeLabel::Members) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }))?; - seq.finish() - }) - .with_kind(NonterminalKind::InterfaceDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn interface_members(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.contract_member(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::InterfaceMembers) - } - - #[allow(unused_assignments, unused_parens)] - fn library_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::LibraryKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::LibraryKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.library_members(input) - .with_label(EdgeLabel::Members) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }))?; - seq.finish() - }) - .with_kind(NonterminalKind::LibraryDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn library_members(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.contract_member(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::LibraryMembers) - } - - #[allow(unused_assignments, unused_parens)] - fn mapping_key(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::KeyType, self.mapping_key_type(input))?; - if self.version_is_at_least_0_8_18 { - seq.elem_labeled( - EdgeLabel::Name, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - ), - )?; - } - seq.finish() - }) - .with_kind(NonterminalKind::MappingKey) - } - - #[allow(unused_assignments, unused_parens)] - fn mapping_key_type(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.elementary_type(input); - choice.consider(input, result)?; - let result = self.identifier_path(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::MappingKeyType) - } - - #[allow(unused_assignments, unused_parens)] - fn mapping_type(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::MappingKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::MappingKeyword, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::KeyType, self.mapping_key(input))?; - seq.elem_labeled( - EdgeLabel::EqualGreaterThan, - self.parse_terminal_with_trivia::( - input, - TerminalKind::EqualGreaterThan, - ), - )?; - seq.elem_labeled(EdgeLabel::ValueType, self.mapping_value(input))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }))?; - seq.finish() - }) - .with_kind(NonterminalKind::MappingType) - } - - #[allow(unused_assignments, unused_parens)] - fn mapping_value(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - if self.version_is_at_least_0_8_18 { - seq.elem_labeled( - EdgeLabel::Name, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - ), - )?; - } - seq.finish() - }) - .with_kind(NonterminalKind::MappingValue) - } - - #[allow(unused_assignments, unused_parens)] - fn member_access_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::MemberAccessExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn modifier_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - if self.version_is_at_least_0_6_0 { - let result = self.override_specifier(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_6_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::VirtualKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::ModifierAttribute) - } - - #[allow(unused_assignments, unused_parens)] - fn modifier_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.modifier_attribute(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::ModifierAttributes) - } - - #[allow(unused_assignments, unused_parens)] - fn modifier_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ModifierKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ModifierKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Parameters, - OptionalHelper::transform(self.parameters_declaration(input)), - )?; - seq.elem_labeled(EdgeLabel::Attributes, self.modifier_attributes(input))?; - seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::ModifierDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn modifier_invocation(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::Name, self.identifier_path(input))?; - seq.elem_labeled( - EdgeLabel::Arguments, - OptionalHelper::transform(self.arguments_declaration(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ModifierInvocation) - } - - #[allow(unused_assignments, unused_parens)] - fn multiplicative_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::MultiplicativeExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn named_argument(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Colon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Colon, - ), - )?; - seq.elem_labeled(EdgeLabel::Value, self.expression(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::NamedArgument) - } - - #[allow(unused_assignments, unused_parens)] - fn named_argument_group(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.named_arguments(input) - .with_label(EdgeLabel::Arguments) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::NamedArgumentGroup) - } - - #[allow(unused_assignments, unused_parens)] - fn named_arguments(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.named_argument(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - )) - .with_kind(NonterminalKind::NamedArguments) - } - - #[allow(unused_assignments, unused_parens)] - fn named_arguments_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - OptionalHelper::transform(self.named_argument_group(input)) - .with_label(EdgeLabel::Arguments) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::NamedArgumentsDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn named_import(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Asterisk, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Asterisk, - ), - )?; - seq.elem_labeled(EdgeLabel::Alias, self.import_alias(input))?; - seq.elem_labeled( - EdgeLabel::FromKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::FromKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Path, self.string_literal(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::NamedImport) - } - - #[allow(unused_assignments, unused_parens)] - fn new_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::NewKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::NewKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::NewExpression) - } - - #[allow(unused_assignments, unused_parens)] - fn number_unit(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::WeiKeyword, - ); - choice.consider(input, result)?; - if self.version_is_at_least_0_6_11 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::GweiKeyword, - ); - choice.consider(input, result)?; - } - if !self.version_is_at_least_0_7_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::SzaboKeyword, - ); - choice.consider(input, result)?; - } - if !self.version_is_at_least_0_7_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::FinneyKeyword, - ); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::EtherKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::SecondsKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::MinutesKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::HoursKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::DaysKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::WeeksKeyword, - ); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YearsKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::NumberUnit) - } - - #[allow(unused_assignments, unused_parens)] - fn or_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::OrExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn override_paths(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.identifier_path(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - ) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::OverridePaths) - } - - #[allow(unused_assignments, unused_parens)] - fn override_paths_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.override_paths(input) - .with_label(EdgeLabel::Paths) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::OverridePathsDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn override_specifier(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::OverrideKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OverrideKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Overridden, - OptionalHelper::transform(self.override_paths_declaration(input)), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::OverrideSpecifier) - } - - #[allow(unused_assignments, unused_parens)] - fn parameter(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - seq.elem_labeled( - EdgeLabel::StorageLocation, - OptionalHelper::transform(self.storage_location(input)), - )?; - seq.elem_labeled( - EdgeLabel::Name, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::Parameter) - } - - #[allow(unused_assignments, unused_parens)] - fn parameters(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.parameter(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - )) - .with_kind(NonterminalKind::Parameters) - } - - #[allow(unused_assignments, unused_parens)] - fn parameters_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.parameters(input) - .with_label(EdgeLabel::Parameters) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ParametersDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn path_import(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::Path, self.string_literal(input))?; - seq.elem_labeled( - EdgeLabel::Alias, - OptionalHelper::transform(self.import_alias(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::PathImport) - } - - #[allow(unused_assignments, unused_parens)] - fn positional_arguments(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.expression(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - )) - .with_kind(NonterminalKind::PositionalArguments) - } - - #[allow(unused_assignments, unused_parens)] - fn positional_arguments_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.positional_arguments(input) - .with_label(EdgeLabel::Arguments) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::PositionalArgumentsDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn postfix_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::PostfixExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn pragma(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.abicoder_pragma(input); - choice.consider(input, result)?; - let result = self.experimental_pragma(input); - choice.consider(input, result)?; - let result = self.version_pragma(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::Pragma) - } - - #[allow(unused_assignments, unused_parens)] - fn pragma_directive(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::PragmaKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::PragmaKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Pragma, self.pragma(input))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Pragma>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::PragmaDirective) - } - - #[allow(unused_assignments, unused_parens)] - fn prefix_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::PrefixExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn receive_function_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.modifier_invocation(input); - choice.consider(input, result)?; - let result = self.override_specifier(input); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ExternalKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PayableKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::VirtualKeyword, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ReceiveFunctionAttribute) - } - - #[allow(unused_assignments, unused_parens)] - fn receive_function_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - ZeroOrMoreHelper::run(input, |input| { - self.receive_function_attribute(input) - .with_label(EdgeLabel::Item) - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ReceiveFunctionAttributes) - } - - #[allow(unused_assignments, unused_parens)] - fn receive_function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ReceiveKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ReceiveKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; - seq.elem_labeled( - EdgeLabel::Attributes, - self.receive_function_attributes(input), - )?; - seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ReceiveFunctionDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn return_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ReturnKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ReturnKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Expression, - OptionalHelper::transform(self.expression(input)), - )?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::ReturnStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn returns_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ReturnsKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ReturnsKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Variables, self.parameters_declaration(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::ReturnsDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn revert_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_4 { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::RevertKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::RevertKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Error, - OptionalHelper::transform(self.identifier_path(input)), - )?; - seq.elem_labeled(EdgeLabel::Arguments, self.arguments_declaration(input))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::RevertStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn shift_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.expression(input); - let ParserResult::Match(r#match) = &result else { - return result; - }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::Expression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::ShiftExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn simple_version_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Pragma>( - input, - self, - |input| { - self.parse_terminal_with_trivia::( - input, - TerminalKind::VersionSpecifier, - ) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Period, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::SimpleVersionLiteral) - } - - #[allow(unused_assignments, unused_parens)] - fn source_unit(&self, input: &mut ParserContext<'_>) -> ParserResult { - self.source_unit_members(input) - .with_label(EdgeLabel::Members) - .with_kind(NonterminalKind::SourceUnit) - } - - #[allow(unused_assignments, unused_parens)] - fn source_unit_member(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.pragma_directive(input); - choice.consider(input, result)?; - let result = self.import_directive(input); - choice.consider(input, result)?; - let result = self.contract_definition(input); - choice.consider(input, result)?; - let result = self.interface_definition(input); - choice.consider(input, result)?; - let result = self.library_definition(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_6_0 { - let result = self.struct_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_6_0 { - let result = self.enum_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_7_1 { - let result = self.function_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_4 { - let result = self.error_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_8 { - let result = self.user_defined_value_type_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_13 { - let result = self.using_directive(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_22 { - let result = self.event_definition(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_7_4 { - let result = self.constant_definition(input); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::SourceUnitMember) - } - - #[allow(unused_assignments, unused_parens)] - fn source_unit_members(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.source_unit_member(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::SourceUnitMembers) - } - - #[allow(unused_assignments, unused_parens)] - fn state_variable_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - if self.version_is_at_least_0_6_0 { - let result = self.override_specifier(input); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ConstantKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::InternalKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PrivateKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PublicKeyword, - ); - choice.consider(input, result)?; - if self.version_is_at_least_0_6_5 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ImmutableKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_27 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::TransientKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::StateVariableAttribute) - } - - #[allow(unused_assignments, unused_parens)] - fn state_variable_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.state_variable_attribute(input) - .with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::StateVariableAttributes) - } - - #[allow(unused_assignments, unused_parens)] - fn state_variable_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - seq.elem_labeled(EdgeLabel::Attributes, self.state_variable_attributes(input))?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Value, - OptionalHelper::transform(self.state_variable_definition_value(input)), - )?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::StateVariableDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn state_variable_definition_value(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Equal, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Equal, - ), - )?; - seq.elem_labeled(EdgeLabel::Value, self.expression(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::StateVariableDefinitionValue) - } - - #[allow(unused_assignments, unused_parens)] - fn statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.if_statement(input); - choice.consider(input, result)?; - let result = self.for_statement(input); - choice.consider(input, result)?; - let result = self.while_statement(input); - choice.consider(input, result)?; - let result = self.do_while_statement(input); - choice.consider(input, result)?; - let result = self.continue_statement(input); - choice.consider(input, result)?; - let result = self.break_statement(input); - choice.consider(input, result)?; - let result = self.return_statement(input); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.throw_statement(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_4_21 { - let result = self.emit_statement(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_6_0 { - let result = self.try_statement(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_4 { - let result = self.revert_statement(input); - choice.consider(input, result)?; - } - let result = self.assembly_statement(input); - choice.consider(input, result)?; - let result = self.block(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_8_0 { - let result = self.unchecked_block(input); - choice.consider(input, result)?; - } - let result = self.tuple_deconstruction_statement(input); - choice.consider(input, result)?; - let result = self.variable_declaration_statement(input); - choice.consider(input, result)?; - let result = self.expression_statement(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::Statement) - } - - #[allow(unused_assignments, unused_parens)] - fn statements(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.statement(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::Statements) - } - - #[allow(unused_assignments, unused_parens)] - fn storage_location(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::MemoryKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::StorageKeyword, - ); - choice.consider(input, result)?; - if self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::CallDataKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::StorageLocation) - } - - #[allow(unused_assignments, unused_parens)] - fn string_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - if !self.version_is_at_least_0_5_14 { - let result = self.string_literal(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_5_14 { - let result = self.string_literals(input); - choice.consider(input, result)?; - } - if !self.version_is_at_least_0_5_14 { - let result = self.hex_string_literal(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_5_14 { - let result = self.hex_string_literals(input); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_7_0 { - let result = self.unicode_string_literals(input); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::StringExpression) - } - - #[allow(unused_assignments, unused_parens)] - fn string_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::SingleQuotedStringLiteral, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::DoubleQuotedStringLiteral, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::StringLiteral) - } - - #[allow(unused_assignments, unused_parens)] - fn string_literals(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_5_14 { - OneOrMoreHelper::run(input, |input| { - self.string_literal(input).with_label(EdgeLabel::Item) - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::StringLiterals) - } - - #[allow(unused_assignments, unused_parens)] - fn struct_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::StructKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::StructKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.struct_members(input) - .with_label(EdgeLabel::Members) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }))?; - seq.finish() - }) - .with_kind(NonterminalKind::StructDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn struct_member(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::StructMember) - } - - #[allow(unused_assignments, unused_parens)] - fn struct_members(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.struct_member(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::StructMembers) - } - - #[allow(unused_assignments, unused_parens)] - fn throw_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_5_0 { - SequenceHelper::run(|mut seq| { - seq.elem( - self.parse_terminal_with_trivia::( - input, - TerminalKind::ThrowKeyword, - ) - .with_label(EdgeLabel::ThrowKeyword) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::ThrowStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn try_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::TryKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::TryKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Expression, self.expression(input))?; - seq.elem_labeled( - EdgeLabel::Returns, - OptionalHelper::transform(self.returns_declaration(input)), - )?; - seq.elem_labeled(EdgeLabel::Body, self.block(input))?; - seq.elem_labeled(EdgeLabel::CatchClauses, self.catch_clauses(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::TryStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn tuple_deconstruction_element(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(self.tuple_member(input)) - .with_label(EdgeLabel::Member) - .with_kind(NonterminalKind::TupleDeconstructionElement) - } - - #[allow(unused_assignments, unused_parens)] - fn tuple_deconstruction_elements(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| { - self.tuple_deconstruction_element(input) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Comma, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::TupleDeconstructionElements) - } - - #[allow(unused_assignments, unused_parens)] - fn tuple_deconstruction_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - if !self.version_is_at_least_0_5_0 { - seq.elem_labeled( - EdgeLabel::VarKeyword, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::VarKeyword, - ), - ), - )?; - } - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.tuple_deconstruction_elements(input) - .with_label(EdgeLabel::Elements) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }))?; - seq.elem_labeled( - EdgeLabel::Equal, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Equal, - ), - )?; - seq.elem_labeled(EdgeLabel::Expression, self.expression(input))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::TupleDeconstructionStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn tuple_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.tuple_values(input) - .with_label(EdgeLabel::Items) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::TupleExpression) - } - - #[allow(unused_assignments, unused_parens)] - fn tuple_member(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.typed_tuple_member(input); - choice.consider(input, result)?; - let result = self.untyped_tuple_member(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::TupleMember) - } - - #[allow(unused_assignments, unused_parens)] - fn tuple_value(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(self.expression(input)) - .with_label(EdgeLabel::Expression) - .with_kind(NonterminalKind::TupleValue) - } - - #[allow(unused_assignments, unused_parens)] - fn tuple_values(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| self.tuple_value(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::TupleValues) - } - - #[allow(unused_assignments, unused_parens)] - fn type_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_5_3 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::TypeKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::TypeKeyword, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.type_name(input) - .with_label(EdgeLabel::TypeName) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::TypeExpression) - } - - #[allow(unused_assignments, unused_parens)] - fn type_name(&self, input: &mut ParserContext<'_>) -> ParserResult { - let parse_postfix_array_type_name = |input: &mut ParserContext<'_>| { - PrecedenceHelper::to_postfix_operator( - NonterminalKind::ArrayTypeName, - 1u8, - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBracket); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBracket, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBracket, - ), - )?; - seq.elem( - OptionalHelper::transform(self.expression(input)) - .with_label(EdgeLabel::Index) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBracket, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBracket, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBracket, - ), - )?; - seq.finish() - }), - ) - }; - let primary_expression_parser = |input: &mut ParserContext<'_>| { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.function_type(input); - choice.consider(input, result)?; - let result = self.mapping_type(input); - choice.consider(input, result)?; - let result = self.elementary_type(input); - choice.consider(input, result)?; - let result = self.identifier_path(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - }; - let postfix_operator_parser = |input: &mut ParserContext<'_>| { - ChoiceHelper::run(input, |mut choice, input| { - let result = parse_postfix_array_type_name(input); - choice.consider(input, result)?; - choice.finish(input) - }) - }; - let linear_expression_parser = |input: &mut ParserContext<'_>| { - SequenceHelper::run(|mut seq| { - seq.elem(primary_expression_parser(input))?; - seq.elem(ZeroOrMoreHelper::run(input, postfix_operator_parser))?; - seq.finish() - }) - }; - PrecedenceHelper::reduce_precedence_result( - NonterminalKind::TypeName, - linear_expression_parser(input), - ) - .with_kind(NonterminalKind::TypeName) - } - - #[allow(unused_assignments, unused_parens)] - fn typed_tuple_member(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; - seq.elem_labeled( - EdgeLabel::StorageLocation, - OptionalHelper::transform(self.storage_location(input)), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::TypedTupleMember) - } - - #[allow(unused_assignments, unused_parens)] - fn unchecked_block(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::UncheckedKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::UncheckedKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Block, self.block(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UncheckedBlock) - } - - #[allow(unused_assignments, unused_parens)] - fn unicode_string_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_7_0 { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::SingleQuotedUnicodeStringLiteral, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::DoubleQuotedUnicodeStringLiteral, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UnicodeStringLiteral) - } - - #[allow(unused_assignments, unused_parens)] - fn unicode_string_literals(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_7_0 { - OneOrMoreHelper::run(input, |input| { - self.unicode_string_literal(input) - .with_label(EdgeLabel::Item) - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UnicodeStringLiterals) - } - - #[allow(unused_assignments, unused_parens)] - fn unnamed_function_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_6_0 { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.modifier_invocation(input); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ConstantKeyword, - ); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ExternalKeyword, - ); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::InternalKeyword, - ); - choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PayableKeyword, - ); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PrivateKeyword, - ); - choice.consider(input, result)?; - } - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PublicKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_4_16 && !self.version_is_at_least_0_6_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::PureKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_4_16 && !self.version_is_at_least_0_6_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ViewKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UnnamedFunctionAttribute) - } - - #[allow(unused_assignments, unused_parens)] - fn unnamed_function_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_6_0 { - ZeroOrMoreHelper::run(input, |input| { - self.unnamed_function_attribute(input) - .with_label(EdgeLabel::Item) - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UnnamedFunctionAttributes) - } - - #[allow(unused_assignments, unused_parens)] - fn unnamed_function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_6_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::FunctionKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::FunctionKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; - seq.elem_labeled( - EdgeLabel::Attributes, - self.unnamed_function_attributes(input), - )?; - seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UnnamedFunctionDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn untyped_tuple_member(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::StorageLocation, - OptionalHelper::transform(self.storage_location(input)), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::UntypedTupleMember) - } - - #[allow(unused_assignments, unused_parens)] - fn user_defined_value_type_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_8 { - SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::TypeKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::TypeKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::IsKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::IsKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::ValueType, self.elementary_type(input))?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UserDefinedValueTypeDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn using_alias(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_19 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::AsKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::AsKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Operator, self.using_operator(input))?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UsingAlias) - } - - #[allow(unused_assignments, unused_parens)] - fn using_clause(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.identifier_path(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_8_13 { - let result = self.using_deconstruction(input); - choice.consider(input, result)?; + pub fn parse_nonterminal(&self, kind: NonterminalKind, input: &str) -> ParseOutput { + match kind { + NonterminalKind::AbicoderPragma => Self::abicoder_pragma.parse(self, input, kind), + NonterminalKind::AdditiveExpression => { + Self::additive_expression.parse(self, input, kind) + } + NonterminalKind::AddressType => Self::address_type.parse(self, input, kind), + NonterminalKind::AndExpression => Self::and_expression.parse(self, input, kind), + NonterminalKind::ArgumentsDeclaration => { + Self::arguments_declaration.parse(self, input, kind) + } + NonterminalKind::ArrayExpression => Self::array_expression.parse(self, input, kind), + NonterminalKind::ArrayTypeName => Self::array_type_name.parse(self, input, kind), + NonterminalKind::ArrayValues => Self::array_values.parse(self, input, kind), + NonterminalKind::AssemblyFlags => Self::assembly_flags.parse(self, input, kind), + NonterminalKind::AssemblyFlagsDeclaration => { + Self::assembly_flags_declaration.parse(self, input, kind) + } + NonterminalKind::AssemblyStatement => Self::assembly_statement.parse(self, input, kind), + NonterminalKind::AssignmentExpression => { + Self::assignment_expression.parse(self, input, kind) + } + NonterminalKind::BitwiseAndExpression => { + Self::bitwise_and_expression.parse(self, input, kind) + } + NonterminalKind::BitwiseOrExpression => { + Self::bitwise_or_expression.parse(self, input, kind) + } + NonterminalKind::BitwiseXorExpression => { + Self::bitwise_xor_expression.parse(self, input, kind) + } + NonterminalKind::Block => Self::block.parse(self, input, kind), + NonterminalKind::BreakStatement => Self::break_statement.parse(self, input, kind), + NonterminalKind::CallOptions => Self::call_options.parse(self, input, kind), + NonterminalKind::CallOptionsExpression => { + Self::call_options_expression.parse(self, input, kind) + } + NonterminalKind::CatchClause => Self::catch_clause.parse(self, input, kind), + NonterminalKind::CatchClauseError => Self::catch_clause_error.parse(self, input, kind), + NonterminalKind::CatchClauses => Self::catch_clauses.parse(self, input, kind), + NonterminalKind::ComparisonExpression => { + Self::comparison_expression.parse(self, input, kind) + } + NonterminalKind::ConditionalExpression => { + Self::conditional_expression.parse(self, input, kind) + } + NonterminalKind::ConstantDefinition => { + Self::constant_definition.parse(self, input, kind) + } + NonterminalKind::ConstructorAttribute => { + Self::constructor_attribute.parse(self, input, kind) + } + NonterminalKind::ConstructorAttributes => { + Self::constructor_attributes.parse(self, input, kind) + } + NonterminalKind::ConstructorDefinition => { + Self::constructor_definition.parse(self, input, kind) + } + NonterminalKind::ContinueStatement => Self::continue_statement.parse(self, input, kind), + NonterminalKind::ContractDefinition => { + Self::contract_definition.parse(self, input, kind) + } + NonterminalKind::ContractMember => Self::contract_member.parse(self, input, kind), + NonterminalKind::ContractMembers => Self::contract_members.parse(self, input, kind), + NonterminalKind::DecimalNumberExpression => { + Self::decimal_number_expression.parse(self, input, kind) + } + NonterminalKind::DoWhileStatement => Self::do_while_statement.parse(self, input, kind), + NonterminalKind::ElementaryType => Self::elementary_type.parse(self, input, kind), + NonterminalKind::ElseBranch => Self::else_branch.parse(self, input, kind), + NonterminalKind::EmitStatement => Self::emit_statement.parse(self, input, kind), + NonterminalKind::EnumDefinition => Self::enum_definition.parse(self, input, kind), + NonterminalKind::EnumMembers => Self::enum_members.parse(self, input, kind), + NonterminalKind::EqualityExpression => { + Self::equality_expression.parse(self, input, kind) + } + NonterminalKind::ErrorDefinition => Self::error_definition.parse(self, input, kind), + NonterminalKind::ErrorParameter => Self::error_parameter.parse(self, input, kind), + NonterminalKind::ErrorParameters => Self::error_parameters.parse(self, input, kind), + NonterminalKind::ErrorParametersDeclaration => { + Self::error_parameters_declaration.parse(self, input, kind) + } + NonterminalKind::EventDefinition => Self::event_definition.parse(self, input, kind), + NonterminalKind::EventParameter => Self::event_parameter.parse(self, input, kind), + NonterminalKind::EventParameters => Self::event_parameters.parse(self, input, kind), + NonterminalKind::EventParametersDeclaration => { + Self::event_parameters_declaration.parse(self, input, kind) + } + NonterminalKind::ExperimentalFeature => { + Self::experimental_feature.parse(self, input, kind) + } + NonterminalKind::ExperimentalPragma => { + Self::experimental_pragma.parse(self, input, kind) + } + NonterminalKind::ExponentiationExpression => { + Self::exponentiation_expression.parse(self, input, kind) + } + NonterminalKind::Expression => Self::expression.parse(self, input, kind), + NonterminalKind::ExpressionStatement => { + Self::expression_statement.parse(self, input, kind) + } + NonterminalKind::FallbackFunctionAttribute => { + Self::fallback_function_attribute.parse(self, input, kind) + } + NonterminalKind::FallbackFunctionAttributes => { + Self::fallback_function_attributes.parse(self, input, kind) + } + NonterminalKind::FallbackFunctionDefinition => { + Self::fallback_function_definition.parse(self, input, kind) + } + NonterminalKind::ForStatement => Self::for_statement.parse(self, input, kind), + NonterminalKind::ForStatementCondition => { + Self::for_statement_condition.parse(self, input, kind) + } + NonterminalKind::ForStatementInitialization => { + Self::for_statement_initialization.parse(self, input, kind) + } + NonterminalKind::FunctionAttribute => Self::function_attribute.parse(self, input, kind), + NonterminalKind::FunctionAttributes => { + Self::function_attributes.parse(self, input, kind) + } + NonterminalKind::FunctionBody => Self::function_body.parse(self, input, kind), + NonterminalKind::FunctionCallExpression => { + Self::function_call_expression.parse(self, input, kind) + } + NonterminalKind::FunctionDefinition => { + Self::function_definition.parse(self, input, kind) + } + NonterminalKind::FunctionName => Self::function_name.parse(self, input, kind), + NonterminalKind::FunctionType => Self::function_type.parse(self, input, kind), + NonterminalKind::FunctionTypeAttribute => { + Self::function_type_attribute.parse(self, input, kind) + } + NonterminalKind::FunctionTypeAttributes => { + Self::function_type_attributes.parse(self, input, kind) + } + NonterminalKind::HexNumberExpression => { + Self::hex_number_expression.parse(self, input, kind) + } + NonterminalKind::HexStringLiteral => Self::hex_string_literal.parse(self, input, kind), + NonterminalKind::HexStringLiterals => { + Self::hex_string_literals.parse(self, input, kind) + } + NonterminalKind::IdentifierPath => Self::identifier_path.parse(self, input, kind), + NonterminalKind::IfStatement => Self::if_statement.parse(self, input, kind), + NonterminalKind::ImportAlias => Self::import_alias.parse(self, input, kind), + NonterminalKind::ImportClause => Self::import_clause.parse(self, input, kind), + NonterminalKind::ImportDeconstruction => { + Self::import_deconstruction.parse(self, input, kind) + } + NonterminalKind::ImportDeconstructionSymbol => { + Self::import_deconstruction_symbol.parse(self, input, kind) + } + NonterminalKind::ImportDeconstructionSymbols => { + Self::import_deconstruction_symbols.parse(self, input, kind) + } + NonterminalKind::ImportDirective => Self::import_directive.parse(self, input, kind), + NonterminalKind::IndexAccessEnd => Self::index_access_end.parse(self, input, kind), + NonterminalKind::IndexAccessExpression => { + Self::index_access_expression.parse(self, input, kind) + } + NonterminalKind::InheritanceSpecifier => { + Self::inheritance_specifier.parse(self, input, kind) + } + NonterminalKind::InheritanceType => Self::inheritance_type.parse(self, input, kind), + NonterminalKind::InheritanceTypes => Self::inheritance_types.parse(self, input, kind), + NonterminalKind::InterfaceDefinition => { + Self::interface_definition.parse(self, input, kind) + } + NonterminalKind::InterfaceMembers => Self::interface_members.parse(self, input, kind), + NonterminalKind::LibraryDefinition => Self::library_definition.parse(self, input, kind), + NonterminalKind::LibraryMembers => Self::library_members.parse(self, input, kind), + NonterminalKind::MappingKey => Self::mapping_key.parse(self, input, kind), + NonterminalKind::MappingKeyType => Self::mapping_key_type.parse(self, input, kind), + NonterminalKind::MappingType => Self::mapping_type.parse(self, input, kind), + NonterminalKind::MappingValue => Self::mapping_value.parse(self, input, kind), + NonterminalKind::MemberAccessExpression => { + Self::member_access_expression.parse(self, input, kind) } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::UsingClause) - } - - #[allow(unused_assignments, unused_parens)] - fn using_deconstruction(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_13 { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.using_deconstruction_symbols(input) - .with_label(EdgeLabel::Symbols) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() + NonterminalKind::ModifierAttribute => Self::modifier_attribute.parse(self, input, kind), + NonterminalKind::ModifierAttributes => { + Self::modifier_attributes.parse(self, input, kind) + } + NonterminalKind::ModifierDefinition => { + Self::modifier_definition.parse(self, input, kind) + } + NonterminalKind::ModifierInvocation => { + Self::modifier_invocation.parse(self, input, kind) + } + NonterminalKind::MultiplicativeExpression => { + Self::multiplicative_expression.parse(self, input, kind) + } + NonterminalKind::NamedArgument => Self::named_argument.parse(self, input, kind), + NonterminalKind::NamedArgumentGroup => { + Self::named_argument_group.parse(self, input, kind) + } + NonterminalKind::NamedArguments => Self::named_arguments.parse(self, input, kind), + NonterminalKind::NamedArgumentsDeclaration => { + Self::named_arguments_declaration.parse(self, input, kind) + } + NonterminalKind::NamedImport => Self::named_import.parse(self, input, kind), + NonterminalKind::NewExpression => Self::new_expression.parse(self, input, kind), + NonterminalKind::NumberUnit => Self::number_unit.parse(self, input, kind), + NonterminalKind::OrExpression => Self::or_expression.parse(self, input, kind), + NonterminalKind::OverridePaths => Self::override_paths.parse(self, input, kind), + NonterminalKind::OverridePathsDeclaration => { + Self::override_paths_declaration.parse(self, input, kind) + } + NonterminalKind::OverrideSpecifier => Self::override_specifier.parse(self, input, kind), + NonterminalKind::Parameter => Self::parameter.parse(self, input, kind), + NonterminalKind::Parameters => Self::parameters.parse(self, input, kind), + NonterminalKind::ParametersDeclaration => { + Self::parameters_declaration.parse(self, input, kind) + } + NonterminalKind::PathImport => Self::path_import.parse(self, input, kind), + NonterminalKind::PositionalArguments => { + Self::positional_arguments.parse(self, input, kind) + } + NonterminalKind::PositionalArgumentsDeclaration => { + Self::positional_arguments_declaration.parse(self, input, kind) + } + NonterminalKind::PostfixExpression => Self::postfix_expression.parse(self, input, kind), + NonterminalKind::Pragma => Self::pragma.parse(self, input, kind), + NonterminalKind::PragmaDirective => Self::pragma_directive.parse(self, input, kind), + NonterminalKind::PrefixExpression => Self::prefix_expression.parse(self, input, kind), + NonterminalKind::ReceiveFunctionAttribute => { + Self::receive_function_attribute.parse(self, input, kind) + } + NonterminalKind::ReceiveFunctionAttributes => { + Self::receive_function_attributes.parse(self, input, kind) + } + NonterminalKind::ReceiveFunctionDefinition => { + Self::receive_function_definition.parse(self, input, kind) + } + NonterminalKind::ReturnStatement => Self::return_statement.parse(self, input, kind), + NonterminalKind::ReturnsDeclaration => { + Self::returns_declaration.parse(self, input, kind) + } + NonterminalKind::RevertStatement => Self::revert_statement.parse(self, input, kind), + NonterminalKind::ShiftExpression => Self::shift_expression.parse(self, input, kind), + NonterminalKind::SimpleVersionLiteral => { + Self::simple_version_literal.parse(self, input, kind) + } + NonterminalKind::SourceUnit => Self::source_unit.parse(self, input, kind), + NonterminalKind::SourceUnitMember => Self::source_unit_member.parse(self, input, kind), + NonterminalKind::SourceUnitMembers => { + Self::source_unit_members.parse(self, input, kind) + } + NonterminalKind::StateVariableAttribute => { + Self::state_variable_attribute.parse(self, input, kind) + } + NonterminalKind::StateVariableAttributes => { + Self::state_variable_attributes.parse(self, input, kind) + } + NonterminalKind::StateVariableDefinition => { + Self::state_variable_definition.parse(self, input, kind) + } + NonterminalKind::StateVariableDefinitionValue => { + Self::state_variable_definition_value.parse(self, input, kind) + } + NonterminalKind::Statement => Self::statement.parse(self, input, kind), + NonterminalKind::Statements => Self::statements.parse(self, input, kind), + NonterminalKind::StorageLocation => Self::storage_location.parse(self, input, kind), + NonterminalKind::StringExpression => Self::string_expression.parse(self, input, kind), + NonterminalKind::StringLiteral => Self::string_literal.parse(self, input, kind), + NonterminalKind::StringLiterals => Self::string_literals.parse(self, input, kind), + NonterminalKind::StructDefinition => Self::struct_definition.parse(self, input, kind), + NonterminalKind::StructMember => Self::struct_member.parse(self, input, kind), + NonterminalKind::StructMembers => Self::struct_members.parse(self, input, kind), + NonterminalKind::ThrowStatement => Self::throw_statement.parse(self, input, kind), + NonterminalKind::TryStatement => Self::try_statement.parse(self, input, kind), + NonterminalKind::TupleDeconstructionElement => { + Self::tuple_deconstruction_element.parse(self, input, kind) + } + NonterminalKind::TupleDeconstructionElements => { + Self::tuple_deconstruction_elements.parse(self, input, kind) + } + NonterminalKind::TupleDeconstructionStatement => { + Self::tuple_deconstruction_statement.parse(self, input, kind) + } + NonterminalKind::TupleExpression => Self::tuple_expression.parse(self, input, kind), + NonterminalKind::TupleMember => Self::tuple_member.parse(self, input, kind), + NonterminalKind::TupleValue => Self::tuple_value.parse(self, input, kind), + NonterminalKind::TupleValues => Self::tuple_values.parse(self, input, kind), + NonterminalKind::TypeExpression => Self::type_expression.parse(self, input, kind), + NonterminalKind::TypeName => Self::type_name.parse(self, input, kind), + NonterminalKind::TypedTupleMember => Self::typed_tuple_member.parse(self, input, kind), + NonterminalKind::UncheckedBlock => Self::unchecked_block.parse(self, input, kind), + NonterminalKind::UnicodeStringLiteral => { + Self::unicode_string_literal.parse(self, input, kind) + } + NonterminalKind::UnicodeStringLiterals => { + Self::unicode_string_literals.parse(self, input, kind) + } + NonterminalKind::UnnamedFunctionAttribute => { + Self::unnamed_function_attribute.parse(self, input, kind) + } + NonterminalKind::UnnamedFunctionAttributes => { + Self::unnamed_function_attributes.parse(self, input, kind) + } + NonterminalKind::UnnamedFunctionDefinition => { + Self::unnamed_function_definition.parse(self, input, kind) + } + NonterminalKind::UntypedTupleMember => { + Self::untyped_tuple_member.parse(self, input, kind) + } + NonterminalKind::UserDefinedValueTypeDefinition => { + Self::user_defined_value_type_definition.parse(self, input, kind) + } + NonterminalKind::UsingAlias => Self::using_alias.parse(self, input, kind), + NonterminalKind::UsingClause => Self::using_clause.parse(self, input, kind), + NonterminalKind::UsingDeconstruction => { + Self::using_deconstruction.parse(self, input, kind) + } + NonterminalKind::UsingDeconstructionSymbol => { + Self::using_deconstruction_symbol.parse(self, input, kind) + } + NonterminalKind::UsingDeconstructionSymbols => { + Self::using_deconstruction_symbols.parse(self, input, kind) + } + NonterminalKind::UsingDirective => Self::using_directive.parse(self, input, kind), + NonterminalKind::UsingOperator => Self::using_operator.parse(self, input, kind), + NonterminalKind::UsingTarget => Self::using_target.parse(self, input, kind), + NonterminalKind::VariableDeclarationStatement => { + Self::variable_declaration_statement.parse(self, input, kind) + } + NonterminalKind::VariableDeclarationType => { + Self::variable_declaration_type.parse(self, input, kind) + } + NonterminalKind::VariableDeclarationValue => { + Self::variable_declaration_value.parse(self, input, kind) + } + NonterminalKind::VersionExpression => Self::version_expression.parse(self, input, kind), + NonterminalKind::VersionExpressionSet => { + Self::version_expression_set.parse(self, input, kind) + } + NonterminalKind::VersionExpressionSets => { + Self::version_expression_sets.parse(self, input, kind) + } + NonterminalKind::VersionLiteral => Self::version_literal.parse(self, input, kind), + NonterminalKind::VersionOperator => Self::version_operator.parse(self, input, kind), + NonterminalKind::VersionPragma => Self::version_pragma.parse(self, input, kind), + NonterminalKind::VersionRange => Self::version_range.parse(self, input, kind), + NonterminalKind::VersionTerm => Self::version_term.parse(self, input, kind), + NonterminalKind::WhileStatement => Self::while_statement.parse(self, input, kind), + NonterminalKind::YulArguments => Self::yul_arguments.parse(self, input, kind), + NonterminalKind::YulAssignmentOperator => { + Self::yul_assignment_operator.parse(self, input, kind) + } + NonterminalKind::YulBlock => Self::yul_block.parse(self, input, kind), + NonterminalKind::YulBreakStatement => { + Self::yul_break_statement.parse(self, input, kind) + } + NonterminalKind::YulBuiltInFunction => { + Self::yul_built_in_function.parse(self, input, kind) + } + NonterminalKind::YulColonAndEqual => Self::yul_colon_and_equal.parse(self, input, kind), + NonterminalKind::YulContinueStatement => { + Self::yul_continue_statement.parse(self, input, kind) + } + NonterminalKind::YulDefaultCase => Self::yul_default_case.parse(self, input, kind), + NonterminalKind::YulEqualAndColon => Self::yul_equal_and_colon.parse(self, input, kind), + NonterminalKind::YulExpression => Self::yul_expression.parse(self, input, kind), + NonterminalKind::YulForStatement => Self::yul_for_statement.parse(self, input, kind), + NonterminalKind::YulFunctionCallExpression => { + Self::yul_function_call_expression.parse(self, input, kind) + } + NonterminalKind::YulFunctionDefinition => { + Self::yul_function_definition.parse(self, input, kind) + } + NonterminalKind::YulIfStatement => Self::yul_if_statement.parse(self, input, kind), + NonterminalKind::YulLabel => Self::yul_label.parse(self, input, kind), + NonterminalKind::YulLeaveStatement => { + Self::yul_leave_statement.parse(self, input, kind) + } + NonterminalKind::YulLiteral => Self::yul_literal.parse(self, input, kind), + NonterminalKind::YulParameters => Self::yul_parameters.parse(self, input, kind), + NonterminalKind::YulParametersDeclaration => { + Self::yul_parameters_declaration.parse(self, input, kind) + } + NonterminalKind::YulPath => Self::yul_path.parse(self, input, kind), + NonterminalKind::YulPaths => Self::yul_paths.parse(self, input, kind), + NonterminalKind::YulReturnsDeclaration => { + Self::yul_returns_declaration.parse(self, input, kind) + } + NonterminalKind::YulStackAssignmentOperator => { + Self::yul_stack_assignment_operator.parse(self, input, kind) + } + NonterminalKind::YulStackAssignmentStatement => { + Self::yul_stack_assignment_statement.parse(self, input, kind) + } + NonterminalKind::YulStatement => Self::yul_statement.parse(self, input, kind), + NonterminalKind::YulStatements => Self::yul_statements.parse(self, input, kind), + NonterminalKind::YulSwitchCase => Self::yul_switch_case.parse(self, input, kind), + NonterminalKind::YulSwitchCases => Self::yul_switch_cases.parse(self, input, kind), + NonterminalKind::YulSwitchStatement => { + Self::yul_switch_statement.parse(self, input, kind) + } + NonterminalKind::YulValueCase => Self::yul_value_case.parse(self, input, kind), + NonterminalKind::YulVariableAssignmentStatement => { + Self::yul_variable_assignment_statement.parse(self, input, kind) + } + NonterminalKind::YulVariableDeclarationStatement => { + Self::yul_variable_declaration_statement.parse(self, input, kind) + } + NonterminalKind::YulVariableDeclarationValue => { + Self::yul_variable_declaration_value.parse(self, input, kind) + } + NonterminalKind::YulVariableNames => Self::yul_variable_names.parse(self, input, kind), } - .with_kind(NonterminalKind::UsingDeconstruction) } + /******************************************** + * Parser Functions + ********************************************/ + #[allow(unused_assignments, unused_parens)] - fn using_deconstruction_symbol(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_13 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::Name, self.identifier_path(input))?; - if self.version_is_at_least_0_8_19 { - seq.elem_labeled( - EdgeLabel::Alias, - OptionalHelper::transform(self.using_alias(input)), - )?; - } - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::UsingDeconstructionSymbol) + fn abicoder_pragma(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::AbicoderKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::AbicoderKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Version, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::AbicoderPragma) } #[allow(unused_assignments, unused_parens)] - fn using_deconstruction_symbols(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_13 { - SeparatedHelper::run::<_, LexicalContextType::Default>( - input, - self, - |input| { - self.using_deconstruction_symbol(input) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Comma, - EdgeLabel::Separator, - ) - } else { - ParserResult::disabled() + fn additive_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::AdditiveExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), } - .with_kind(NonterminalKind::UsingDeconstructionSymbols) } #[allow(unused_assignments, unused_parens)] - fn using_directive(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn address_type(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::UsingKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::UsingKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Clause, self.using_clause(input))?; - seq.elem_labeled( - EdgeLabel::ForKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::ForKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Target, self.using_target(input))?; - if self.version_is_at_least_0_8_13 { - seq.elem_labeled( - EdgeLabel::GlobalKeyword, - OptionalHelper::transform( - self.parse_terminal_with_trivia::( - input, - TerminalKind::GlobalKeyword, - ), - ), - )?; - } - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + seq.elem_labeled( + EdgeLabel::AddressKeyword, + self.parse_terminal_with_trivia::( input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), + TerminalKind::AddressKeyword, ), )?; seq.elem_labeled( - EdgeLabel::Semicolon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Semicolon, + EdgeLabel::PayableKeyword, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::PayableKeyword, + ), ), )?; seq.finish() }) - .with_kind(NonterminalKind::UsingDirective) + .with_kind(NonterminalKind::AddressType) } #[allow(unused_assignments, unused_parens)] - fn using_operator(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_8_19 { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Ampersand, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Asterisk, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::BangEqual, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Bar, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Caret, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::EqualEqual, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThan, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThanEqual, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::LessThan, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::LessThanEqual, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Minus, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Percent, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Plus, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Slash, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Tilde, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - } else { - ParserResult::disabled() + fn and_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::AndExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), } - .with_kind(NonterminalKind::UsingOperator) } #[allow(unused_assignments, unused_parens)] - fn using_target(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn arguments_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { ChoiceHelper::run(input, |mut choice, input| { - let result = self.type_name(input); + let result = self.positional_arguments_declaration(input); choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Asterisk, - ); + let result = self.named_arguments_declaration(input); choice.consider(input, result)?; choice.finish(input) }) .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::UsingTarget) + .with_kind(NonterminalKind::ArgumentsDeclaration) } #[allow(unused_assignments, unused_parens)] - fn variable_declaration_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn array_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { - seq.elem( - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::VariableType, - self.variable_declaration_type(input), - )?; - seq.elem_labeled( - EdgeLabel::StorageLocation, - OptionalHelper::transform(self.storage_location(input)), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Identifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Value, - OptionalHelper::transform(self.variable_declaration_value(input)), - )?; - seq.finish() - }) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + let mut delim_guard = input.open_delim(TerminalKind::CloseBracket); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBracket, + self.parse_terminal_with_trivia::( input, - self, - TerminalKind::Semicolon, - TerminalAcceptanceThreshold(1u8), + TerminalKind::OpenBracket, ), )?; + seq.elem( + self.array_values(input) + .with_label(EdgeLabel::Items) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBracket, + TerminalAcceptanceThreshold(0u8), + ), + )?; seq.elem_labeled( - EdgeLabel::Semicolon, + EdgeLabel::CloseBracket, self.parse_terminal_with_trivia::( input, - TerminalKind::Semicolon, + TerminalKind::CloseBracket, ), )?; seq.finish() }) - .with_kind(NonterminalKind::VariableDeclarationStatement) + .with_kind(NonterminalKind::ArrayExpression) } #[allow(unused_assignments, unused_parens)] - fn variable_declaration_type(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.type_name(input); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::VarKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::VariableDeclarationType) + fn array_type_name(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.type_name(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::TypeName => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::ArrayTypeName => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } } #[allow(unused_assignments, unused_parens)] - fn variable_declaration_value(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn array_values(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| self.expression(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::ArrayValues) + } + + #[allow(unused_assignments, unused_parens)] + fn assembly_flags(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| self.string_literal(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::AssemblyFlags) + } + + #[allow(unused_assignments, unused_parens)] + fn assembly_flags_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); seq.elem_labeled( - EdgeLabel::Equal, + EdgeLabel::OpenParen, self.parse_terminal_with_trivia::( input, - TerminalKind::Equal, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.assembly_flags(input) + .with_label(EdgeLabel::Flags) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, ), )?; - seq.elem_labeled(EdgeLabel::Expression, self.expression(input))?; seq.finish() }) - .with_kind(NonterminalKind::VariableDeclarationValue) + .with_kind(NonterminalKind::AssemblyFlagsDeclaration) } #[allow(unused_assignments, unused_parens)] - fn version_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.version_range(input); - choice.consider(input, result)?; - let result = self.version_term(input); - choice.consider(input, result)?; - choice.finish(input) + fn assembly_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::AssemblyKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::AssemblyKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Label, + OptionalHelper::transform(self.string_literal(input)), + )?; + seq.elem_labeled( + EdgeLabel::Flags, + OptionalHelper::transform(self.assembly_flags_declaration(input)), + )?; + seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; + seq.finish() }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::VersionExpression) + .with_kind(NonterminalKind::AssemblyStatement) } #[allow(unused_assignments, unused_parens)] - fn version_expression_set(&self, input: &mut ParserContext<'_>) -> ParserResult { - OneOrMoreHelper::run(input, |input| { - self.version_expression(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::VersionExpressionSet) + fn assignment_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::AssignmentExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } } #[allow(unused_assignments, unused_parens)] - fn version_expression_sets(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Pragma>( - input, - self, - |input| { - self.version_expression_set(input) - .with_label(EdgeLabel::Item) + fn bitwise_and_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::BitwiseAndExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), }, - TerminalKind::BarBar, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::VersionExpressionSets) + _ => ParserResult::default(), + } } #[allow(unused_assignments, unused_parens)] - fn version_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.simple_version_literal(input); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::SingleQuotedVersionLiteral, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::DoubleQuotedVersionLiteral, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::VersionLiteral) + fn bitwise_or_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::BitwiseOrExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } } #[allow(unused_assignments, unused_parens)] - fn version_operator(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Caret, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Tilde, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::Equal, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::LessThan, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThan, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::LessThanEqual, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::GreaterThanEqual, - ); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::VersionOperator) + fn bitwise_xor_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::BitwiseXorExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } } #[allow(unused_assignments, unused_parens)] - fn version_pragma(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn block(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); seq.elem_labeled( - EdgeLabel::SolidityKeyword, - self.parse_terminal_with_trivia::( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( input, - TerminalKind::SolidityKeyword, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.statements(input) + .with_label(EdgeLabel::Statements) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, ), )?; - seq.elem_labeled(EdgeLabel::Sets, self.version_expression_sets(input))?; seq.finish() }) - .with_kind(NonterminalKind::VersionPragma) + .with_kind(NonterminalKind::Block) } #[allow(unused_assignments, unused_parens)] - fn version_range(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn break_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::Start, self.version_literal(input))?; + seq.elem( + self.parse_terminal_with_trivia::( + input, + TerminalKind::BreakKeyword, + ) + .with_label(EdgeLabel::BreakKeyword) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; seq.elem_labeled( - EdgeLabel::Minus, - self.parse_terminal_with_trivia::( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( input, - TerminalKind::Minus, + TerminalKind::Semicolon, ), )?; - seq.elem_labeled(EdgeLabel::End, self.version_literal(input))?; seq.finish() }) - .with_kind(NonterminalKind::VersionRange) + .with_kind(NonterminalKind::BreakStatement) } #[allow(unused_assignments, unused_parens)] - fn version_term(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Operator, - OptionalHelper::transform(self.version_operator(input)), - )?; - seq.elem_labeled(EdgeLabel::Literal, self.version_literal(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::VersionTerm) + fn call_options(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_2 { + SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| self.named_argument(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + ) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::CallOptions) } #[allow(unused_assignments, unused_parens)] - fn while_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::WhileKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::WhileKeyword, - ), - )?; - seq.elem(SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); + fn call_options_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::CallOptionsExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn catch_clause(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + SequenceHelper::run(|mut seq| { seq.elem_labeled( - EdgeLabel::OpenParen, + EdgeLabel::CatchKeyword, self.parse_terminal_with_trivia::( input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.expression(input) - .with_label(EdgeLabel::Condition) - .recover_until_with_nested_delims::<_, LexicalContextType::Default>( - input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), + TerminalKind::CatchKeyword, ), )?; seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseParen, - ), + EdgeLabel::Error, + OptionalHelper::transform(self.catch_clause_error(input)), )?; + seq.elem_labeled(EdgeLabel::Body, self.block(input))?; seq.finish() - }))?; - seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::WhileStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_arguments(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Yul>( - input, - self, - |input| self.yul_expression(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - )) - .with_kind(NonterminalKind::YulArguments) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::CatchClause) } #[allow(unused_assignments, unused_parens)] - fn yul_assignment_operator(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::ColonEqual, - ); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_5 { - let result = self.yul_colon_and_equal(input); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::YulAssignmentOperator) + fn catch_clause_error(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Name, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + ), + )?; + seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::CatchClauseError) } #[allow(unused_assignments, unused_parens)] - fn yul_block(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenBrace, - ), - )?; - seq.elem( - self.yul_statements(input) - .with_label(EdgeLabel::Statements) - .recover_until_with_nested_delims::<_, LexicalContextType::Yul>( - input, - self, - TerminalKind::CloseBrace, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseBrace, - self.parse_terminal_with_trivia::( - input, - TerminalKind::CloseBrace, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::YulBlock) + fn catch_clauses(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + OneOrMoreHelper::run(input, |input| { + self.catch_clause(input).with_label(EdgeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::CatchClauses) } #[allow(unused_assignments, unused_parens)] - fn yul_break_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulBreakKeyword, - ) - .with_label(EdgeLabel::BreakKeyword) - .with_kind(NonterminalKind::YulBreakStatement) + fn comparison_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::ComparisonExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } } #[allow(unused_assignments, unused_parens)] - fn yul_built_in_function(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulAddKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulAddModKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulAddressKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulAndKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulBalanceKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulBlockHashKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulByteKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCallCodeKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCallDataCopyKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCallDataLoadKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCallDataSizeKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCallerKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCallKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCallValueKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCoinBaseKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCreateKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulDelegateCallKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulDivKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulEqKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulExpKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulExtCodeCopyKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulExtCodeSizeKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulGasKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulGasLimitKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulGasPriceKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulGtKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulInvalidKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulIsZeroKeyword, - ); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( + fn conditional_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::ConditionalExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn constant_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_7_4 { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + seq.elem_labeled( + EdgeLabel::ConstantKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ConstantKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Equal, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Equal, + ), + )?; + seq.elem_labeled(EdgeLabel::Value, self.expression(input))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ConstantDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn constructor_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_4_22 { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.modifier_invocation(input); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::YulJumpKeyword, + TerminalKind::InternalKeyword, ); choice.consider(input, result)?; - } - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( + if self.version_is_at_least_0_6_0 && !self.version_is_at_least_0_6_7 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::OverrideKeyword, + ); + choice.consider(input, result)?; + } + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::YulJumpiKeyword, + TerminalKind::PayableKeyword, ); choice.consider(input, result)?; - } - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulLog0Keyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulLog1Keyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulLog2Keyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulLog3Keyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulLog4Keyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulLtKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulMLoadKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulModKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulMSizeKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulMStore8Keyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulMStoreKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulMulKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulMulModKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulNotKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulNumberKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulOriginKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulOrKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulPopKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulReturnKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulRevertKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSDivKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSelfDestructKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSgtKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSignExtendKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSLoadKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSltKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSModKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSStoreKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulStopKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSubKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulTimestampKeyword, - ); + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PublicKeyword, + ); + choice.consider(input, result)?; + if self.version_is_at_least_0_6_0 && !self.version_is_at_least_0_6_7 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::VirtualKeyword, + ); + choice.consider(input, result)?; + } + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ConstructorAttribute) + } + + #[allow(unused_assignments, unused_parens)] + fn constructor_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_4_22 { + ZeroOrMoreHelper::run(input, |input| { + self.constructor_attribute(input) + .with_label(EdgeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ConstructorAttributes) + } + + #[allow(unused_assignments, unused_parens)] + fn constructor_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_4_22 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ConstructorKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ConstructorKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; + seq.elem_labeled(EdgeLabel::Attributes, self.constructor_attributes(input))?; + seq.elem_labeled(EdgeLabel::Body, self.block(input))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ConstructorDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn continue_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + self.parse_terminal_with_trivia::( + input, + TerminalKind::ContinueKeyword, + ) + .with_label(EdgeLabel::ContinueKeyword) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::ContinueStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn contract_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + if self.version_is_at_least_0_6_0 { + seq.elem_labeled( + EdgeLabel::AbstractKeyword, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::AbstractKeyword, + ), + ), + )?; + } + seq.elem_labeled( + EdgeLabel::ContractKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ContractKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Inheritance, + OptionalHelper::transform(self.inheritance_specifier(input)), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.contract_members(input) + .with_label(EdgeLabel::Members) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }))?; + seq.finish() + }) + .with_kind(NonterminalKind::ContractDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn contract_member(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.using_directive(input); choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulXorKeyword, - ); + let result = self.function_definition(input); choice.consider(input, result)?; - if self.version_is_at_least_0_4_12 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulKeccak256Keyword, - ); + if self.version_is_at_least_0_4_22 { + let result = self.constructor_definition(input); choice.consider(input, result)?; } - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSha3Keyword, - ); + if self.version_is_at_least_0_6_0 { + let result = self.receive_function_definition(input); choice.consider(input, result)?; } - if !self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSuicideKeyword, - ); + if self.version_is_at_least_0_6_0 { + let result = self.fallback_function_definition(input); choice.consider(input, result)?; } - if self.version_is_at_least_0_4_12 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulReturnDataCopyKeyword, - ); + if !self.version_is_at_least_0_6_0 { + let result = self.unnamed_function_definition(input); choice.consider(input, result)?; } - if self.version_is_at_least_0_4_12 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulReturnDataSizeKeyword, - ); + let result = self.modifier_definition(input); + choice.consider(input, result)?; + let result = self.struct_definition(input); + choice.consider(input, result)?; + let result = self.enum_definition(input); + choice.consider(input, result)?; + let result = self.event_definition(input); + choice.consider(input, result)?; + if self.version_is_at_least_0_8_4 { + let result = self.error_definition(input); choice.consider(input, result)?; } - if self.version_is_at_least_0_4_12 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulStaticCallKeyword, - ); + if self.version_is_at_least_0_8_8 { + let result = self.user_defined_value_type_definition(input); choice.consider(input, result)?; } - if self.version_is_at_least_0_4_12 { - let result = self.parse_terminal_with_trivia::( + let result = self.state_variable_definition(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::ContractMember) + } + + #[allow(unused_assignments, unused_parens)] + fn contract_members(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.contract_member(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::ContractMembers) + } + + #[allow(unused_assignments, unused_parens)] + fn decimal_number_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Literal, + self.parse_terminal_with_trivia::( + input, + TerminalKind::DecimalLiteral, + ), + )?; + seq.elem_labeled( + EdgeLabel::Unit, + OptionalHelper::transform(self.number_unit(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::DecimalNumberExpression) + } + + #[allow(unused_assignments, unused_parens)] + fn do_while_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::DoKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::DoKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; + seq.elem_labeled( + EdgeLabel::WhileKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::WhileKeyword, + ), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.expression(input) + .with_label(EdgeLabel::Condition) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( input, - TerminalKind::YulCreate2Keyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_5_0 { - let result = self.parse_terminal_with_trivia::( + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::DoWhileStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn elementary_type(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::BoolKeyword, + ); + choice.consider(input, result)?; + if !self.version_is_at_least_0_8_0 { + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::YulExtCodeHashKeyword, + TerminalKind::ByteKeyword, ); choice.consider(input, result)?; } - let result = self.parse_terminal_with_trivia::( + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::YulSarKeyword, + TerminalKind::StringKeyword, ); choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( + let result = self.address_type(input); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::YulShlKeyword, + TerminalKind::BytesKeyword, ); choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::YulShrKeyword, + TerminalKind::IntKeyword, ); choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::YulChainIdKeyword, + TerminalKind::UintKeyword, ); choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::FixedKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::UfixedKeyword, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::ElementaryType) + } + + #[allow(unused_assignments, unused_parens)] + fn else_branch(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ElseKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ElseKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::ElseBranch) + } + + #[allow(unused_assignments, unused_parens)] + fn emit_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_4_21 { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::EmitKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::EmitKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Event, self.identifier_path(input))?; + seq.elem_labeled(EdgeLabel::Arguments, self.arguments_declaration(input))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::EmitStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn enum_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::EnumKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::EnumKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.enum_members(input) + .with_label(EdgeLabel::Members) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }))?; + seq.finish() + }) + .with_kind(NonterminalKind::EnumDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn enum_members(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| { + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ) + .with_label(EdgeLabel::Item) + }, + TerminalKind::Comma, + EdgeLabel::Separator, + )) + .with_kind(NonterminalKind::EnumMembers) + } + + #[allow(unused_assignments, unused_parens)] + fn equality_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::EqualityExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn error_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_4 { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ErrorKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ErrorKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Members, + self.error_parameters_declaration(input), + )?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ErrorDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn error_parameter(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_4 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + seq.elem_labeled( + EdgeLabel::Name, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ErrorParameter) + } + + #[allow(unused_assignments, unused_parens)] + fn error_parameters(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_4 { + OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( input, - TerminalKind::YulSelfBalanceKeyword, - ); - choice.consider(input, result)?; - if self.version_is_at_least_0_8_7 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulBaseFeeKeyword, - ); - choice.consider(input, result)?; - } - if !self.version_is_at_least_0_8_18 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulDifficultyKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_18 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulPrevRandaoKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_24 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulBlobBaseFeeKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_24 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulBlobHashKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_24 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulTLoadKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_24 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulTStoreKeyword, - ); - choice.consider(input, result)?; - } - if self.version_is_at_least_0_8_24 { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulMCopyKeyword, - ); - choice.consider(input, result)?; - } - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::YulBuiltInFunction) + self, + |input| self.error_parameter(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + )) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ErrorParameters) } #[allow(unused_assignments, unused_parens)] - fn yul_colon_and_equal(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_5_5 { + fn error_parameters_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_4 { SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); seq.elem_labeled( - EdgeLabel::Colon, - self.parse_terminal_with_trivia::( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( input, - TerminalKind::Colon, + TerminalKind::OpenParen, ), )?; + seq.elem( + self.error_parameters(input) + .with_label(EdgeLabel::Parameters) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; seq.elem_labeled( - EdgeLabel::Equal, - self.parse_terminal_with_trivia::( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( input, - TerminalKind::Equal, + TerminalKind::CloseParen, ), )?; seq.finish() @@ -6241,3236 +1782,7698 @@ impl Parser { } else { ParserResult::disabled() } - .with_kind(NonterminalKind::YulColonAndEqual) + .with_kind(NonterminalKind::ErrorParametersDeclaration) + } + + #[allow(unused_assignments, unused_parens)] + fn event_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::EventKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::EventKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Parameters, + self.event_parameters_declaration(input), + )?; + seq.elem_labeled( + EdgeLabel::AnonymousKeyword, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::AnonymousKeyword, + ), + ), + )?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::EventDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn event_parameter(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + seq.elem_labeled( + EdgeLabel::IndexedKeyword, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::IndexedKeyword, + ), + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::EventParameter) + } + + #[allow(unused_assignments, unused_parens)] + fn event_parameters(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| self.event_parameter(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + )) + .with_kind(NonterminalKind::EventParameters) + } + + #[allow(unused_assignments, unused_parens)] + fn event_parameters_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.event_parameters(input) + .with_label(EdgeLabel::Parameters) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::EventParametersDeclaration) } #[allow(unused_assignments, unused_parens)] - fn yul_continue_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulContinueKeyword, - ) - .with_label(EdgeLabel::ContinueKeyword) - .with_kind(NonterminalKind::YulContinueStatement) + fn experimental_feature(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ); + choice.consider(input, result)?; + let result = self.string_literal(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::ExperimentalFeature) } #[allow(unused_assignments, unused_parens)] - fn yul_default_case(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn experimental_pragma(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { seq.elem_labeled( - EdgeLabel::DefaultKeyword, - self.parse_terminal_with_trivia::( + EdgeLabel::ExperimentalKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ExperimentalKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Feature, self.experimental_feature(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::ExperimentalPragma) + } + + #[allow(unused_assignments, unused_parens)] + fn exponentiation_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::ExponentiationExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let parse_left_assignment_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::AssignmentExpression, + 1u8, + 1u8 + 1, + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::Equal, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::BarEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::PlusEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::MinusEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::CaretEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::SlashEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::PercentEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::AsteriskEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::AmpersandEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::LessThanLessThanEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThanGreaterThanEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThanGreaterThanGreaterThanEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + choice.finish(input) + }), + ) + }; + let parse_postfix_conditional_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_postfix_operator( + NonterminalKind::ConditionalExpression, + 3u8, + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::QuestionMark, + self.parse_terminal_with_trivia::( + input, + TerminalKind::QuestionMark, + ), + )?; + seq.elem_labeled(EdgeLabel::TrueExpression, self.expression(input))?; + seq.elem_labeled( + EdgeLabel::Colon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Colon, + ), + )?; + seq.elem_labeled(EdgeLabel::FalseExpression, self.expression(input))?; + seq.finish() + }), + ) + }; + let parse_left_or_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::OrExpression, + 5u8, + 5u8 + 1, + self.parse_terminal_with_trivia::( + input, + TerminalKind::BarBar, + ) + .with_label(EdgeLabel::Operator), + ) + }; + let parse_left_and_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::AndExpression, + 7u8, + 7u8 + 1, + self.parse_terminal_with_trivia::( + input, + TerminalKind::AmpersandAmpersand, + ) + .with_label(EdgeLabel::Operator), + ) + }; + let parse_left_equality_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::EqualityExpression, + 9u8, + 9u8 + 1, + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::EqualEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::BangEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + choice.finish(input) + }), + ) + }; + let parse_left_comparison_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::ComparisonExpression, + 11u8, + 11u8 + 1, + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::LessThan, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThan, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::LessThanEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThanEqual, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + choice.finish(input) + }), + ) + }; + let parse_left_bitwise_or_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::BitwiseOrExpression, + 13u8, + 13u8 + 1, + self.parse_terminal_with_trivia::( input, - TerminalKind::YulDefaultKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulDefaultCase) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_equal_and_colon(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_5_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Equal, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Equal, - ), - )?; - seq.elem_labeled( - EdgeLabel::Colon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Colon, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::YulEqualAndColon) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let parse_postfix_yul_function_call_expression = |input: &mut ParserContext<'_>| { + TerminalKind::Bar, + ) + .with_label(EdgeLabel::Operator), + ) + }; + let parse_left_bitwise_xor_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::BitwiseXorExpression, + 15u8, + 15u8 + 1, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Caret, + ) + .with_label(EdgeLabel::Operator), + ) + }; + let parse_left_bitwise_and_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::BitwiseAndExpression, + 17u8, + 17u8 + 1, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Ampersand, + ) + .with_label(EdgeLabel::Operator), + ) + }; + let parse_left_shift_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::ShiftExpression, + 19u8, + 19u8 + 1, + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::LessThanLessThan, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThanGreaterThan, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThanGreaterThanGreaterThan, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + choice.finish(input) + }), + ) + }; + let parse_left_additive_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::AdditiveExpression, + 21u8, + 21u8 + 1, + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::Plus, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::Minus, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + choice.finish(input) + }), + ) + }; + let parse_left_multiplicative_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::MultiplicativeExpression, + 23u8, + 23u8 + 1, + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::Asterisk, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::Slash, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::Percent, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + choice.finish(input) + }), + ) + }; + let parse_left_exponentiation_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::ExponentiationExpression, + 25u8, + 25u8 + 1, + ChoiceHelper::run(input, |mut choice, input| { + if !self.version_is_at_least_0_8_0 { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::AsteriskAsterisk, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + } + choice.finish(input) + }), + ) + }; + let parse_right_exponentiation_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_binary_operator( + NonterminalKind::ExponentiationExpression, + 27u8 + 1, + 27u8, + ChoiceHelper::run(input, |mut choice, input| { + if self.version_is_at_least_0_8_0 { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::AsteriskAsterisk, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + } + choice.finish(input) + }), + ) + }; + let parse_postfix_postfix_expression = |input: &mut ParserContext<'_>| { PrecedenceHelper::to_postfix_operator( - NonterminalKind::YulFunctionCallExpression, - 1u8, - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( + NonterminalKind::PostfixExpression, + 29u8, + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::PlusPlus, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::MinusMinus, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + choice.finish(input) + }), + ) + }; + let parse_prefix_prefix_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_prefix_operator( + NonterminalKind::PrefixExpression, + 31u8, + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::PlusPlus, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.yul_arguments(input) - .with_label(EdgeLabel::Arguments) - .recover_until_with_nested_delims::<_, LexicalContextType::Yul>( + TerminalKind::MinusMinus, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( + TerminalKind::Tilde, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() + TerminalKind::Bang, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::Minus, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::Plus, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + } + let result = self + .parse_terminal_with_trivia::( + input, + TerminalKind::DeleteKeyword, + ) + .with_label(EdgeLabel::Operator); + choice.consider(input, result)?; + choice.finish(input) }), ) }; - let primary_expression_parser = |input: &mut ParserContext<'_>| { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.yul_literal(input); - choice.consider(input, result)?; - let result = self.yul_built_in_function(input); - choice.consider(input, result)?; - let result = self.yul_path(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - }; - let postfix_operator_parser = |input: &mut ParserContext<'_>| { - ChoiceHelper::run(input, |mut choice, input| { - let result = parse_postfix_yul_function_call_expression(input); - choice.consider(input, result)?; - choice.finish(input) - }) - }; - let linear_expression_parser = |input: &mut ParserContext<'_>| { - SequenceHelper::run(|mut seq| { - seq.elem(primary_expression_parser(input))?; - seq.elem(ZeroOrMoreHelper::run(input, postfix_operator_parser))?; - seq.finish() - }) + let parse_postfix_function_call_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_postfix_operator( + NonterminalKind::FunctionCallExpression, + 33u8, + self.arguments_declaration(input) + .with_label(EdgeLabel::Arguments), + ) }; - PrecedenceHelper::reduce_precedence_result( - NonterminalKind::YulExpression, - linear_expression_parser(input), - ) - .with_kind(NonterminalKind::YulExpression) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_for_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::ForKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulForKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Initialization, self.yul_block(input))?; - seq.elem_labeled(EdgeLabel::Condition, self.yul_expression(input))?; - seq.elem_labeled(EdgeLabel::Iterator, self.yul_block(input))?; - seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulForStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_function_call_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { - let result = self.yul_expression(input); - let ParserResult::Match(r#match) = &result else { - return result; + let parse_postfix_call_options_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_postfix_operator( + NonterminalKind::CallOptionsExpression, + 35u8, + ChoiceHelper::run(input, |mut choice, input| { + if self.version_is_at_least_0_6_2 { + let result = SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq . elem (self . call_options (input) . with_label (EdgeLabel :: Options) . recover_until_with_nested_delims :: < _ , LexicalContextType :: Default > (input , self , TerminalKind :: CloseBrace , TerminalAcceptanceThreshold (2u8) ,)) ? ; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }); + choice.consider(input, result)?; + } + choice.finish(input) + }), + ) }; - match &r#match.nodes[..] { - [cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::YulExpression => match &node.children[..] { - [inner @ cst::Edge { - node: cst::Node::Nonterminal(node), - .. - }] if node.kind == NonterminalKind::YulFunctionCallExpression => { - ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) - } - _ => ParserResult::default(), - }, - _ => ParserResult::default(), - } - } - - #[allow(unused_assignments, unused_parens)] - fn yul_function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::FunctionKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulFunctionKeyword, - ), - )?; - seq.elem_labeled( - EdgeLabel::Name, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulIdentifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Parameters, - self.yul_parameters_declaration(input), - )?; - seq.elem_labeled( - EdgeLabel::Returns, - OptionalHelper::transform(self.yul_returns_declaration(input)), - )?; - seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulFunctionDefinition) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_if_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::IfKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulIfKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Condition, self.yul_expression(input))?; - seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulIfStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_label(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_5_0 { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Label, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulIdentifier, - ), - )?; - seq.elem_labeled( - EdgeLabel::Colon, - self.parse_terminal_with_trivia::( - input, - TerminalKind::Colon, - ), - )?; - seq.finish() - }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::YulLabel) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_leave_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - if self.version_is_at_least_0_6_0 { - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulLeaveKeyword, + let parse_postfix_member_access_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_postfix_operator( + NonterminalKind::MemberAccessExpression, + 37u8, + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Period, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Period, + ), + )?; + seq.elem_labeled( + EdgeLabel::Member, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.finish() + }), ) - .with_label(EdgeLabel::LeaveKeyword) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::YulLeaveStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulTrueKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulFalseKeyword, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulDecimalLiteral, - ); - choice.consider(input, result)?; - let result = self.parse_terminal_with_trivia::( - input, - TerminalKind::YulHexLiteral, - ); - choice.consider(input, result)?; - let result = self.hex_string_literal(input); - choice.consider(input, result)?; - let result = self.string_literal(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::YulLiteral) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_parameters(&self, input: &mut ParserContext<'_>) -> ParserResult { - OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Yul>( - input, - self, - |input| { - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulIdentifier, - ) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Comma, - EdgeLabel::Separator, - )) - .with_kind(NonterminalKind::YulParameters) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_parameters_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - let mut delim_guard = input.open_delim(TerminalKind::CloseParen); - let input = delim_guard.ctx(); - seq.elem_labeled( - EdgeLabel::OpenParen, - self.parse_terminal_with_trivia::( - input, - TerminalKind::OpenParen, - ), - )?; - seq.elem( - self.yul_parameters(input) - .with_label(EdgeLabel::Parameters) - .recover_until_with_nested_delims::<_, LexicalContextType::Yul>( + }; + let parse_postfix_index_access_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_postfix_operator( + NonterminalKind::IndexAccessExpression, + 39u8, + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBracket); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBracket, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBracket, + ), + )?; + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Start, + OptionalHelper::transform(self.expression(input)), + )?; + seq.elem_labeled( + EdgeLabel::End, + OptionalHelper::transform(self.index_access_end(input)), + )?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBracket, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBracket, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBracket, + ), + )?; + seq.finish() + }), + ) + }; + let prefix_operator_parser = |input: &mut ParserContext<'_>| { + ChoiceHelper::run(input, |mut choice, input| { + let result = parse_prefix_prefix_expression(input); + choice.consider(input, result)?; + choice.finish(input) + }) + }; + let primary_expression_parser = |input: &mut ParserContext<'_>| { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.new_expression(input); + choice.consider(input, result)?; + let result = self.tuple_expression(input); + choice.consider(input, result)?; + if self.version_is_at_least_0_5_3 { + let result = self.type_expression(input); + choice.consider(input, result)?; + } + let result = self.array_expression(input); + choice.consider(input, result)?; + let result = self.hex_number_expression(input); + choice.consider(input, result)?; + let result = self.decimal_number_expression(input); + choice.consider(input, result)?; + let result = self.string_expression(input); + choice.consider(input, result)?; + let result = self.elementary_type(input); + choice.consider(input, result)?; + if self.version_is_at_least_0_6_0 { + let result = self.parse_terminal_with_trivia::( input, - self, - TerminalKind::CloseParen, - TerminalAcceptanceThreshold(0u8), - ), - )?; - seq.elem_labeled( - EdgeLabel::CloseParen, - self.parse_terminal_with_trivia::( + TerminalKind::PayableKeyword, + ); + choice.consider(input, result)?; + } + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::CloseParen, - ), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::YulParametersDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_path(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Yul>( - input, - self, - |input| { - self.parse_terminal_with_trivia::( + TerminalKind::ThisKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::YulIdentifier, - ) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Period, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::YulPath) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_paths(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Yul>( - input, - self, - |input| self.yul_path(input).with_label(EdgeLabel::Item), - TerminalKind::Comma, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::YulPaths) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_returns_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::MinusGreaterThan, - self.parse_terminal_with_trivia::( + TerminalKind::SuperKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::MinusGreaterThan, - ), - )?; - seq.elem_labeled(EdgeLabel::Variables, self.yul_variable_names(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulReturnsDeclaration) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_stack_assignment_operator(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_5_0 { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.parse_terminal_with_trivia::( + TerminalKind::TrueKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( input, - TerminalKind::EqualColon, + TerminalKind::FalseKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, ); choice.consider(input, result)?; - let result = self.yul_equal_and_colon(input); + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + }; + let postfix_operator_parser = |input: &mut ParserContext<'_>| { + ChoiceHelper::run(input, |mut choice, input| { + let result = parse_postfix_conditional_expression(input); + choice.consider(input, result)?; + let result = parse_postfix_postfix_expression(input); + choice.consider(input, result)?; + let result = parse_postfix_function_call_expression(input); + choice.consider(input, result)?; + let result = parse_postfix_call_options_expression(input); + choice.consider(input, result)?; + let result = parse_postfix_member_access_expression(input); + choice.consider(input, result)?; + let result = parse_postfix_index_access_expression(input); choice.consider(input, result)?; choice.finish(input) }) - .with_label(EdgeLabel::Variant) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::YulStackAssignmentOperator) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_stack_assignment_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - if !self.version_is_at_least_0_5_0 { + }; + let binary_operand_parser = |input: &mut ParserContext<'_>| { SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::Assignment, - self.yul_stack_assignment_operator(input), - )?; - seq.elem_labeled( - EdgeLabel::Variable, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulIdentifier, - ), - )?; + seq.elem(ZeroOrMoreHelper::run(input, prefix_operator_parser))?; + seq.elem(primary_expression_parser(input))?; + seq.elem(ZeroOrMoreHelper::run(input, postfix_operator_parser))?; seq.finish() }) - } else { - ParserResult::disabled() - } - .with_kind(NonterminalKind::YulStackAssignmentStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.yul_block(input); - choice.consider(input, result)?; - let result = self.yul_function_definition(input); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.yul_stack_assignment_statement(input); + }; + let binary_operator_parser = |input: &mut ParserContext<'_>| { + ChoiceHelper::run(input, |mut choice, input| { + let result = parse_left_assignment_expression(input); choice.consider(input, result)?; - } - let result = self.yul_if_statement(input); - choice.consider(input, result)?; - let result = self.yul_for_statement(input); - choice.consider(input, result)?; - let result = self.yul_switch_statement(input); - choice.consider(input, result)?; - if self.version_is_at_least_0_6_0 { - let result = self.yul_leave_statement(input); + let result = parse_left_or_expression(input); choice.consider(input, result)?; - } - let result = self.yul_break_statement(input); - choice.consider(input, result)?; - let result = self.yul_continue_statement(input); - choice.consider(input, result)?; - let result = self.yul_variable_assignment_statement(input); - choice.consider(input, result)?; - if !self.version_is_at_least_0_5_0 { - let result = self.yul_label(input); + let result = parse_left_and_expression(input); choice.consider(input, result)?; - } - let result = self.yul_variable_declaration_statement(input); - choice.consider(input, result)?; - let result = self.yul_expression(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::YulStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_statements(&self, input: &mut ParserContext<'_>) -> ParserResult { - ZeroOrMoreHelper::run(input, |input| { - self.yul_statement(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::YulStatements) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_switch_case(&self, input: &mut ParserContext<'_>) -> ParserResult { - ChoiceHelper::run(input, |mut choice, input| { - let result = self.yul_default_case(input); - choice.consider(input, result)?; - let result = self.yul_value_case(input); - choice.consider(input, result)?; - choice.finish(input) - }) - .with_label(EdgeLabel::Variant) - .with_kind(NonterminalKind::YulSwitchCase) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_switch_cases(&self, input: &mut ParserContext<'_>) -> ParserResult { - OneOrMoreHelper::run(input, |input| { - self.yul_switch_case(input).with_label(EdgeLabel::Item) - }) - .with_kind(NonterminalKind::YulSwitchCases) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_switch_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::SwitchKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulSwitchKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Expression, self.yul_expression(input))?; - seq.elem_labeled(EdgeLabel::Cases, self.yul_switch_cases(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulSwitchStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_value_case(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::CaseKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulCaseKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Value, self.yul_literal(input))?; - seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulValueCase) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_variable_assignment_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::Variables, self.yul_paths(input))?; - seq.elem_labeled(EdgeLabel::Assignment, self.yul_assignment_operator(input))?; - seq.elem_labeled(EdgeLabel::Expression, self.yul_expression(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulVariableAssignmentStatement) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_variable_declaration_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { - SequenceHelper::run(|mut seq| { - seq.elem_labeled( - EdgeLabel::LetKeyword, - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulLetKeyword, - ), - )?; - seq.elem_labeled(EdgeLabel::Variables, self.yul_variable_names(input))?; - seq.elem_labeled( - EdgeLabel::Value, - OptionalHelper::transform(self.yul_variable_declaration_value(input)), - )?; - seq.finish() - }) - .with_kind(NonterminalKind::YulVariableDeclarationStatement) + let result = parse_left_equality_expression(input); + choice.consider(input, result)?; + let result = parse_left_comparison_expression(input); + choice.consider(input, result)?; + let result = parse_left_bitwise_or_expression(input); + choice.consider(input, result)?; + let result = parse_left_bitwise_xor_expression(input); + choice.consider(input, result)?; + let result = parse_left_bitwise_and_expression(input); + choice.consider(input, result)?; + let result = parse_left_shift_expression(input); + choice.consider(input, result)?; + let result = parse_left_additive_expression(input); + choice.consider(input, result)?; + let result = parse_left_multiplicative_expression(input); + choice.consider(input, result)?; + let result = parse_left_exponentiation_expression(input); + choice.consider(input, result)?; + let result = parse_right_exponentiation_expression(input); + choice.consider(input, result)?; + choice.finish(input) + }) + }; + let linear_expression_parser = |input: &mut ParserContext<'_>| { + SequenceHelper::run(|mut seq| { + seq.elem(binary_operand_parser(input))?; + seq.elem(ZeroOrMoreHelper::run(input, |input| { + SequenceHelper::run(|mut seq| { + seq.elem(binary_operator_parser(input))?; + seq.elem(binary_operand_parser(input))?; + seq.finish() + }) + }))?; + seq.finish() + }) + }; + PrecedenceHelper::reduce_precedence_result( + NonterminalKind::Expression, + linear_expression_parser(input), + ) + .with_kind(NonterminalKind::Expression) } #[allow(unused_assignments, unused_parens)] - fn yul_variable_declaration_value(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn expression_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { - seq.elem_labeled(EdgeLabel::Assignment, self.yul_assignment_operator(input))?; - seq.elem_labeled(EdgeLabel::Expression, self.yul_expression(input))?; - seq.finish() - }) - .with_kind(NonterminalKind::YulVariableDeclarationValue) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_variable_names(&self, input: &mut ParserContext<'_>) -> ParserResult { - SeparatedHelper::run::<_, LexicalContextType::Yul>( - input, - self, - |input| { - self.parse_terminal_with_trivia::( - input, - TerminalKind::YulIdentifier, - ) - .with_label(EdgeLabel::Item) - }, - TerminalKind::Comma, - EdgeLabel::Separator, - ) - .with_kind(NonterminalKind::YulVariableNames) + seq.elem( + self.expression(input) + .with_label(EdgeLabel::Expression) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::ExpressionStatement) } #[allow(unused_assignments, unused_parens)] - fn leading_trivia(&self, input: &mut ParserContext<'_>) -> ParserResult { - OneOrMoreHelper::run(input, |input| { + fn fallback_function_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { ChoiceHelper::run(input, |mut choice, input| { - let result = self - .parse_terminal::(input, TerminalKind::Whitespace) - .with_label(EdgeLabel::LeadingTrivia); + let result = self.modifier_invocation(input); choice.consider(input, result)?; - let result = self - .parse_terminal::(input, TerminalKind::EndOfLine) - .with_label(EdgeLabel::LeadingTrivia); + let result = self.override_specifier(input); choice.consider(input, result)?; - let result = self - .parse_terminal::( - input, - TerminalKind::SingleLineComment, - ) - .with_label(EdgeLabel::LeadingTrivia); + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ExternalKeyword, + ); choice.consider(input, result)?; - let result = self - .parse_terminal::( - input, - TerminalKind::MultiLineComment, - ) - .with_label(EdgeLabel::LeadingTrivia); + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PayableKeyword, + ); choice.consider(input, result)?; - let result = self - .parse_terminal::( - input, - TerminalKind::SingleLineNatSpecComment, - ) - .with_label(EdgeLabel::LeadingTrivia); + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PureKeyword, + ); choice.consider(input, result)?; - let result = self - .parse_terminal::( - input, - TerminalKind::MultiLineNatSpecComment, - ) - .with_label(EdgeLabel::LeadingTrivia); + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ViewKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::VirtualKeyword, + ); choice.consider(input, result)?; choice.finish(input) }) - }) + .with_label(EdgeLabel::Variant) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::FallbackFunctionAttribute) } #[allow(unused_assignments, unused_parens)] - fn trailing_trivia(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn fallback_function_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + ZeroOrMoreHelper::run(input, |input| { + self.fallback_function_attribute(input) + .with_label(EdgeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::FallbackFunctionAttributes) + } + + #[allow(unused_assignments, unused_parens)] + fn fallback_function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::FallbackKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::FallbackKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; + seq.elem_labeled( + EdgeLabel::Attributes, + self.fallback_function_attributes(input), + )?; + seq.elem_labeled( + EdgeLabel::Returns, + OptionalHelper::transform(self.returns_declaration(input)), + )?; + seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::FallbackFunctionDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn for_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { - seq.elem(OptionalHelper::transform( - self.parse_terminal::(input, TerminalKind::Whitespace) - .with_label(EdgeLabel::TrailingTrivia), - ))?; - seq.elem(OptionalHelper::transform( - self.parse_terminal::( + seq.elem_labeled( + EdgeLabel::ForKeyword, + self.parse_terminal_with_trivia::( input, - TerminalKind::SingleLineComment, - ) - .with_label(EdgeLabel::TrailingTrivia), - ))?; - seq.elem( - self.parse_terminal::(input, TerminalKind::EndOfLine) - .with_label(EdgeLabel::TrailingTrivia), + TerminalKind::ForKeyword, + ), )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Initialization, + self.for_statement_initialization(input), + )?; + seq.elem_labeled( + EdgeLabel::Condition, + self.for_statement_condition(input), + )?; + seq.elem_labeled( + EdgeLabel::Iterator, + OptionalHelper::transform(self.expression(input)), + )?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }))?; + seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; seq.finish() }) + .with_kind(NonterminalKind::ForStatement) } - /******************************************** - * Scanner Functions - ********************************************/ + #[allow(unused_assignments, unused_parens)] + fn for_statement_condition(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.expression_statement(input); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::ForStatementCondition) + } #[allow(unused_assignments, unused_parens)] - fn ascii_escape(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - scan_chars!(input, 't'), - scan_chars!(input, 'r'), - scan_chars!(input, 'n'), - scan_chars!(input, '\\'), - scan_chars!(input, '\''), - scan_chars!(input, '"'), - scan_chars!(input, '\r', '\n'), - scan_chars!(input, '\r'), - scan_chars!(input, '\n') - ) + fn for_statement_initialization(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.tuple_deconstruction_statement(input); + choice.consider(input, result)?; + let result = self.variable_declaration_statement(input); + choice.consider(input, result)?; + let result = self.expression_statement(input); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::ForStatementInitialization) } #[allow(unused_assignments, unused_parens)] - fn decimal_digits(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_one_or_more!(input, scan_char_range!(input, '0'..='9')), - scan_zero_or_more!( + fn function_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.modifier_invocation(input); + choice.consider(input, result)?; + if self.version_is_at_least_0_6_0 { + let result = self.override_specifier(input); + choice.consider(input, result)?; + } + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ConstantKeyword, + ); + choice.consider(input, result)?; + } + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ExternalKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::InternalKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( input, - scan_sequence!( - scan_chars!(input, '_'), - scan_one_or_more!(input, scan_char_range!(input, '0'..='9')) - ) - ) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn decimal_exponent(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_choice!(input, scan_chars!(input, 'e'), scan_chars!(input, 'E')), - scan_optional!(input, scan_chars!(input, '-')), - self.decimal_digits(input) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn decimal_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - scan_not_followed_by!( + TerminalKind::PayableKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( input, - scan_sequence!( - scan_chars!(input, '.'), - self.decimal_digits(input), - scan_optional!(input, self.decimal_exponent(input)) - ), - self.identifier_start(input) - ), - scan_not_followed_by!( + TerminalKind::PrivateKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( input, - scan_sequence!( - scan_not_followed_by!( - input, - self.decimal_digits(input), - scan_chars!(input, '.') - ), - scan_optional!(input, self.decimal_exponent(input)) - ), - self.identifier_start(input) - ), - if !self.version_is_at_least_0_5_0 { - scan_not_followed_by!( + TerminalKind::PublicKeyword, + ); + choice.consider(input, result)?; + if self.version_is_at_least_0_4_16 { + let result = self.parse_terminal_with_trivia::( input, - scan_sequence!( - scan_not_followed_by!( - input, - scan_sequence!(self.decimal_digits(input), scan_chars!(input, '.')), - self.decimal_digits(input) - ), - scan_optional!(input, self.decimal_exponent(input)) - ), - self.identifier_start(input) - ) - } else { - false - }, - if !self.version_is_at_least_0_5_0 { - scan_not_followed_by!( + TerminalKind::PureKeyword, + ); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_4_16 { + let result = self.parse_terminal_with_trivia::( input, - scan_sequence!( - self.decimal_digits(input), - scan_chars!(input, '.'), - self.decimal_digits(input), - scan_optional!(input, self.decimal_exponent(input)) - ), - self.identifier_start(input) - ) - } else { - false - }, - if self.version_is_at_least_0_5_0 { - scan_not_followed_by!( + TerminalKind::ViewKeyword, + ); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_6_0 { + let result = self.parse_terminal_with_trivia::( input, - scan_sequence!( - self.decimal_digits(input), - scan_optional!( - input, - scan_sequence!(scan_chars!(input, '.'), self.decimal_digits(input)) - ), - scan_optional!(input, self.decimal_exponent(input)) - ), - self.identifier_start(input) - ) - } else { - false + TerminalKind::VirtualKeyword, + ); + choice.consider(input, result)?; } - ) + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::FunctionAttribute) } #[allow(unused_assignments, unused_parens)] - fn double_quoted_hex_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, 'h', 'e', 'x', '"'), - scan_optional!(input, self.hex_string_contents(input)), - scan_chars!(input, '"') - ) + fn function_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.function_attribute(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::FunctionAttributes) } #[allow(unused_assignments, unused_parens)] - fn double_quoted_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - if !self.version_is_at_least_0_4_25 { - scan_sequence!( - scan_chars!(input, '"'), - scan_zero_or_more!( - input, - scan_choice!( - input, - self.escape_sequence_arbitrary(input), - scan_none_of!(input, '"', '\\', '\r', '\n') - ) - ), - scan_chars!(input, '"') - ) - } else { - false - }, - if self.version_is_at_least_0_4_25 && !self.version_is_at_least_0_7_0 { - scan_sequence!( - scan_chars!(input, '"'), - scan_zero_or_more!( - input, - scan_choice!( - input, - self.escape_sequence(input), - scan_none_of!(input, '"', '\\', '\r', '\n') - ) - ), - scan_chars!(input, '"') - ) - } else { - false - }, - scan_sequence!( - scan_chars!(input, '"'), - scan_zero_or_more!( - input, - scan_choice!( - input, - self.escape_sequence(input), - scan_char_range!(input, ' '..='!'), - scan_char_range!(input, '#'..='['), - scan_char_range!(input, ']'..='~') - ) - ), - scan_chars!(input, '"') - ) - ) + fn function_body(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.block(input); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::FunctionBody) } #[allow(unused_assignments, unused_parens)] - fn double_quoted_unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - if self.version_is_at_least_0_7_0 { - scan_sequence!( - scan_chars!(input, 'u', 'n', 'i', 'c', 'o', 'd', 'e', '"'), - scan_zero_or_more!( - input, - scan_choice!( - input, - self.escape_sequence(input), - scan_none_of!(input, '"', '\\', '\r', '\n') - ) - ), - scan_chars!(input, '"') - ) - } else { - false + fn function_call_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::FunctionCallExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), } } #[allow(unused_assignments, unused_parens)] - fn double_quoted_version_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, '"'), - self.version_specifier_fragment(input), - scan_zero_or_more!( - input, - scan_sequence!( - scan_chars!(input, '.'), - self.version_specifier_fragment(input) - ) - ), - scan_chars!(input, '"') - ) - } - - #[allow(unused_assignments, unused_parens)] - fn end_of_line(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - scan_chars!(input, '\n'), - scan_sequence!( - scan_chars!(input, '\r'), - scan_optional!(input, scan_chars!(input, '\n')) - ) - ) + fn function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::FunctionKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::FunctionKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Name, self.function_name(input))?; + seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; + seq.elem_labeled(EdgeLabel::Attributes, self.function_attributes(input))?; + seq.elem_labeled( + EdgeLabel::Returns, + OptionalHelper::transform(self.returns_declaration(input)), + )?; + seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::FunctionDefinition) } #[allow(unused_assignments, unused_parens)] - fn escape_sequence(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, '\\'), - scan_choice!( + fn function_name(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( input, - self.ascii_escape(input), - self.hex_byte_escape(input), - self.unicode_escape(input) - ) - ) + TerminalKind::Identifier, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::FallbackKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ReceiveKeyword, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::FunctionName) } #[allow(unused_assignments, unused_parens)] - fn escape_sequence_arbitrary(&self, input: &mut ParserContext<'_>) -> bool { - if !self.version_is_at_least_0_4_25 { - scan_sequence!( - scan_chars!(input, '\\'), - scan_choice!( + fn function_type(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::FunctionKeyword, + self.parse_terminal_with_trivia::( input, - scan_none_of!(input, 'x', 'u'), - self.hex_byte_escape(input), - self.unicode_escape(input) - ) - ) - } else { - false - } + TerminalKind::FunctionKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; + seq.elem_labeled(EdgeLabel::Attributes, self.function_type_attributes(input))?; + seq.elem_labeled( + EdgeLabel::Returns, + OptionalHelper::transform(self.returns_declaration(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::FunctionType) } #[allow(unused_assignments, unused_parens)] - fn hex_byte_escape(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, 'x'), - self.hex_character(input), - self.hex_character(input) - ) + fn function_type_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::InternalKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ExternalKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PrivateKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PublicKeyword, + ); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ConstantKeyword, + ); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_4_16 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PureKeyword, + ); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_4_16 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ViewKeyword, + ); + choice.consider(input, result)?; + } + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PayableKeyword, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::FunctionTypeAttribute) } #[allow(unused_assignments, unused_parens)] - fn hex_character(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - scan_char_range!(input, '0'..='9'), - scan_char_range!(input, 'a'..='f'), - scan_char_range!(input, 'A'..='F') - ) + fn function_type_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.function_type_attribute(input) + .with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::FunctionTypeAttributes) } #[allow(unused_assignments, unused_parens)] - fn hex_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - scan_not_followed_by!( - input, - scan_sequence!( - scan_chars!(input, '0', 'x'), - scan_one_or_more!(input, self.hex_character(input)), - scan_zero_or_more!( - input, - scan_sequence!( - scan_chars!(input, '_'), - scan_one_or_more!(input, self.hex_character(input)) - ) - ) + fn hex_number_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Literal, + self.parse_terminal_with_trivia::( + input, + TerminalKind::HexLiteral, ), - self.identifier_start(input) - ), + )?; if !self.version_is_at_least_0_5_0 { - scan_not_followed_by!( - input, - scan_sequence!( - scan_chars!(input, '0', 'X'), - scan_one_or_more!(input, self.hex_character(input)), - scan_zero_or_more!( - input, - scan_sequence!( - scan_chars!(input, '_'), - scan_one_or_more!(input, self.hex_character(input)) - ) - ) - ), - self.identifier_start(input) - ) - } else { - false + seq.elem_labeled( + EdgeLabel::Unit, + OptionalHelper::transform(self.number_unit(input)), + )?; } - ) + seq.finish() + }) + .with_kind(NonterminalKind::HexNumberExpression) } #[allow(unused_assignments, unused_parens)] - fn hex_string_contents(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - self.hex_character(input), - self.hex_character(input), - scan_zero_or_more!( + fn hex_string_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( input, - scan_sequence!( - scan_optional!(input, scan_chars!(input, '_')), - self.hex_character(input), - self.hex_character(input) - ) - ) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn identifier(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - self.identifier_start(input), - scan_zero_or_more!(input, self.identifier_part(input)) - ) + TerminalKind::SingleQuotedHexStringLiteral, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::DoubleQuotedHexStringLiteral, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::HexStringLiteral) } #[allow(unused_assignments, unused_parens)] - fn identifier_part(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - self.identifier_start(input), - scan_char_range!(input, '0'..='9') - ) + fn hex_string_literals(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_5_14 { + OneOrMoreHelper::run(input, |input| { + self.hex_string_literal(input).with_label(EdgeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::HexStringLiterals) } #[allow(unused_assignments, unused_parens)] - fn identifier_start(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( + fn identifier_path(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Default>( input, - scan_chars!(input, '_'), - scan_chars!(input, '$'), - scan_char_range!(input, 'a'..='z'), - scan_char_range!(input, 'A'..='Z') + self, + |input| { + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ) + .with_label(EdgeLabel::Item) + }, + TerminalKind::Period, + EdgeLabel::Separator, ) + .with_kind(NonterminalKind::IdentifierPath) } #[allow(unused_assignments, unused_parens)] - fn multi_line_comment(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_not_followed_by!( - input, - scan_chars!(input, '/', '*'), - scan_sequence!(scan_chars!(input, '*'), scan_none_of!(input, '/')) - ), - scan_zero_or_more!( - input, - scan_choice!( + fn if_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::IfKeyword, + self.parse_terminal_with_trivia::( input, - scan_none_of!(input, '*'), - scan_not_followed_by!(input, scan_chars!(input, '*'), scan_chars!(input, '/')) - ) - ), - scan_chars!(input, '*', '/') - ) + TerminalKind::IfKeyword, + ), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.expression(input) + .with_label(EdgeLabel::Condition) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }))?; + seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; + seq.elem_labeled( + EdgeLabel::ElseBranch, + OptionalHelper::transform(self.else_branch(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::IfStatement) } #[allow(unused_assignments, unused_parens)] - fn multi_line_nat_spec_comment(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_not_followed_by!( - input, - scan_chars!(input, '/', '*', '*'), - scan_chars!(input, '/') - ), - scan_zero_or_more!( - input, - scan_choice!( + fn import_alias(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::AsKeyword, + self.parse_terminal_with_trivia::( input, - scan_none_of!(input, '*'), - scan_not_followed_by!(input, scan_chars!(input, '*'), scan_chars!(input, '/')) - ) - ), - scan_chars!(input, '*', '/') - ) + TerminalKind::AsKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Identifier, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::ImportAlias) } #[allow(unused_assignments, unused_parens)] - fn single_line_comment(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_not_followed_by!(input, scan_chars!(input, '/', '/'), scan_chars!(input, '/')), - scan_zero_or_more!(input, scan_none_of!(input, '\r', '\n')) - ) + fn import_clause(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.path_import(input); + choice.consider(input, result)?; + let result = self.named_import(input); + choice.consider(input, result)?; + let result = self.import_deconstruction(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::ImportClause) } #[allow(unused_assignments, unused_parens)] - fn single_line_nat_spec_comment(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, '/', '/', '/'), - scan_zero_or_more!(input, scan_none_of!(input, '\r', '\n')) - ) + fn import_deconstruction(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.import_deconstruction_symbols(input) + .with_label(EdgeLabel::Symbols) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }))?; + seq.elem_labeled( + EdgeLabel::FromKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::FromKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Path, self.string_literal(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::ImportDeconstruction) } #[allow(unused_assignments, unused_parens)] - fn single_quoted_hex_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, 'h', 'e', 'x', '\''), - scan_optional!(input, self.hex_string_contents(input)), - scan_chars!(input, '\'') - ) + fn import_deconstruction_symbol(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Alias, + OptionalHelper::transform(self.import_alias(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::ImportDeconstructionSymbol) } #[allow(unused_assignments, unused_parens)] - fn single_quoted_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( + fn import_deconstruction_symbols(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Default>( input, - if !self.version_is_at_least_0_4_25 { - scan_sequence!( - scan_chars!(input, '\''), - scan_zero_or_more!( - input, - scan_choice!( - input, - self.escape_sequence_arbitrary(input), - scan_none_of!(input, '\'', '\\', '\r', '\n') - ) - ), - scan_chars!(input, '\'') - ) - } else { - false + self, + |input| { + self.import_deconstruction_symbol(input) + .with_label(EdgeLabel::Item) }, - if self.version_is_at_least_0_4_25 && !self.version_is_at_least_0_7_0 { - scan_sequence!( - scan_chars!(input, '\''), - scan_zero_or_more!( - input, - scan_choice!( + TerminalKind::Comma, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::ImportDeconstructionSymbols) + } + + #[allow(unused_assignments, unused_parens)] + fn import_directive(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ImportKeyword, + self.parse_terminal_with_trivia::( input, - self.escape_sequence(input), - scan_none_of!(input, '\'', '\\', '\r', '\n') - ) - ), - scan_chars!(input, '\'') - ) - } else { - false - }, - scan_sequence!( - scan_chars!(input, '\''), - scan_zero_or_more!( + TerminalKind::ImportKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Clause, self.import_clause(input))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( input, - scan_choice!( - input, - self.escape_sequence(input), - scan_char_range!(input, ' '..='&'), - scan_char_range!(input, '('..='['), - scan_char_range!(input, ']'..='~') - ) + TerminalKind::Semicolon, ), - scan_chars!(input, '\'') - ) - ) + )?; + seq.finish() + }) + .with_kind(NonterminalKind::ImportDirective) } #[allow(unused_assignments, unused_parens)] - fn single_quoted_unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - if self.version_is_at_least_0_7_0 { - scan_sequence!( - scan_chars!(input, 'u', 'n', 'i', 'c', 'o', 'd', 'e', '\''), - scan_zero_or_more!( + fn index_access_end(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Colon, + self.parse_terminal_with_trivia::( input, - scan_choice!( - input, - self.escape_sequence(input), - scan_none_of!(input, '\'', '\\', '\r', '\n') - ) + TerminalKind::Colon, ), - scan_chars!(input, '\'') - ) - } else { - false + )?; + seq.elem_labeled( + EdgeLabel::End, + OptionalHelper::transform(self.expression(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::IndexAccessEnd) + } + + #[allow(unused_assignments, unused_parens)] + fn index_access_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::IndexAccessExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), } } #[allow(unused_assignments, unused_parens)] - fn single_quoted_version_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, '\''), - self.version_specifier_fragment(input), - scan_zero_or_more!( - input, - scan_sequence!( - scan_chars!(input, '.'), - self.version_specifier_fragment(input) - ) - ), - scan_chars!(input, '\'') - ) + fn inheritance_specifier(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::IsKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::IsKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Types, self.inheritance_types(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::InheritanceSpecifier) } #[allow(unused_assignments, unused_parens)] - fn slash(&self, input: &mut ParserContext<'_>) -> bool { - scan_not_followed_by!( + fn inheritance_type(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.identifier_path(input))?; + seq.elem_labeled( + EdgeLabel::Arguments, + OptionalHelper::transform(self.arguments_declaration(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::InheritanceType) + } + + #[allow(unused_assignments, unused_parens)] + fn inheritance_types(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Default>( input, - scan_chars!(input, '/'), - scan_choice!( - input, - scan_chars!(input, '='), - scan_chars!(input, '/'), - scan_chars!(input, '*') - ) + self, + |input| self.inheritance_type(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, ) + .with_kind(NonterminalKind::InheritanceTypes) } #[allow(unused_assignments, unused_parens)] - fn unicode_escape(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, 'u'), - self.hex_character(input), - self.hex_character(input), - self.hex_character(input), - self.hex_character(input) - ) + fn interface_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::InterfaceKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::InterfaceKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Inheritance, + OptionalHelper::transform(self.inheritance_specifier(input)), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.interface_members(input) + .with_label(EdgeLabel::Members) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }))?; + seq.finish() + }) + .with_kind(NonterminalKind::InterfaceDefinition) } #[allow(unused_assignments, unused_parens)] - fn version_specifier(&self, input: &mut ParserContext<'_>) -> bool { - self.version_specifier_fragment(input) + fn interface_members(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.contract_member(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::InterfaceMembers) } #[allow(unused_assignments, unused_parens)] - fn version_specifier_fragment(&self, input: &mut ParserContext<'_>) -> bool { - scan_one_or_more!( - input, - scan_choice!( - input, - scan_chars!(input, 'x'), - scan_chars!(input, 'X'), - scan_chars!(input, '*'), - scan_char_range!(input, '0'..='9') - ) - ) + fn library_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::LibraryKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::LibraryKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.library_members(input) + .with_label(EdgeLabel::Members) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }))?; + seq.finish() + }) + .with_kind(NonterminalKind::LibraryDefinition) } #[allow(unused_assignments, unused_parens)] - fn whitespace(&self, input: &mut ParserContext<'_>) -> bool { - scan_one_or_more!( - input, - scan_choice!(input, scan_chars!(input, ' '), scan_chars!(input, '\t')) - ) + fn library_members(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.contract_member(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::LibraryMembers) } #[allow(unused_assignments, unused_parens)] - fn yul_decimal_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_not_followed_by!( - input, - scan_choice!( - input, - scan_chars!(input, '0'), - scan_sequence!( - scan_char_range!(input, '1'..='9'), - scan_zero_or_more!(input, scan_char_range!(input, '0'..='9')) - ) - ), - self.identifier_start(input) - ) + fn mapping_key(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::KeyType, self.mapping_key_type(input))?; + if self.version_is_at_least_0_8_18 { + seq.elem_labeled( + EdgeLabel::Name, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + ), + )?; + } + seq.finish() + }) + .with_kind(NonterminalKind::MappingKey) } #[allow(unused_assignments, unused_parens)] - fn yul_hex_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_not_followed_by!( - input, - scan_sequence!( - scan_chars!(input, '0', 'x'), - scan_one_or_more!(input, self.hex_character(input)) - ), - self.identifier_start(input) - ) + fn mapping_key_type(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.elementary_type(input); + choice.consider(input, result)?; + let result = self.identifier_path(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::MappingKeyType) } #[allow(unused_assignments, unused_parens)] - fn yul_identifier(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - if self.version_is_at_least_0_5_8 && !self.version_is_at_least_0_7_0 { - scan_sequence!( - self.identifier_start(input), - scan_zero_or_more!( + fn mapping_type(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::MappingKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::MappingKeyword, + ), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( input, - scan_choice!(input, scan_chars!(input, '.'), self.identifier_part(input)) - ) - ) - } else { - false - }, - scan_sequence!( - self.identifier_start(input), - scan_zero_or_more!(input, self.identifier_part(input)) - ) - ) + TerminalKind::OpenParen, + ), + )?; + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::KeyType, self.mapping_key(input))?; + seq.elem_labeled( + EdgeLabel::EqualGreaterThan, + self.parse_terminal_with_trivia::( + input, + TerminalKind::EqualGreaterThan, + ), + )?; + seq.elem_labeled(EdgeLabel::ValueType, self.mapping_value(input))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }))?; + seq.finish() + }) + .with_kind(NonterminalKind::MappingType) } - #[inline] - fn bytes_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( - input, - ident, - if scan_sequence!( - scan_chars!(input, 'b', 'y', 't', 'e', 's'), - scan_optional!( - input, - scan_choice!( - input, - scan_chars!(input, '9'), - scan_chars!(input, '8'), - scan_chars!(input, '7'), - scan_chars!(input, '6'), - scan_chars!(input, '5'), - scan_chars!(input, '4'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '3', '1'), - scan_chars!(input, '3', '0'), - scan_chars!(input, '3'), - scan_chars!(input, '2', '9'), - scan_chars!(input, '2', '8'), - scan_chars!(input, '2', '7'), - scan_chars!(input, '2', '6'), - scan_chars!(input, '2', '5'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3'), - scan_chars!(input, '2', '2'), - scan_chars!(input, '2', '1'), - scan_chars!(input, '2', '0'), - scan_chars!(input, '2'), - scan_chars!(input, '1', '9'), - scan_chars!(input, '1', '8'), - scan_chars!(input, '1', '7'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5'), - scan_chars!(input, '1', '4'), - scan_chars!(input, '1', '3'), - scan_chars!(input, '1', '2'), - scan_chars!(input, '1', '1'), - scan_chars!(input, '1', '0'), - scan_chars!(input, '1') - ) - ) - ) { - KeywordScan::Reserved(TerminalKind::BytesKeyword) - } else { - KeywordScan::Absent + #[allow(unused_assignments, unused_parens)] + fn mapping_value(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + if self.version_is_at_least_0_8_18 { + seq.elem_labeled( + EdgeLabel::Name, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + ), + )?; } - ) + seq.finish() + }) + .with_kind(NonterminalKind::MappingValue) } - #[inline] - fn fixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( - input, - ident, - if scan_chars!(input, 'f', 'i', 'x', 'e', 'd') { - KeywordScan::Reserved(TerminalKind::FixedKeyword) - } else { - KeywordScan::Absent - }, - if scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( - input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') - ), - scan_chars!(input, 'x'), - scan_choice!( - input, - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '1', '6') - ) - ) { - KeywordScan::Reserved(TerminalKind::FixedKeyword) - } else { - KeywordScan::Absent + #[allow(unused_assignments, unused_parens)] + fn member_access_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::MemberAccessExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), }, - if scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn modifier_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + if self.version_is_at_least_0_6_0 { + let result = self.override_specifier(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_6_0 { + let result = self.parse_terminal_with_trivia::( input, - scan_chars!(input, '2', '4', '8', 'x', '8'), - scan_chars!(input, '2', '4', '0', 'x', '8'), - scan_chars!(input, '2', '4', '0', 'x', '1', '6'), - scan_chars!(input, '2', '3', '2', 'x', '8'), - scan_chars!(input, '2', '3', '2', 'x', '2', '4'), - scan_chars!(input, '2', '3', '2', 'x', '1', '6'), - scan_chars!(input, '2', '2', '4', 'x', '8'), - scan_chars!(input, '2', '2', '4', 'x', '3', '2'), - scan_chars!(input, '2', '2', '4', 'x', '2', '4'), - scan_chars!(input, '2', '2', '4', 'x', '1', '6'), - scan_chars!(input, '2', '1', '6', 'x', '8'), - scan_chars!(input, '2', '1', '6', 'x', '4', '0'), - scan_chars!(input, '2', '1', '6', 'x', '3', '2'), - scan_chars!(input, '2', '1', '6', 'x', '2', '4'), - scan_chars!(input, '2', '1', '6', 'x', '1', '6'), - scan_chars!(input, '2', '0', '8', 'x', '8'), - scan_chars!(input, '2', '0', '8', 'x', '4', '8'), - scan_chars!(input, '2', '0', '8', 'x', '4', '0'), - scan_chars!(input, '2', '0', '8', 'x', '3', '2'), - scan_chars!(input, '2', '0', '8', 'x', '2', '4'), - scan_chars!(input, '2', '0', '8', 'x', '1', '6'), - scan_chars!(input, '2', '0', '0', 'x', '8'), - scan_chars!(input, '2', '0', '0', 'x', '5', '6'), - scan_chars!(input, '2', '0', '0', 'x', '4', '8'), - scan_chars!(input, '2', '0', '0', 'x', '4', '0'), - scan_chars!(input, '2', '0', '0', 'x', '3', '2'), - scan_chars!(input, '2', '0', '0', 'x', '2', '4'), - scan_chars!(input, '2', '0', '0', 'x', '1', '6'), - scan_chars!(input, '1', '9', '2', 'x', '8'), - scan_chars!(input, '1', '9', '2', 'x', '6', '4'), - scan_chars!(input, '1', '9', '2', 'x', '5', '6'), - scan_chars!(input, '1', '9', '2', 'x', '4', '8'), - scan_chars!(input, '1', '9', '2', 'x', '4', '0'), - scan_chars!(input, '1', '9', '2', 'x', '3', '2'), - scan_chars!(input, '1', '9', '2', 'x', '2', '4'), - scan_chars!(input, '1', '9', '2', 'x', '1', '6'), - scan_chars!(input, '1', '8', '4', 'x', '8'), - scan_chars!(input, '1', '8', '4', 'x', '7', '2'), - scan_chars!(input, '1', '8', '4', 'x', '6', '4'), - scan_chars!(input, '1', '8', '4', 'x', '5', '6'), - scan_chars!(input, '1', '8', '4', 'x', '4', '8'), - scan_chars!(input, '1', '8', '4', 'x', '4', '0'), - scan_chars!(input, '1', '8', '4', 'x', '3', '2'), - scan_chars!(input, '1', '8', '4', 'x', '2', '4'), - scan_chars!(input, '1', '8', '4', 'x', '1', '6') - ) - ) { - KeywordScan::Reserved(TerminalKind::FixedKeyword) - } else { - KeywordScan::Absent - }, - if scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + TerminalKind::VirtualKeyword, + ); + choice.consider(input, result)?; + } + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::ModifierAttribute) + } + + #[allow(unused_assignments, unused_parens)] + fn modifier_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.modifier_attribute(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::ModifierAttributes) + } + + #[allow(unused_assignments, unused_parens)] + fn modifier_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ModifierKeyword, + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '2', '5', '6', 'x', '8', '0'), - scan_chars!(input, '2', '5', '6', 'x', '8'), - scan_chars!(input, '2', '5', '6', 'x', '7', '2'), - scan_chars!(input, '2', '5', '6', 'x', '6', '4'), - scan_chars!(input, '2', '5', '6', 'x', '5', '6'), - scan_chars!(input, '2', '5', '6', 'x', '4', '8'), - scan_chars!(input, '2', '5', '6', 'x', '4', '0'), - scan_chars!(input, '2', '5', '6', 'x', '3', '2'), - scan_chars!(input, '2', '5', '6', 'x', '2', '4'), - scan_chars!(input, '2', '5', '6', 'x', '1', '6'), - scan_chars!(input, '2', '4', '8', 'x', '8', '0'), - scan_chars!(input, '2', '4', '8', 'x', '7', '2'), - scan_chars!(input, '2', '4', '8', 'x', '6', '4'), - scan_chars!(input, '2', '4', '8', 'x', '5', '6'), - scan_chars!(input, '2', '4', '8', 'x', '4', '8'), - scan_chars!(input, '2', '4', '8', 'x', '4', '0'), - scan_chars!(input, '2', '4', '8', 'x', '3', '2'), - scan_chars!(input, '2', '4', '8', 'x', '2', '4'), - scan_chars!(input, '2', '4', '8', 'x', '1', '6'), - scan_chars!(input, '2', '4', '0', 'x', '8', '0'), - scan_chars!(input, '2', '4', '0', 'x', '7', '2'), - scan_chars!(input, '2', '4', '0', 'x', '6', '4'), - scan_chars!(input, '2', '4', '0', 'x', '5', '6'), - scan_chars!(input, '2', '4', '0', 'x', '4', '8'), - scan_chars!(input, '2', '4', '0', 'x', '4', '0'), - scan_chars!(input, '2', '4', '0', 'x', '3', '2'), - scan_chars!(input, '2', '4', '0', 'x', '2', '4'), - scan_chars!(input, '2', '3', '2', 'x', '8', '0'), - scan_chars!(input, '2', '3', '2', 'x', '7', '2'), - scan_chars!(input, '2', '3', '2', 'x', '6', '4'), - scan_chars!(input, '2', '3', '2', 'x', '5', '6'), - scan_chars!(input, '2', '3', '2', 'x', '4', '8'), - scan_chars!(input, '2', '3', '2', 'x', '4', '0'), - scan_chars!(input, '2', '3', '2', 'x', '3', '2'), - scan_chars!(input, '2', '2', '4', 'x', '8', '0'), - scan_chars!(input, '2', '2', '4', 'x', '7', '2'), - scan_chars!(input, '2', '2', '4', 'x', '6', '4'), - scan_chars!(input, '2', '2', '4', 'x', '5', '6'), - scan_chars!(input, '2', '2', '4', 'x', '4', '8'), - scan_chars!(input, '2', '2', '4', 'x', '4', '0'), - scan_chars!(input, '2', '1', '6', 'x', '8', '0'), - scan_chars!(input, '2', '1', '6', 'x', '7', '2'), - scan_chars!(input, '2', '1', '6', 'x', '6', '4'), - scan_chars!(input, '2', '1', '6', 'x', '5', '6'), - scan_chars!(input, '2', '1', '6', 'x', '4', '8'), - scan_chars!(input, '2', '0', '8', 'x', '8', '0'), - scan_chars!(input, '2', '0', '8', 'x', '7', '2'), - scan_chars!(input, '2', '0', '8', 'x', '6', '4'), - scan_chars!(input, '2', '0', '8', 'x', '5', '6'), - scan_chars!(input, '2', '0', '0', 'x', '8', '0'), - scan_chars!(input, '2', '0', '0', 'x', '7', '2'), - scan_chars!(input, '2', '0', '0', 'x', '6', '4'), - scan_chars!(input, '1', '9', '2', 'x', '8', '0'), - scan_chars!(input, '1', '9', '2', 'x', '7', '2'), - scan_chars!(input, '1', '8', '4', 'x', '8', '0') - ) - ) { - if self.version_is_at_least_0_4_14 { - KeywordScan::Reserved(TerminalKind::FixedKeyword) - } else { - KeywordScan::Present(TerminalKind::FixedKeyword) + TerminalKind::ModifierKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Parameters, + OptionalHelper::transform(self.parameters_declaration(input)), + )?; + seq.elem_labeled(EdgeLabel::Attributes, self.modifier_attributes(input))?; + seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::ModifierDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn modifier_invocation(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::Name, self.identifier_path(input))?; + seq.elem_labeled( + EdgeLabel::Arguments, + OptionalHelper::transform(self.arguments_declaration(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::ModifierInvocation) + } + + #[allow(unused_assignments, unused_parens)] + fn multiplicative_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::MultiplicativeExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - } else { - KeywordScan::Absent + _ => ParserResult::default(), }, - if scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( - input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '5', '6'), - scan_chars!(input, '2', '4', '8'), - scan_chars!(input, '2', '4', '0'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3', '2'), - scan_chars!(input, '2', '2', '4'), - scan_chars!(input, '2', '1', '6'), - scan_chars!(input, '2', '0', '8'), - scan_chars!(input, '2', '0', '0'), - scan_chars!(input, '1', '9', '2'), - scan_chars!(input, '1', '8', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn named_argument(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, ), - scan_chars!(input, 'x'), - scan_choice!( + )?; + seq.elem_labeled( + EdgeLabel::Colon, + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '9'), - scan_chars!(input, '7', '9'), - scan_chars!(input, '7', '8'), - scan_chars!(input, '7', '7'), - scan_chars!(input, '7', '6'), - scan_chars!(input, '7', '5'), - scan_chars!(input, '7', '4'), - scan_chars!(input, '7', '3'), - scan_chars!(input, '7', '1'), - scan_chars!(input, '7', '0'), - scan_chars!(input, '7'), - scan_chars!(input, '6', '9'), - scan_chars!(input, '6', '8'), - scan_chars!(input, '6', '7'), - scan_chars!(input, '6', '6'), - scan_chars!(input, '6', '5'), - scan_chars!(input, '6', '3'), - scan_chars!(input, '6', '2'), - scan_chars!(input, '6', '1'), - scan_chars!(input, '6', '0'), - scan_chars!(input, '6'), - scan_chars!(input, '5', '9'), - scan_chars!(input, '5', '8'), - scan_chars!(input, '5', '7'), - scan_chars!(input, '5', '5'), - scan_chars!(input, '5', '4'), - scan_chars!(input, '5', '3'), - scan_chars!(input, '5', '2'), - scan_chars!(input, '5', '1'), - scan_chars!(input, '5', '0'), - scan_chars!(input, '5'), - scan_chars!(input, '4', '9'), - scan_chars!(input, '4', '7'), - scan_chars!(input, '4', '6'), - scan_chars!(input, '4', '5'), - scan_chars!(input, '4', '4'), - scan_chars!(input, '4', '3'), - scan_chars!(input, '4', '2'), - scan_chars!(input, '4', '1'), - scan_chars!(input, '4'), - scan_chars!(input, '3', '9'), - scan_chars!(input, '3', '8'), - scan_chars!(input, '3', '7'), - scan_chars!(input, '3', '6'), - scan_chars!(input, '3', '5'), - scan_chars!(input, '3', '4'), - scan_chars!(input, '3', '3'), - scan_chars!(input, '3', '1'), - scan_chars!(input, '3', '0'), - scan_chars!(input, '3'), - scan_chars!(input, '2', '9'), - scan_chars!(input, '2', '8'), - scan_chars!(input, '2', '7'), - scan_chars!(input, '2', '6'), - scan_chars!(input, '2', '5'), - scan_chars!(input, '2', '3'), - scan_chars!(input, '2', '2'), - scan_chars!(input, '2', '1'), - scan_chars!(input, '2', '0'), - scan_chars!(input, '2'), - scan_chars!(input, '1', '9'), - scan_chars!(input, '1', '8'), - scan_chars!(input, '1', '7'), - scan_chars!(input, '1', '5'), - scan_chars!(input, '1', '4'), - scan_chars!(input, '1', '3'), - scan_chars!(input, '1', '2'), - scan_chars!(input, '1', '1'), - scan_chars!(input, '1', '0'), - scan_chars!(input, '1'), - scan_chars!(input, '0') - ) - ) { - if self.version_is_at_least_0_4_14 { - KeywordScan::Reserved(TerminalKind::FixedKeyword) - } else { - KeywordScan::Present(TerminalKind::FixedKeyword) - } - } else { - KeywordScan::Absent - } - ) + TerminalKind::Colon, + ), + )?; + seq.elem_labeled(EdgeLabel::Value, self.expression(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::NamedArgument) } - #[inline] - fn int_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( + #[allow(unused_assignments, unused_parens)] + fn named_argument_group(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.named_arguments(input) + .with_label(EdgeLabel::Arguments) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::NamedArgumentGroup) + } + + #[allow(unused_assignments, unused_parens)] + fn named_arguments(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( input, - ident, - if scan_sequence!( - scan_chars!(input, 'i', 'n', 't'), - scan_optional!( + self, + |input| self.named_argument(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + )) + .with_kind(NonterminalKind::NamedArguments) + } + + #[allow(unused_assignments, unused_parens)] + fn named_arguments_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( input, - scan_choice!( + TerminalKind::OpenParen, + ), + )?; + seq.elem( + OptionalHelper::transform(self.named_argument_group(input)) + .with_label(EdgeLabel::Arguments) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '5', '6'), - scan_chars!(input, '2', '4', '8'), - scan_chars!(input, '2', '4', '0'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3', '2'), - scan_chars!(input, '2', '2', '4'), - scan_chars!(input, '2', '1', '6'), - scan_chars!(input, '2', '0', '8'), - scan_chars!(input, '2', '0', '0'), - scan_chars!(input, '1', '9', '2'), - scan_chars!(input, '1', '8', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') - ) - ) - ) { - KeywordScan::Reserved(TerminalKind::IntKeyword) - } else { - KeywordScan::Absent - } - ) + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::NamedArgumentsDeclaration) + } + + #[allow(unused_assignments, unused_parens)] + fn named_import(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Asterisk, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Asterisk, + ), + )?; + seq.elem_labeled(EdgeLabel::Alias, self.import_alias(input))?; + seq.elem_labeled( + EdgeLabel::FromKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::FromKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Path, self.string_literal(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::NamedImport) + } + + #[allow(unused_assignments, unused_parens)] + fn new_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::NewKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::NewKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::NewExpression) } - #[inline] - fn ufixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( - input, - ident, - if scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') { - KeywordScan::Reserved(TerminalKind::UfixedKeyword) - } else { - KeywordScan::Absent - }, - if scan_sequence!( - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + #[allow(unused_assignments, unused_parens)] + fn number_unit(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::WeiKeyword, + ); + choice.consider(input, result)?; + if self.version_is_at_least_0_6_11 { + let result = self.parse_terminal_with_trivia::( input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') - ), - scan_chars!(input, 'x'), - scan_choice!( + TerminalKind::GweiKeyword, + ); + choice.consider(input, result)?; + } + if !self.version_is_at_least_0_7_0 { + let result = self.parse_terminal_with_trivia::( input, - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '1', '6') - ) - ) { - KeywordScan::Reserved(TerminalKind::UfixedKeyword) - } else { - KeywordScan::Absent - }, - if scan_sequence!( - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + TerminalKind::SzaboKeyword, + ); + choice.consider(input, result)?; + } + if !self.version_is_at_least_0_7_0 { + let result = self.parse_terminal_with_trivia::( input, - scan_chars!(input, '2', '4', '8', 'x', '8'), - scan_chars!(input, '2', '4', '0', 'x', '8'), - scan_chars!(input, '2', '4', '0', 'x', '1', '6'), - scan_chars!(input, '2', '3', '2', 'x', '8'), - scan_chars!(input, '2', '3', '2', 'x', '2', '4'), - scan_chars!(input, '2', '3', '2', 'x', '1', '6'), - scan_chars!(input, '2', '2', '4', 'x', '8'), - scan_chars!(input, '2', '2', '4', 'x', '3', '2'), - scan_chars!(input, '2', '2', '4', 'x', '2', '4'), - scan_chars!(input, '2', '2', '4', 'x', '1', '6'), - scan_chars!(input, '2', '1', '6', 'x', '8'), - scan_chars!(input, '2', '1', '6', 'x', '4', '0'), - scan_chars!(input, '2', '1', '6', 'x', '3', '2'), - scan_chars!(input, '2', '1', '6', 'x', '2', '4'), - scan_chars!(input, '2', '1', '6', 'x', '1', '6'), - scan_chars!(input, '2', '0', '8', 'x', '8'), - scan_chars!(input, '2', '0', '8', 'x', '4', '8'), - scan_chars!(input, '2', '0', '8', 'x', '4', '0'), - scan_chars!(input, '2', '0', '8', 'x', '3', '2'), - scan_chars!(input, '2', '0', '8', 'x', '2', '4'), - scan_chars!(input, '2', '0', '8', 'x', '1', '6'), - scan_chars!(input, '2', '0', '0', 'x', '8'), - scan_chars!(input, '2', '0', '0', 'x', '5', '6'), - scan_chars!(input, '2', '0', '0', 'x', '4', '8'), - scan_chars!(input, '2', '0', '0', 'x', '4', '0'), - scan_chars!(input, '2', '0', '0', 'x', '3', '2'), - scan_chars!(input, '2', '0', '0', 'x', '2', '4'), - scan_chars!(input, '2', '0', '0', 'x', '1', '6'), - scan_chars!(input, '1', '9', '2', 'x', '8'), - scan_chars!(input, '1', '9', '2', 'x', '6', '4'), - scan_chars!(input, '1', '9', '2', 'x', '5', '6'), - scan_chars!(input, '1', '9', '2', 'x', '4', '8'), - scan_chars!(input, '1', '9', '2', 'x', '4', '0'), - scan_chars!(input, '1', '9', '2', 'x', '3', '2'), - scan_chars!(input, '1', '9', '2', 'x', '2', '4'), - scan_chars!(input, '1', '9', '2', 'x', '1', '6'), - scan_chars!(input, '1', '8', '4', 'x', '8'), - scan_chars!(input, '1', '8', '4', 'x', '7', '2'), - scan_chars!(input, '1', '8', '4', 'x', '6', '4'), - scan_chars!(input, '1', '8', '4', 'x', '5', '6'), - scan_chars!(input, '1', '8', '4', 'x', '4', '8'), - scan_chars!(input, '1', '8', '4', 'x', '4', '0'), - scan_chars!(input, '1', '8', '4', 'x', '3', '2'), - scan_chars!(input, '1', '8', '4', 'x', '2', '4'), - scan_chars!(input, '1', '8', '4', 'x', '1', '6') - ) - ) { - KeywordScan::Reserved(TerminalKind::UfixedKeyword) - } else { - KeywordScan::Absent - }, - if scan_sequence!( - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + TerminalKind::FinneyKeyword, + ); + choice.consider(input, result)?; + } + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::EtherKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::SecondsKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::MinutesKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::HoursKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::DaysKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::WeeksKeyword, + ); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( input, - scan_chars!(input, '2', '5', '6', 'x', '8', '0'), - scan_chars!(input, '2', '5', '6', 'x', '8'), - scan_chars!(input, '2', '5', '6', 'x', '7', '2'), - scan_chars!(input, '2', '5', '6', 'x', '6', '4'), - scan_chars!(input, '2', '5', '6', 'x', '5', '6'), - scan_chars!(input, '2', '5', '6', 'x', '4', '8'), - scan_chars!(input, '2', '5', '6', 'x', '4', '0'), - scan_chars!(input, '2', '5', '6', 'x', '3', '2'), - scan_chars!(input, '2', '5', '6', 'x', '2', '4'), - scan_chars!(input, '2', '5', '6', 'x', '1', '6'), - scan_chars!(input, '2', '4', '8', 'x', '8', '0'), - scan_chars!(input, '2', '4', '8', 'x', '7', '2'), - scan_chars!(input, '2', '4', '8', 'x', '6', '4'), - scan_chars!(input, '2', '4', '8', 'x', '5', '6'), - scan_chars!(input, '2', '4', '8', 'x', '4', '8'), - scan_chars!(input, '2', '4', '8', 'x', '4', '0'), - scan_chars!(input, '2', '4', '8', 'x', '3', '2'), - scan_chars!(input, '2', '4', '8', 'x', '2', '4'), - scan_chars!(input, '2', '4', '8', 'x', '1', '6'), - scan_chars!(input, '2', '4', '0', 'x', '8', '0'), - scan_chars!(input, '2', '4', '0', 'x', '7', '2'), - scan_chars!(input, '2', '4', '0', 'x', '6', '4'), - scan_chars!(input, '2', '4', '0', 'x', '5', '6'), - scan_chars!(input, '2', '4', '0', 'x', '4', '8'), - scan_chars!(input, '2', '4', '0', 'x', '4', '0'), - scan_chars!(input, '2', '4', '0', 'x', '3', '2'), - scan_chars!(input, '2', '4', '0', 'x', '2', '4'), - scan_chars!(input, '2', '3', '2', 'x', '8', '0'), - scan_chars!(input, '2', '3', '2', 'x', '7', '2'), - scan_chars!(input, '2', '3', '2', 'x', '6', '4'), - scan_chars!(input, '2', '3', '2', 'x', '5', '6'), - scan_chars!(input, '2', '3', '2', 'x', '4', '8'), - scan_chars!(input, '2', '3', '2', 'x', '4', '0'), - scan_chars!(input, '2', '3', '2', 'x', '3', '2'), - scan_chars!(input, '2', '2', '4', 'x', '8', '0'), - scan_chars!(input, '2', '2', '4', 'x', '7', '2'), - scan_chars!(input, '2', '2', '4', 'x', '6', '4'), - scan_chars!(input, '2', '2', '4', 'x', '5', '6'), - scan_chars!(input, '2', '2', '4', 'x', '4', '8'), - scan_chars!(input, '2', '2', '4', 'x', '4', '0'), - scan_chars!(input, '2', '1', '6', 'x', '8', '0'), - scan_chars!(input, '2', '1', '6', 'x', '7', '2'), - scan_chars!(input, '2', '1', '6', 'x', '6', '4'), - scan_chars!(input, '2', '1', '6', 'x', '5', '6'), - scan_chars!(input, '2', '1', '6', 'x', '4', '8'), - scan_chars!(input, '2', '0', '8', 'x', '8', '0'), - scan_chars!(input, '2', '0', '8', 'x', '7', '2'), - scan_chars!(input, '2', '0', '8', 'x', '6', '4'), - scan_chars!(input, '2', '0', '8', 'x', '5', '6'), - scan_chars!(input, '2', '0', '0', 'x', '8', '0'), - scan_chars!(input, '2', '0', '0', 'x', '7', '2'), - scan_chars!(input, '2', '0', '0', 'x', '6', '4'), - scan_chars!(input, '1', '9', '2', 'x', '8', '0'), - scan_chars!(input, '1', '9', '2', 'x', '7', '2'), - scan_chars!(input, '1', '8', '4', 'x', '8', '0') - ) - ) { - if self.version_is_at_least_0_4_14 { - KeywordScan::Reserved(TerminalKind::UfixedKeyword) - } else { - KeywordScan::Present(TerminalKind::UfixedKeyword) + TerminalKind::YearsKeyword, + ); + choice.consider(input, result)?; + } + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::NumberUnit) + } + + #[allow(unused_assignments, unused_parens)] + fn or_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::OrExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) } - } else { - KeywordScan::Absent + _ => ParserResult::default(), }, - if scan_sequence!( - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - scan_choice!( - input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '5', '6'), - scan_chars!(input, '2', '4', '8'), - scan_chars!(input, '2', '4', '0'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3', '2'), - scan_chars!(input, '2', '2', '4'), - scan_chars!(input, '2', '1', '6'), - scan_chars!(input, '2', '0', '8'), - scan_chars!(input, '2', '0', '0'), - scan_chars!(input, '1', '9', '2'), - scan_chars!(input, '1', '8', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn override_paths(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| self.identifier_path(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + ) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::OverridePaths) + } + + #[allow(unused_assignments, unused_parens)] + fn override_paths_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.override_paths(input) + .with_label(EdgeLabel::Paths) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::OverridePathsDeclaration) + } + + #[allow(unused_assignments, unused_parens)] + fn override_specifier(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::OverrideKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OverrideKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Overridden, + OptionalHelper::transform(self.override_paths_declaration(input)), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::OverrideSpecifier) + } + + #[allow(unused_assignments, unused_parens)] + fn parameter(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + seq.elem_labeled( + EdgeLabel::StorageLocation, + OptionalHelper::transform(self.storage_location(input)), + )?; + seq.elem_labeled( + EdgeLabel::Name, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), ), - scan_chars!(input, 'x'), - scan_choice!( + )?; + seq.finish() + }) + .with_kind(NonterminalKind::Parameter) + } + + #[allow(unused_assignments, unused_parens)] + fn parameters(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| self.parameter(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + )) + .with_kind(NonterminalKind::Parameters) + } + + #[allow(unused_assignments, unused_parens)] + fn parameters_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '9'), - scan_chars!(input, '7', '9'), - scan_chars!(input, '7', '8'), - scan_chars!(input, '7', '7'), - scan_chars!(input, '7', '6'), - scan_chars!(input, '7', '5'), - scan_chars!(input, '7', '4'), - scan_chars!(input, '7', '3'), - scan_chars!(input, '7', '1'), - scan_chars!(input, '7', '0'), - scan_chars!(input, '7'), - scan_chars!(input, '6', '9'), - scan_chars!(input, '6', '8'), - scan_chars!(input, '6', '7'), - scan_chars!(input, '6', '6'), - scan_chars!(input, '6', '5'), - scan_chars!(input, '6', '3'), - scan_chars!(input, '6', '2'), - scan_chars!(input, '6', '1'), - scan_chars!(input, '6', '0'), - scan_chars!(input, '6'), - scan_chars!(input, '5', '9'), - scan_chars!(input, '5', '8'), - scan_chars!(input, '5', '7'), - scan_chars!(input, '5', '5'), - scan_chars!(input, '5', '4'), - scan_chars!(input, '5', '3'), - scan_chars!(input, '5', '2'), - scan_chars!(input, '5', '1'), - scan_chars!(input, '5', '0'), - scan_chars!(input, '5'), - scan_chars!(input, '4', '9'), - scan_chars!(input, '4', '7'), - scan_chars!(input, '4', '6'), - scan_chars!(input, '4', '5'), - scan_chars!(input, '4', '4'), - scan_chars!(input, '4', '3'), - scan_chars!(input, '4', '2'), - scan_chars!(input, '4', '1'), - scan_chars!(input, '4'), - scan_chars!(input, '3', '9'), - scan_chars!(input, '3', '8'), - scan_chars!(input, '3', '7'), - scan_chars!(input, '3', '6'), - scan_chars!(input, '3', '5'), - scan_chars!(input, '3', '4'), - scan_chars!(input, '3', '3'), - scan_chars!(input, '3', '1'), - scan_chars!(input, '3', '0'), - scan_chars!(input, '3'), - scan_chars!(input, '2', '9'), - scan_chars!(input, '2', '8'), - scan_chars!(input, '2', '7'), - scan_chars!(input, '2', '6'), - scan_chars!(input, '2', '5'), - scan_chars!(input, '2', '3'), - scan_chars!(input, '2', '2'), - scan_chars!(input, '2', '1'), - scan_chars!(input, '2', '0'), - scan_chars!(input, '2'), - scan_chars!(input, '1', '9'), - scan_chars!(input, '1', '8'), - scan_chars!(input, '1', '7'), - scan_chars!(input, '1', '5'), - scan_chars!(input, '1', '4'), - scan_chars!(input, '1', '3'), - scan_chars!(input, '1', '2'), - scan_chars!(input, '1', '1'), - scan_chars!(input, '1', '0'), - scan_chars!(input, '1'), - scan_chars!(input, '0') - ) - ) { - if self.version_is_at_least_0_4_14 { - KeywordScan::Reserved(TerminalKind::UfixedKeyword) - } else { - KeywordScan::Present(TerminalKind::UfixedKeyword) - } - } else { - KeywordScan::Absent - } - ) + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.parameters(input) + .with_label(EdgeLabel::Parameters) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::ParametersDeclaration) } - #[inline] - fn uint_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( + #[allow(unused_assignments, unused_parens)] + fn path_import(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::Path, self.string_literal(input))?; + seq.elem_labeled( + EdgeLabel::Alias, + OptionalHelper::transform(self.import_alias(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::PathImport) + } + + #[allow(unused_assignments, unused_parens)] + fn positional_arguments(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Default>( input, - ident, - if scan_sequence!( - scan_chars!(input, 'u', 'i', 'n', 't'), - scan_optional!( + self, + |input| self.expression(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + )) + .with_kind(NonterminalKind::PositionalArguments) + } + + #[allow(unused_assignments, unused_parens)] + fn positional_arguments_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( input, - scan_choice!( + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.positional_arguments(input) + .with_label(EdgeLabel::Arguments) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '5', '6'), - scan_chars!(input, '2', '4', '8'), - scan_chars!(input, '2', '4', '0'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3', '2'), - scan_chars!(input, '2', '2', '4'), - scan_chars!(input, '2', '1', '6'), - scan_chars!(input, '2', '0', '8'), - scan_chars!(input, '2', '0', '0'), - scan_chars!(input, '1', '9', '2'), - scan_chars!(input, '1', '8', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') - ) - ) - ) { - KeywordScan::Reserved(TerminalKind::UintKeyword) - } else { - KeywordScan::Absent - } - ) + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::PositionalArgumentsDeclaration) } - #[inline] - fn yul_bytes_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( - input, - ident, - if !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'b', 'y', 't', 'e', 's'), - scan_optional!( - input, - scan_choice!( + #[allow(unused_assignments, unused_parens)] + fn postfix_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::PostfixExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn pragma(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.abicoder_pragma(input); + choice.consider(input, result)?; + let result = self.experimental_pragma(input); + choice.consider(input, result)?; + let result = self.version_pragma(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::Pragma) + } + + #[allow(unused_assignments, unused_parens)] + fn pragma_directive(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::PragmaKeyword, + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '9'), - scan_chars!(input, '8'), - scan_chars!(input, '7'), - scan_chars!(input, '6'), - scan_chars!(input, '5'), - scan_chars!(input, '4'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '3', '1'), - scan_chars!(input, '3', '0'), - scan_chars!(input, '3'), - scan_chars!(input, '2', '9'), - scan_chars!(input, '2', '8'), - scan_chars!(input, '2', '7'), - scan_chars!(input, '2', '6'), - scan_chars!(input, '2', '5'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3'), - scan_chars!(input, '2', '2'), - scan_chars!(input, '2', '1'), - scan_chars!(input, '2', '0'), - scan_chars!(input, '2'), - scan_chars!(input, '1', '9'), - scan_chars!(input, '1', '8'), - scan_chars!(input, '1', '7'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5'), - scan_chars!(input, '1', '4'), - scan_chars!(input, '1', '3'), - scan_chars!(input, '1', '2'), - scan_chars!(input, '1', '1'), - scan_chars!(input, '1', '0'), - scan_chars!(input, '1') - ) - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulBytesKeyword) - } else { - KeywordScan::Absent - } - ) + TerminalKind::PragmaKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Pragma, self.pragma(input))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Pragma>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::PragmaDirective) + } + + #[allow(unused_assignments, unused_parens)] + fn prefix_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::PrefixExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } } - #[inline] - fn yul_fixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( - input, - ident, - if !self.version_is_at_least_0_7_1 && scan_chars!(input, 'f', 'i', 'x', 'e', 'd') { - KeywordScan::Reserved(TerminalKind::YulFixedKeyword) - } else { - KeywordScan::Absent - }, - if !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + #[allow(unused_assignments, unused_parens)] + fn receive_function_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.modifier_invocation(input); + choice.consider(input, result)?; + let result = self.override_specifier(input); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ExternalKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PayableKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::VirtualKeyword, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ReceiveFunctionAttribute) + } + + #[allow(unused_assignments, unused_parens)] + fn receive_function_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + ZeroOrMoreHelper::run(input, |input| { + self.receive_function_attribute(input) + .with_label(EdgeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ReceiveFunctionAttributes) + } + + #[allow(unused_assignments, unused_parens)] + fn receive_function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ReceiveKeyword, + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') + TerminalKind::ReceiveKeyword, ), - scan_chars!(input, 'x'), - scan_choice!( - input, - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '1', '6') - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulFixedKeyword) - } else { - KeywordScan::Absent - }, - if !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( - input, - scan_chars!(input, '2', '4', '8', 'x', '8'), - scan_chars!(input, '2', '4', '0', 'x', '8'), - scan_chars!(input, '2', '4', '0', 'x', '1', '6'), - scan_chars!(input, '2', '3', '2', 'x', '8'), - scan_chars!(input, '2', '3', '2', 'x', '2', '4'), - scan_chars!(input, '2', '3', '2', 'x', '1', '6'), - scan_chars!(input, '2', '2', '4', 'x', '8'), - scan_chars!(input, '2', '2', '4', 'x', '3', '2'), - scan_chars!(input, '2', '2', '4', 'x', '2', '4'), - scan_chars!(input, '2', '2', '4', 'x', '1', '6'), - scan_chars!(input, '2', '1', '6', 'x', '8'), - scan_chars!(input, '2', '1', '6', 'x', '4', '0'), - scan_chars!(input, '2', '1', '6', 'x', '3', '2'), - scan_chars!(input, '2', '1', '6', 'x', '2', '4'), - scan_chars!(input, '2', '1', '6', 'x', '1', '6'), - scan_chars!(input, '2', '0', '8', 'x', '8'), - scan_chars!(input, '2', '0', '8', 'x', '4', '8'), - scan_chars!(input, '2', '0', '8', 'x', '4', '0'), - scan_chars!(input, '2', '0', '8', 'x', '3', '2'), - scan_chars!(input, '2', '0', '8', 'x', '2', '4'), - scan_chars!(input, '2', '0', '8', 'x', '1', '6'), - scan_chars!(input, '2', '0', '0', 'x', '8'), - scan_chars!(input, '2', '0', '0', 'x', '5', '6'), - scan_chars!(input, '2', '0', '0', 'x', '4', '8'), - scan_chars!(input, '2', '0', '0', 'x', '4', '0'), - scan_chars!(input, '2', '0', '0', 'x', '3', '2'), - scan_chars!(input, '2', '0', '0', 'x', '2', '4'), - scan_chars!(input, '2', '0', '0', 'x', '1', '6'), - scan_chars!(input, '1', '9', '2', 'x', '8'), - scan_chars!(input, '1', '9', '2', 'x', '6', '4'), - scan_chars!(input, '1', '9', '2', 'x', '5', '6'), - scan_chars!(input, '1', '9', '2', 'x', '4', '8'), - scan_chars!(input, '1', '9', '2', 'x', '4', '0'), - scan_chars!(input, '1', '9', '2', 'x', '3', '2'), - scan_chars!(input, '1', '9', '2', 'x', '2', '4'), - scan_chars!(input, '1', '9', '2', 'x', '1', '6'), - scan_chars!(input, '1', '8', '4', 'x', '8'), - scan_chars!(input, '1', '8', '4', 'x', '7', '2'), - scan_chars!(input, '1', '8', '4', 'x', '6', '4'), - scan_chars!(input, '1', '8', '4', 'x', '5', '6'), - scan_chars!(input, '1', '8', '4', 'x', '4', '8'), - scan_chars!(input, '1', '8', '4', 'x', '4', '0'), - scan_chars!(input, '1', '8', '4', 'x', '3', '2'), - scan_chars!(input, '1', '8', '4', 'x', '2', '4'), - scan_chars!(input, '1', '8', '4', 'x', '1', '6') - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulFixedKeyword) - } else { - KeywordScan::Absent - }, - if self.version_is_at_least_0_4_14 - && !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( - input, - scan_chars!(input, '2', '5', '6', 'x', '8', '0'), - scan_chars!(input, '2', '5', '6', 'x', '8'), - scan_chars!(input, '2', '5', '6', 'x', '7', '2'), - scan_chars!(input, '2', '5', '6', 'x', '6', '4'), - scan_chars!(input, '2', '5', '6', 'x', '5', '6'), - scan_chars!(input, '2', '5', '6', 'x', '4', '8'), - scan_chars!(input, '2', '5', '6', 'x', '4', '0'), - scan_chars!(input, '2', '5', '6', 'x', '3', '2'), - scan_chars!(input, '2', '5', '6', 'x', '2', '4'), - scan_chars!(input, '2', '5', '6', 'x', '1', '6'), - scan_chars!(input, '2', '4', '8', 'x', '8', '0'), - scan_chars!(input, '2', '4', '8', 'x', '7', '2'), - scan_chars!(input, '2', '4', '8', 'x', '6', '4'), - scan_chars!(input, '2', '4', '8', 'x', '5', '6'), - scan_chars!(input, '2', '4', '8', 'x', '4', '8'), - scan_chars!(input, '2', '4', '8', 'x', '4', '0'), - scan_chars!(input, '2', '4', '8', 'x', '3', '2'), - scan_chars!(input, '2', '4', '8', 'x', '2', '4'), - scan_chars!(input, '2', '4', '8', 'x', '1', '6'), - scan_chars!(input, '2', '4', '0', 'x', '8', '0'), - scan_chars!(input, '2', '4', '0', 'x', '7', '2'), - scan_chars!(input, '2', '4', '0', 'x', '6', '4'), - scan_chars!(input, '2', '4', '0', 'x', '5', '6'), - scan_chars!(input, '2', '4', '0', 'x', '4', '8'), - scan_chars!(input, '2', '4', '0', 'x', '4', '0'), - scan_chars!(input, '2', '4', '0', 'x', '3', '2'), - scan_chars!(input, '2', '4', '0', 'x', '2', '4'), - scan_chars!(input, '2', '3', '2', 'x', '8', '0'), - scan_chars!(input, '2', '3', '2', 'x', '7', '2'), - scan_chars!(input, '2', '3', '2', 'x', '6', '4'), - scan_chars!(input, '2', '3', '2', 'x', '5', '6'), - scan_chars!(input, '2', '3', '2', 'x', '4', '8'), - scan_chars!(input, '2', '3', '2', 'x', '4', '0'), - scan_chars!(input, '2', '3', '2', 'x', '3', '2'), - scan_chars!(input, '2', '2', '4', 'x', '8', '0'), - scan_chars!(input, '2', '2', '4', 'x', '7', '2'), - scan_chars!(input, '2', '2', '4', 'x', '6', '4'), - scan_chars!(input, '2', '2', '4', 'x', '5', '6'), - scan_chars!(input, '2', '2', '4', 'x', '4', '8'), - scan_chars!(input, '2', '2', '4', 'x', '4', '0'), - scan_chars!(input, '2', '1', '6', 'x', '8', '0'), - scan_chars!(input, '2', '1', '6', 'x', '7', '2'), - scan_chars!(input, '2', '1', '6', 'x', '6', '4'), - scan_chars!(input, '2', '1', '6', 'x', '5', '6'), - scan_chars!(input, '2', '1', '6', 'x', '4', '8'), - scan_chars!(input, '2', '0', '8', 'x', '8', '0'), - scan_chars!(input, '2', '0', '8', 'x', '7', '2'), - scan_chars!(input, '2', '0', '8', 'x', '6', '4'), - scan_chars!(input, '2', '0', '8', 'x', '5', '6'), - scan_chars!(input, '2', '0', '0', 'x', '8', '0'), - scan_chars!(input, '2', '0', '0', 'x', '7', '2'), - scan_chars!(input, '2', '0', '0', 'x', '6', '4'), - scan_chars!(input, '1', '9', '2', 'x', '8', '0'), - scan_chars!(input, '1', '9', '2', 'x', '7', '2'), - scan_chars!(input, '1', '8', '4', 'x', '8', '0') - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulFixedKeyword) - } else { - KeywordScan::Absent - }, - if self.version_is_at_least_0_4_14 - && !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + )?; + seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; + seq.elem_labeled( + EdgeLabel::Attributes, + self.receive_function_attributes(input), + )?; + seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ReceiveFunctionDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn return_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ReturnKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ReturnKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Expression, + OptionalHelper::transform(self.expression(input)), + )?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::ReturnStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn returns_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ReturnsKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ReturnsKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Variables, self.parameters_declaration(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::ReturnsDeclaration) + } + + #[allow(unused_assignments, unused_parens)] + fn revert_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_4 { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::RevertKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::RevertKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Error, + OptionalHelper::transform(self.identifier_path(input)), + )?; + seq.elem_labeled(EdgeLabel::Arguments, self.arguments_declaration(input))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '5', '6'), - scan_chars!(input, '2', '4', '8'), - scan_chars!(input, '2', '4', '0'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3', '2'), - scan_chars!(input, '2', '2', '4'), - scan_chars!(input, '2', '1', '6'), - scan_chars!(input, '2', '0', '8'), - scan_chars!(input, '2', '0', '0'), - scan_chars!(input, '1', '9', '2'), - scan_chars!(input, '1', '8', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), ), - scan_chars!(input, 'x'), - scan_choice!( + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '9'), - scan_chars!(input, '7', '9'), - scan_chars!(input, '7', '8'), - scan_chars!(input, '7', '7'), - scan_chars!(input, '7', '6'), - scan_chars!(input, '7', '5'), - scan_chars!(input, '7', '4'), - scan_chars!(input, '7', '3'), - scan_chars!(input, '7', '1'), - scan_chars!(input, '7', '0'), - scan_chars!(input, '7'), - scan_chars!(input, '6', '9'), - scan_chars!(input, '6', '8'), - scan_chars!(input, '6', '7'), - scan_chars!(input, '6', '6'), - scan_chars!(input, '6', '5'), - scan_chars!(input, '6', '3'), - scan_chars!(input, '6', '2'), - scan_chars!(input, '6', '1'), - scan_chars!(input, '6', '0'), - scan_chars!(input, '6'), - scan_chars!(input, '5', '9'), - scan_chars!(input, '5', '8'), - scan_chars!(input, '5', '7'), - scan_chars!(input, '5', '5'), - scan_chars!(input, '5', '4'), - scan_chars!(input, '5', '3'), - scan_chars!(input, '5', '2'), - scan_chars!(input, '5', '1'), - scan_chars!(input, '5', '0'), - scan_chars!(input, '5'), - scan_chars!(input, '4', '9'), - scan_chars!(input, '4', '7'), - scan_chars!(input, '4', '6'), - scan_chars!(input, '4', '5'), - scan_chars!(input, '4', '4'), - scan_chars!(input, '4', '3'), - scan_chars!(input, '4', '2'), - scan_chars!(input, '4', '1'), - scan_chars!(input, '4'), - scan_chars!(input, '3', '9'), - scan_chars!(input, '3', '8'), - scan_chars!(input, '3', '7'), - scan_chars!(input, '3', '6'), - scan_chars!(input, '3', '5'), - scan_chars!(input, '3', '4'), - scan_chars!(input, '3', '3'), - scan_chars!(input, '3', '1'), - scan_chars!(input, '3', '0'), - scan_chars!(input, '3'), - scan_chars!(input, '2', '9'), - scan_chars!(input, '2', '8'), - scan_chars!(input, '2', '7'), - scan_chars!(input, '2', '6'), - scan_chars!(input, '2', '5'), - scan_chars!(input, '2', '3'), - scan_chars!(input, '2', '2'), - scan_chars!(input, '2', '1'), - scan_chars!(input, '2', '0'), - scan_chars!(input, '2'), - scan_chars!(input, '1', '9'), - scan_chars!(input, '1', '8'), - scan_chars!(input, '1', '7'), - scan_chars!(input, '1', '5'), - scan_chars!(input, '1', '4'), - scan_chars!(input, '1', '3'), - scan_chars!(input, '1', '2'), - scan_chars!(input, '1', '1'), - scan_chars!(input, '1', '0'), - scan_chars!(input, '1'), - scan_chars!(input, '0') - ) + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::RevertStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn shift_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::Expression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::ShiftExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn simple_version_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Pragma>( + input, + self, + |input| { + self.parse_terminal_with_trivia::( + input, + TerminalKind::VersionSpecifier, ) - { - KeywordScan::Reserved(TerminalKind::YulFixedKeyword) - } else { - KeywordScan::Absent + .with_label(EdgeLabel::Item) + }, + TerminalKind::Period, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::SimpleVersionLiteral) + } + + #[allow(unused_assignments, unused_parens)] + fn source_unit(&self, input: &mut ParserContext<'_>) -> ParserResult { + self.source_unit_members(input) + .with_label(EdgeLabel::Members) + .with_kind(NonterminalKind::SourceUnit) + } + + #[allow(unused_assignments, unused_parens)] + fn source_unit_member(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.pragma_directive(input); + choice.consider(input, result)?; + let result = self.import_directive(input); + choice.consider(input, result)?; + let result = self.contract_definition(input); + choice.consider(input, result)?; + let result = self.interface_definition(input); + choice.consider(input, result)?; + let result = self.library_definition(input); + choice.consider(input, result)?; + if self.version_is_at_least_0_6_0 { + let result = self.struct_definition(input); + choice.consider(input, result)?; } - ) + if self.version_is_at_least_0_6_0 { + let result = self.enum_definition(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_7_1 { + let result = self.function_definition(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_8_4 { + let result = self.error_definition(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_8_8 { + let result = self.user_defined_value_type_definition(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_8_13 { + let result = self.using_directive(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_8_22 { + let result = self.event_definition(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_7_4 { + let result = self.constant_definition(input); + choice.consider(input, result)?; + } + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::SourceUnitMember) + } + + #[allow(unused_assignments, unused_parens)] + fn source_unit_members(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.source_unit_member(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::SourceUnitMembers) + } + + #[allow(unused_assignments, unused_parens)] + fn state_variable_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + if self.version_is_at_least_0_6_0 { + let result = self.override_specifier(input); + choice.consider(input, result)?; + } + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ConstantKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::InternalKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PrivateKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PublicKeyword, + ); + choice.consider(input, result)?; + if self.version_is_at_least_0_6_5 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ImmutableKeyword, + ); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_8_27 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::TransientKeyword, + ); + choice.consider(input, result)?; + } + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::StateVariableAttribute) + } + + #[allow(unused_assignments, unused_parens)] + fn state_variable_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.state_variable_attribute(input) + .with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::StateVariableAttributes) + } + + #[allow(unused_assignments, unused_parens)] + fn state_variable_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + seq.elem_labeled(EdgeLabel::Attributes, self.state_variable_attributes(input))?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Value, + OptionalHelper::transform(self.state_variable_definition_value(input)), + )?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::StateVariableDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn state_variable_definition_value(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Equal, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Equal, + ), + )?; + seq.elem_labeled(EdgeLabel::Value, self.expression(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::StateVariableDefinitionValue) + } + + #[allow(unused_assignments, unused_parens)] + fn statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.if_statement(input); + choice.consider(input, result)?; + let result = self.for_statement(input); + choice.consider(input, result)?; + let result = self.while_statement(input); + choice.consider(input, result)?; + let result = self.do_while_statement(input); + choice.consider(input, result)?; + let result = self.continue_statement(input); + choice.consider(input, result)?; + let result = self.break_statement(input); + choice.consider(input, result)?; + let result = self.return_statement(input); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.throw_statement(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_4_21 { + let result = self.emit_statement(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_6_0 { + let result = self.try_statement(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_8_4 { + let result = self.revert_statement(input); + choice.consider(input, result)?; + } + let result = self.assembly_statement(input); + choice.consider(input, result)?; + let result = self.block(input); + choice.consider(input, result)?; + if self.version_is_at_least_0_8_0 { + let result = self.unchecked_block(input); + choice.consider(input, result)?; + } + let result = self.tuple_deconstruction_statement(input); + choice.consider(input, result)?; + let result = self.variable_declaration_statement(input); + choice.consider(input, result)?; + let result = self.expression_statement(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::Statement) + } + + #[allow(unused_assignments, unused_parens)] + fn statements(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.statement(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::Statements) + } + + #[allow(unused_assignments, unused_parens)] + fn storage_location(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::MemoryKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::StorageKeyword, + ); + choice.consider(input, result)?; + if self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::CallDataKeyword, + ); + choice.consider(input, result)?; + } + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::StorageLocation) } - #[inline] - fn yul_int_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( - input, - ident, - if !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'i', 'n', 't'), - scan_optional!( - input, - scan_choice!( - input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '5', '6'), - scan_chars!(input, '2', '4', '8'), - scan_chars!(input, '2', '4', '0'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3', '2'), - scan_chars!(input, '2', '2', '4'), - scan_chars!(input, '2', '1', '6'), - scan_chars!(input, '2', '0', '8'), - scan_chars!(input, '2', '0', '0'), - scan_chars!(input, '1', '9', '2'), - scan_chars!(input, '1', '8', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') - ) - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulIntKeyword) - } else { - KeywordScan::Absent + #[allow(unused_assignments, unused_parens)] + fn string_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + if !self.version_is_at_least_0_5_14 { + let result = self.string_literal(input); + choice.consider(input, result)?; } - ) + if self.version_is_at_least_0_5_14 { + let result = self.string_literals(input); + choice.consider(input, result)?; + } + if !self.version_is_at_least_0_5_14 { + let result = self.hex_string_literal(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_5_14 { + let result = self.hex_string_literals(input); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_7_0 { + let result = self.unicode_string_literals(input); + choice.consider(input, result)?; + } + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::StringExpression) } - #[inline] - fn yul_ufixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( - input, - ident, - if !self.version_is_at_least_0_7_1 && scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') { - KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) - } else { - KeywordScan::Absent - }, - if !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + #[allow(unused_assignments, unused_parens)] + fn string_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::SingleQuotedStringLiteral, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::DoubleQuotedStringLiteral, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::StringLiteral) + } + + #[allow(unused_assignments, unused_parens)] + fn string_literals(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_5_14 { + OneOrMoreHelper::run(input, |input| { + self.string_literal(input).with_label(EdgeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::StringLiterals) + } + + #[allow(unused_assignments, unused_parens)] + fn struct_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::StructKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::StructKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') + TerminalKind::OpenBrace, ), - scan_chars!(input, 'x'), - scan_choice!( + )?; + seq.elem( + self.struct_members(input) + .with_label(EdgeLabel::Members) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( input, - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '1', '6') - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) - } else { - KeywordScan::Absent - }, - if !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }))?; + seq.finish() + }) + .with_kind(NonterminalKind::StructDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn struct_member(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::StructMember) + } + + #[allow(unused_assignments, unused_parens)] + fn struct_members(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.struct_member(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::StructMembers) + } + + #[allow(unused_assignments, unused_parens)] + fn throw_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_5_0 { + SequenceHelper::run(|mut seq| { + seq.elem( + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '2', '4', '8', 'x', '8'), - scan_chars!(input, '2', '4', '0', 'x', '8'), - scan_chars!(input, '2', '4', '0', 'x', '1', '6'), - scan_chars!(input, '2', '3', '2', 'x', '8'), - scan_chars!(input, '2', '3', '2', 'x', '2', '4'), - scan_chars!(input, '2', '3', '2', 'x', '1', '6'), - scan_chars!(input, '2', '2', '4', 'x', '8'), - scan_chars!(input, '2', '2', '4', 'x', '3', '2'), - scan_chars!(input, '2', '2', '4', 'x', '2', '4'), - scan_chars!(input, '2', '2', '4', 'x', '1', '6'), - scan_chars!(input, '2', '1', '6', 'x', '8'), - scan_chars!(input, '2', '1', '6', 'x', '4', '0'), - scan_chars!(input, '2', '1', '6', 'x', '3', '2'), - scan_chars!(input, '2', '1', '6', 'x', '2', '4'), - scan_chars!(input, '2', '1', '6', 'x', '1', '6'), - scan_chars!(input, '2', '0', '8', 'x', '8'), - scan_chars!(input, '2', '0', '8', 'x', '4', '8'), - scan_chars!(input, '2', '0', '8', 'x', '4', '0'), - scan_chars!(input, '2', '0', '8', 'x', '3', '2'), - scan_chars!(input, '2', '0', '8', 'x', '2', '4'), - scan_chars!(input, '2', '0', '8', 'x', '1', '6'), - scan_chars!(input, '2', '0', '0', 'x', '8'), - scan_chars!(input, '2', '0', '0', 'x', '5', '6'), - scan_chars!(input, '2', '0', '0', 'x', '4', '8'), - scan_chars!(input, '2', '0', '0', 'x', '4', '0'), - scan_chars!(input, '2', '0', '0', 'x', '3', '2'), - scan_chars!(input, '2', '0', '0', 'x', '2', '4'), - scan_chars!(input, '2', '0', '0', 'x', '1', '6'), - scan_chars!(input, '1', '9', '2', 'x', '8'), - scan_chars!(input, '1', '9', '2', 'x', '6', '4'), - scan_chars!(input, '1', '9', '2', 'x', '5', '6'), - scan_chars!(input, '1', '9', '2', 'x', '4', '8'), - scan_chars!(input, '1', '9', '2', 'x', '4', '0'), - scan_chars!(input, '1', '9', '2', 'x', '3', '2'), - scan_chars!(input, '1', '9', '2', 'x', '2', '4'), - scan_chars!(input, '1', '9', '2', 'x', '1', '6'), - scan_chars!(input, '1', '8', '4', 'x', '8'), - scan_chars!(input, '1', '8', '4', 'x', '7', '2'), - scan_chars!(input, '1', '8', '4', 'x', '6', '4'), - scan_chars!(input, '1', '8', '4', 'x', '5', '6'), - scan_chars!(input, '1', '8', '4', 'x', '4', '8'), - scan_chars!(input, '1', '8', '4', 'x', '4', '0'), - scan_chars!(input, '1', '8', '4', 'x', '3', '2'), - scan_chars!(input, '1', '8', '4', 'x', '2', '4'), - scan_chars!(input, '1', '8', '4', 'x', '1', '6') + TerminalKind::ThrowKeyword, ) - ) - { - KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) - } else { - KeywordScan::Absent - }, - if self.version_is_at_least_0_4_14 - && !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + .with_label(EdgeLabel::ThrowKeyword) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( input, - scan_chars!(input, '2', '5', '6', 'x', '8', '0'), - scan_chars!(input, '2', '5', '6', 'x', '8'), - scan_chars!(input, '2', '5', '6', 'x', '7', '2'), - scan_chars!(input, '2', '5', '6', 'x', '6', '4'), - scan_chars!(input, '2', '5', '6', 'x', '5', '6'), - scan_chars!(input, '2', '5', '6', 'x', '4', '8'), - scan_chars!(input, '2', '5', '6', 'x', '4', '0'), - scan_chars!(input, '2', '5', '6', 'x', '3', '2'), - scan_chars!(input, '2', '5', '6', 'x', '2', '4'), - scan_chars!(input, '2', '5', '6', 'x', '1', '6'), - scan_chars!(input, '2', '4', '8', 'x', '8', '0'), - scan_chars!(input, '2', '4', '8', 'x', '7', '2'), - scan_chars!(input, '2', '4', '8', 'x', '6', '4'), - scan_chars!(input, '2', '4', '8', 'x', '5', '6'), - scan_chars!(input, '2', '4', '8', 'x', '4', '8'), - scan_chars!(input, '2', '4', '8', 'x', '4', '0'), - scan_chars!(input, '2', '4', '8', 'x', '3', '2'), - scan_chars!(input, '2', '4', '8', 'x', '2', '4'), - scan_chars!(input, '2', '4', '8', 'x', '1', '6'), - scan_chars!(input, '2', '4', '0', 'x', '8', '0'), - scan_chars!(input, '2', '4', '0', 'x', '7', '2'), - scan_chars!(input, '2', '4', '0', 'x', '6', '4'), - scan_chars!(input, '2', '4', '0', 'x', '5', '6'), - scan_chars!(input, '2', '4', '0', 'x', '4', '8'), - scan_chars!(input, '2', '4', '0', 'x', '4', '0'), - scan_chars!(input, '2', '4', '0', 'x', '3', '2'), - scan_chars!(input, '2', '4', '0', 'x', '2', '4'), - scan_chars!(input, '2', '3', '2', 'x', '8', '0'), - scan_chars!(input, '2', '3', '2', 'x', '7', '2'), - scan_chars!(input, '2', '3', '2', 'x', '6', '4'), - scan_chars!(input, '2', '3', '2', 'x', '5', '6'), - scan_chars!(input, '2', '3', '2', 'x', '4', '8'), - scan_chars!(input, '2', '3', '2', 'x', '4', '0'), - scan_chars!(input, '2', '3', '2', 'x', '3', '2'), - scan_chars!(input, '2', '2', '4', 'x', '8', '0'), - scan_chars!(input, '2', '2', '4', 'x', '7', '2'), - scan_chars!(input, '2', '2', '4', 'x', '6', '4'), - scan_chars!(input, '2', '2', '4', 'x', '5', '6'), - scan_chars!(input, '2', '2', '4', 'x', '4', '8'), - scan_chars!(input, '2', '2', '4', 'x', '4', '0'), - scan_chars!(input, '2', '1', '6', 'x', '8', '0'), - scan_chars!(input, '2', '1', '6', 'x', '7', '2'), - scan_chars!(input, '2', '1', '6', 'x', '6', '4'), - scan_chars!(input, '2', '1', '6', 'x', '5', '6'), - scan_chars!(input, '2', '1', '6', 'x', '4', '8'), - scan_chars!(input, '2', '0', '8', 'x', '8', '0'), - scan_chars!(input, '2', '0', '8', 'x', '7', '2'), - scan_chars!(input, '2', '0', '8', 'x', '6', '4'), - scan_chars!(input, '2', '0', '8', 'x', '5', '6'), - scan_chars!(input, '2', '0', '0', 'x', '8', '0'), - scan_chars!(input, '2', '0', '0', 'x', '7', '2'), - scan_chars!(input, '2', '0', '0', 'x', '6', '4'), - scan_chars!(input, '1', '9', '2', 'x', '8', '0'), - scan_chars!(input, '1', '9', '2', 'x', '7', '2'), - scan_chars!(input, '1', '8', '4', 'x', '8', '0') - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) - } else { - KeywordScan::Absent + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::ThrowStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn try_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::TryKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::TryKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Expression, self.expression(input))?; + seq.elem_labeled( + EdgeLabel::Returns, + OptionalHelper::transform(self.returns_declaration(input)), + )?; + seq.elem_labeled(EdgeLabel::Body, self.block(input))?; + seq.elem_labeled(EdgeLabel::CatchClauses, self.catch_clauses(input))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::TryStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn tuple_deconstruction_element(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(self.tuple_member(input)) + .with_label(EdgeLabel::Member) + .with_kind(NonterminalKind::TupleDeconstructionElement) + } + + #[allow(unused_assignments, unused_parens)] + fn tuple_deconstruction_elements(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| { + self.tuple_deconstruction_element(input) + .with_label(EdgeLabel::Item) }, - if self.version_is_at_least_0_4_14 - && !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + TerminalKind::Comma, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::TupleDeconstructionElements) + } + + #[allow(unused_assignments, unused_parens)] + fn tuple_deconstruction_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + if !self.version_is_at_least_0_5_0 { + seq.elem_labeled( + EdgeLabel::VarKeyword, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::VarKeyword, + ), + ), + )?; + } + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.tuple_deconstruction_elements(input) + .with_label(EdgeLabel::Elements) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }))?; + seq.elem_labeled( + EdgeLabel::Equal, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Equal, + ), + )?; + seq.elem_labeled(EdgeLabel::Expression, self.expression(input))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::TupleDeconstructionStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn tuple_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.tuple_values(input) + .with_label(EdgeLabel::Items) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '5', '6'), - scan_chars!(input, '2', '4', '8'), - scan_chars!(input, '2', '4', '0'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3', '2'), - scan_chars!(input, '2', '2', '4'), - scan_chars!(input, '2', '1', '6'), - scan_chars!(input, '2', '0', '8'), - scan_chars!(input, '2', '0', '0'), - scan_chars!(input, '1', '9', '2'), - scan_chars!(input, '1', '8', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), ), - scan_chars!(input, 'x'), - scan_choice!( + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::TupleExpression) + } + + #[allow(unused_assignments, unused_parens)] + fn tuple_member(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.typed_tuple_member(input); + choice.consider(input, result)?; + let result = self.untyped_tuple_member(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::TupleMember) + } + + #[allow(unused_assignments, unused_parens)] + fn tuple_value(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(self.expression(input)) + .with_label(EdgeLabel::Expression) + .with_kind(NonterminalKind::TupleValue) + } + + #[allow(unused_assignments, unused_parens)] + fn tuple_values(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| self.tuple_value(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::TupleValues) + } + + #[allow(unused_assignments, unused_parens)] + fn type_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_5_3 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::TypeKeyword, + self.parse_terminal_with_trivia::( input, - scan_chars!(input, '9'), - scan_chars!(input, '7', '9'), - scan_chars!(input, '7', '8'), - scan_chars!(input, '7', '7'), - scan_chars!(input, '7', '6'), - scan_chars!(input, '7', '5'), - scan_chars!(input, '7', '4'), - scan_chars!(input, '7', '3'), - scan_chars!(input, '7', '1'), - scan_chars!(input, '7', '0'), - scan_chars!(input, '7'), - scan_chars!(input, '6', '9'), - scan_chars!(input, '6', '8'), - scan_chars!(input, '6', '7'), - scan_chars!(input, '6', '6'), - scan_chars!(input, '6', '5'), - scan_chars!(input, '6', '3'), - scan_chars!(input, '6', '2'), - scan_chars!(input, '6', '1'), - scan_chars!(input, '6', '0'), - scan_chars!(input, '6'), - scan_chars!(input, '5', '9'), - scan_chars!(input, '5', '8'), - scan_chars!(input, '5', '7'), - scan_chars!(input, '5', '5'), - scan_chars!(input, '5', '4'), - scan_chars!(input, '5', '3'), - scan_chars!(input, '5', '2'), - scan_chars!(input, '5', '1'), - scan_chars!(input, '5', '0'), - scan_chars!(input, '5'), - scan_chars!(input, '4', '9'), - scan_chars!(input, '4', '7'), - scan_chars!(input, '4', '6'), - scan_chars!(input, '4', '5'), - scan_chars!(input, '4', '4'), - scan_chars!(input, '4', '3'), - scan_chars!(input, '4', '2'), - scan_chars!(input, '4', '1'), - scan_chars!(input, '4'), - scan_chars!(input, '3', '9'), - scan_chars!(input, '3', '8'), - scan_chars!(input, '3', '7'), - scan_chars!(input, '3', '6'), - scan_chars!(input, '3', '5'), - scan_chars!(input, '3', '4'), - scan_chars!(input, '3', '3'), - scan_chars!(input, '3', '1'), - scan_chars!(input, '3', '0'), - scan_chars!(input, '3'), - scan_chars!(input, '2', '9'), - scan_chars!(input, '2', '8'), - scan_chars!(input, '2', '7'), - scan_chars!(input, '2', '6'), - scan_chars!(input, '2', '5'), - scan_chars!(input, '2', '3'), - scan_chars!(input, '2', '2'), - scan_chars!(input, '2', '1'), - scan_chars!(input, '2', '0'), - scan_chars!(input, '2'), - scan_chars!(input, '1', '9'), - scan_chars!(input, '1', '8'), - scan_chars!(input, '1', '7'), - scan_chars!(input, '1', '5'), - scan_chars!(input, '1', '4'), - scan_chars!(input, '1', '3'), - scan_chars!(input, '1', '2'), - scan_chars!(input, '1', '1'), - scan_chars!(input, '1', '0'), - scan_chars!(input, '1'), - scan_chars!(input, '0') - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) - } else { - KeywordScan::Absent - } + TerminalKind::TypeKeyword, + ), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.type_name(input) + .with_label(EdgeLabel::TypeName) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::TypeExpression) + } + + #[allow(unused_assignments, unused_parens)] + fn type_name(&self, input: &mut ParserContext<'_>) -> ParserResult { + let parse_postfix_array_type_name = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_postfix_operator( + NonterminalKind::ArrayTypeName, + 1u8, + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBracket); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBracket, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBracket, + ), + )?; + seq.elem( + OptionalHelper::transform(self.expression(input)) + .with_label(EdgeLabel::Index) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBracket, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBracket, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBracket, + ), + )?; + seq.finish() + }), + ) + }; + let primary_expression_parser = |input: &mut ParserContext<'_>| { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.function_type(input); + choice.consider(input, result)?; + let result = self.mapping_type(input); + choice.consider(input, result)?; + let result = self.elementary_type(input); + choice.consider(input, result)?; + let result = self.identifier_path(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + }; + let postfix_operator_parser = |input: &mut ParserContext<'_>| { + ChoiceHelper::run(input, |mut choice, input| { + let result = parse_postfix_array_type_name(input); + choice.consider(input, result)?; + choice.finish(input) + }) + }; + let linear_expression_parser = |input: &mut ParserContext<'_>| { + SequenceHelper::run(|mut seq| { + seq.elem(primary_expression_parser(input))?; + seq.elem(ZeroOrMoreHelper::run(input, postfix_operator_parser))?; + seq.finish() + }) + }; + PrecedenceHelper::reduce_precedence_result( + NonterminalKind::TypeName, + linear_expression_parser(input), ) + .with_kind(NonterminalKind::TypeName) } - #[inline] - fn yul_uint_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { - scan_keyword_choice!( - input, - ident, - if !self.version_is_at_least_0_7_1 - && scan_sequence!( - scan_chars!(input, 'u', 'i', 'n', 't'), - scan_optional!( + #[allow(unused_assignments, unused_parens)] + fn typed_tuple_member(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::TypeName, self.type_name(input))?; + seq.elem_labeled( + EdgeLabel::StorageLocation, + OptionalHelper::transform(self.storage_location(input)), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::TypedTupleMember) + } + + #[allow(unused_assignments, unused_parens)] + fn unchecked_block(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::UncheckedKeyword, + self.parse_terminal_with_trivia::( input, - scan_choice!( - input, - scan_chars!(input, '9', '6'), - scan_chars!(input, '8', '8'), - scan_chars!(input, '8', '0'), - scan_chars!(input, '8'), - scan_chars!(input, '7', '2'), - scan_chars!(input, '6', '4'), - scan_chars!(input, '5', '6'), - scan_chars!(input, '4', '8'), - scan_chars!(input, '4', '0'), - scan_chars!(input, '3', '2'), - scan_chars!(input, '2', '5', '6'), - scan_chars!(input, '2', '4', '8'), - scan_chars!(input, '2', '4', '0'), - scan_chars!(input, '2', '4'), - scan_chars!(input, '2', '3', '2'), - scan_chars!(input, '2', '2', '4'), - scan_chars!(input, '2', '1', '6'), - scan_chars!(input, '2', '0', '8'), - scan_chars!(input, '2', '0', '0'), - scan_chars!(input, '1', '9', '2'), - scan_chars!(input, '1', '8', '4'), - scan_chars!(input, '1', '7', '6'), - scan_chars!(input, '1', '6', '8'), - scan_chars!(input, '1', '6', '0'), - scan_chars!(input, '1', '6'), - scan_chars!(input, '1', '5', '2'), - scan_chars!(input, '1', '4', '4'), - scan_chars!(input, '1', '3', '6'), - scan_chars!(input, '1', '2', '8'), - scan_chars!(input, '1', '2', '0'), - scan_chars!(input, '1', '1', '2'), - scan_chars!(input, '1', '0', '4') - ) - ) - ) - { - KeywordScan::Reserved(TerminalKind::YulUintKeyword) - } else { - KeywordScan::Absent - } - ) + TerminalKind::UncheckedKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Block, self.block(input))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UncheckedBlock) + } + + #[allow(unused_assignments, unused_parens)] + fn unicode_string_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_7_0 { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::SingleQuotedUnicodeStringLiteral, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::DoubleQuotedUnicodeStringLiteral, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UnicodeStringLiteral) + } + + #[allow(unused_assignments, unused_parens)] + fn unicode_string_literals(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_7_0 { + OneOrMoreHelper::run(input, |input| { + self.unicode_string_literal(input) + .with_label(EdgeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UnicodeStringLiterals) + } + + #[allow(unused_assignments, unused_parens)] + fn unnamed_function_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_6_0 { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.modifier_invocation(input); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ConstantKeyword, + ); + choice.consider(input, result)?; + } + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ExternalKeyword, + ); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::InternalKeyword, + ); + choice.consider(input, result)?; + } + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PayableKeyword, + ); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PrivateKeyword, + ); + choice.consider(input, result)?; + } + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PublicKeyword, + ); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_4_16 && !self.version_is_at_least_0_6_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::PureKeyword, + ); + choice.consider(input, result)?; + } + if self.version_is_at_least_0_4_16 && !self.version_is_at_least_0_6_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ViewKeyword, + ); + choice.consider(input, result)?; + } + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UnnamedFunctionAttribute) + } + + #[allow(unused_assignments, unused_parens)] + fn unnamed_function_attributes(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_6_0 { + ZeroOrMoreHelper::run(input, |input| { + self.unnamed_function_attribute(input) + .with_label(EdgeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UnnamedFunctionAttributes) } - - pub fn parse(&self, kind: NonterminalKind, input: &str) -> ParseOutput { - match kind { - NonterminalKind::AbicoderPragma => Self::abicoder_pragma.parse(self, input, kind), - NonterminalKind::AdditiveExpression => { - Self::additive_expression.parse(self, input, kind) - } - NonterminalKind::AddressType => Self::address_type.parse(self, input, kind), - NonterminalKind::AndExpression => Self::and_expression.parse(self, input, kind), - NonterminalKind::ArgumentsDeclaration => { - Self::arguments_declaration.parse(self, input, kind) - } - NonterminalKind::ArrayExpression => Self::array_expression.parse(self, input, kind), - NonterminalKind::ArrayTypeName => Self::array_type_name.parse(self, input, kind), - NonterminalKind::ArrayValues => Self::array_values.parse(self, input, kind), - NonterminalKind::AssemblyFlags => Self::assembly_flags.parse(self, input, kind), - NonterminalKind::AssemblyFlagsDeclaration => { - Self::assembly_flags_declaration.parse(self, input, kind) - } - NonterminalKind::AssemblyStatement => Self::assembly_statement.parse(self, input, kind), - NonterminalKind::AssignmentExpression => { - Self::assignment_expression.parse(self, input, kind) - } - NonterminalKind::BitwiseAndExpression => { - Self::bitwise_and_expression.parse(self, input, kind) - } - NonterminalKind::BitwiseOrExpression => { - Self::bitwise_or_expression.parse(self, input, kind) - } - NonterminalKind::BitwiseXorExpression => { - Self::bitwise_xor_expression.parse(self, input, kind) - } - NonterminalKind::Block => Self::block.parse(self, input, kind), - NonterminalKind::BreakStatement => Self::break_statement.parse(self, input, kind), - NonterminalKind::CallOptions => Self::call_options.parse(self, input, kind), - NonterminalKind::CallOptionsExpression => { - Self::call_options_expression.parse(self, input, kind) - } - NonterminalKind::CatchClause => Self::catch_clause.parse(self, input, kind), - NonterminalKind::CatchClauseError => Self::catch_clause_error.parse(self, input, kind), - NonterminalKind::CatchClauses => Self::catch_clauses.parse(self, input, kind), - NonterminalKind::ComparisonExpression => { - Self::comparison_expression.parse(self, input, kind) - } - NonterminalKind::ConditionalExpression => { - Self::conditional_expression.parse(self, input, kind) - } - NonterminalKind::ConstantDefinition => { - Self::constant_definition.parse(self, input, kind) - } - NonterminalKind::ConstructorAttribute => { - Self::constructor_attribute.parse(self, input, kind) - } - NonterminalKind::ConstructorAttributes => { - Self::constructor_attributes.parse(self, input, kind) - } - NonterminalKind::ConstructorDefinition => { - Self::constructor_definition.parse(self, input, kind) - } - NonterminalKind::ContinueStatement => Self::continue_statement.parse(self, input, kind), - NonterminalKind::ContractDefinition => { - Self::contract_definition.parse(self, input, kind) - } - NonterminalKind::ContractMember => Self::contract_member.parse(self, input, kind), - NonterminalKind::ContractMembers => Self::contract_members.parse(self, input, kind), - NonterminalKind::DecimalNumberExpression => { - Self::decimal_number_expression.parse(self, input, kind) - } - NonterminalKind::DoWhileStatement => Self::do_while_statement.parse(self, input, kind), - NonterminalKind::ElementaryType => Self::elementary_type.parse(self, input, kind), - NonterminalKind::ElseBranch => Self::else_branch.parse(self, input, kind), - NonterminalKind::EmitStatement => Self::emit_statement.parse(self, input, kind), - NonterminalKind::EnumDefinition => Self::enum_definition.parse(self, input, kind), - NonterminalKind::EnumMembers => Self::enum_members.parse(self, input, kind), - NonterminalKind::EqualityExpression => { - Self::equality_expression.parse(self, input, kind) - } - NonterminalKind::ErrorDefinition => Self::error_definition.parse(self, input, kind), - NonterminalKind::ErrorParameter => Self::error_parameter.parse(self, input, kind), - NonterminalKind::ErrorParameters => Self::error_parameters.parse(self, input, kind), - NonterminalKind::ErrorParametersDeclaration => { - Self::error_parameters_declaration.parse(self, input, kind) - } - NonterminalKind::EventDefinition => Self::event_definition.parse(self, input, kind), - NonterminalKind::EventParameter => Self::event_parameter.parse(self, input, kind), - NonterminalKind::EventParameters => Self::event_parameters.parse(self, input, kind), - NonterminalKind::EventParametersDeclaration => { - Self::event_parameters_declaration.parse(self, input, kind) - } - NonterminalKind::ExperimentalFeature => { - Self::experimental_feature.parse(self, input, kind) - } - NonterminalKind::ExperimentalPragma => { - Self::experimental_pragma.parse(self, input, kind) - } - NonterminalKind::ExponentiationExpression => { - Self::exponentiation_expression.parse(self, input, kind) - } - NonterminalKind::Expression => Self::expression.parse(self, input, kind), - NonterminalKind::ExpressionStatement => { - Self::expression_statement.parse(self, input, kind) - } - NonterminalKind::FallbackFunctionAttribute => { - Self::fallback_function_attribute.parse(self, input, kind) - } - NonterminalKind::FallbackFunctionAttributes => { - Self::fallback_function_attributes.parse(self, input, kind) - } - NonterminalKind::FallbackFunctionDefinition => { - Self::fallback_function_definition.parse(self, input, kind) - } - NonterminalKind::ForStatement => Self::for_statement.parse(self, input, kind), - NonterminalKind::ForStatementCondition => { - Self::for_statement_condition.parse(self, input, kind) - } - NonterminalKind::ForStatementInitialization => { - Self::for_statement_initialization.parse(self, input, kind) - } - NonterminalKind::FunctionAttribute => Self::function_attribute.parse(self, input, kind), - NonterminalKind::FunctionAttributes => { - Self::function_attributes.parse(self, input, kind) - } - NonterminalKind::FunctionBody => Self::function_body.parse(self, input, kind), - NonterminalKind::FunctionCallExpression => { - Self::function_call_expression.parse(self, input, kind) - } - NonterminalKind::FunctionDefinition => { - Self::function_definition.parse(self, input, kind) - } - NonterminalKind::FunctionName => Self::function_name.parse(self, input, kind), - NonterminalKind::FunctionType => Self::function_type.parse(self, input, kind), - NonterminalKind::FunctionTypeAttribute => { - Self::function_type_attribute.parse(self, input, kind) - } - NonterminalKind::FunctionTypeAttributes => { - Self::function_type_attributes.parse(self, input, kind) - } - NonterminalKind::HexNumberExpression => { - Self::hex_number_expression.parse(self, input, kind) - } - NonterminalKind::HexStringLiteral => Self::hex_string_literal.parse(self, input, kind), - NonterminalKind::HexStringLiterals => { - Self::hex_string_literals.parse(self, input, kind) - } - NonterminalKind::IdentifierPath => Self::identifier_path.parse(self, input, kind), - NonterminalKind::IfStatement => Self::if_statement.parse(self, input, kind), - NonterminalKind::ImportAlias => Self::import_alias.parse(self, input, kind), - NonterminalKind::ImportClause => Self::import_clause.parse(self, input, kind), - NonterminalKind::ImportDeconstruction => { - Self::import_deconstruction.parse(self, input, kind) - } - NonterminalKind::ImportDeconstructionSymbol => { - Self::import_deconstruction_symbol.parse(self, input, kind) - } - NonterminalKind::ImportDeconstructionSymbols => { - Self::import_deconstruction_symbols.parse(self, input, kind) - } - NonterminalKind::ImportDirective => Self::import_directive.parse(self, input, kind), - NonterminalKind::IndexAccessEnd => Self::index_access_end.parse(self, input, kind), - NonterminalKind::IndexAccessExpression => { - Self::index_access_expression.parse(self, input, kind) - } - NonterminalKind::InheritanceSpecifier => { - Self::inheritance_specifier.parse(self, input, kind) - } - NonterminalKind::InheritanceType => Self::inheritance_type.parse(self, input, kind), - NonterminalKind::InheritanceTypes => Self::inheritance_types.parse(self, input, kind), - NonterminalKind::InterfaceDefinition => { - Self::interface_definition.parse(self, input, kind) - } - NonterminalKind::InterfaceMembers => Self::interface_members.parse(self, input, kind), - NonterminalKind::LibraryDefinition => Self::library_definition.parse(self, input, kind), - NonterminalKind::LibraryMembers => Self::library_members.parse(self, input, kind), - NonterminalKind::MappingKey => Self::mapping_key.parse(self, input, kind), - NonterminalKind::MappingKeyType => Self::mapping_key_type.parse(self, input, kind), - NonterminalKind::MappingType => Self::mapping_type.parse(self, input, kind), - NonterminalKind::MappingValue => Self::mapping_value.parse(self, input, kind), - NonterminalKind::MemberAccessExpression => { - Self::member_access_expression.parse(self, input, kind) - } - NonterminalKind::ModifierAttribute => Self::modifier_attribute.parse(self, input, kind), - NonterminalKind::ModifierAttributes => { - Self::modifier_attributes.parse(self, input, kind) - } - NonterminalKind::ModifierDefinition => { - Self::modifier_definition.parse(self, input, kind) - } - NonterminalKind::ModifierInvocation => { - Self::modifier_invocation.parse(self, input, kind) - } - NonterminalKind::MultiplicativeExpression => { - Self::multiplicative_expression.parse(self, input, kind) - } - NonterminalKind::NamedArgument => Self::named_argument.parse(self, input, kind), - NonterminalKind::NamedArgumentGroup => { - Self::named_argument_group.parse(self, input, kind) - } - NonterminalKind::NamedArguments => Self::named_arguments.parse(self, input, kind), - NonterminalKind::NamedArgumentsDeclaration => { - Self::named_arguments_declaration.parse(self, input, kind) - } - NonterminalKind::NamedImport => Self::named_import.parse(self, input, kind), - NonterminalKind::NewExpression => Self::new_expression.parse(self, input, kind), - NonterminalKind::NumberUnit => Self::number_unit.parse(self, input, kind), - NonterminalKind::OrExpression => Self::or_expression.parse(self, input, kind), - NonterminalKind::OverridePaths => Self::override_paths.parse(self, input, kind), - NonterminalKind::OverridePathsDeclaration => { - Self::override_paths_declaration.parse(self, input, kind) - } - NonterminalKind::OverrideSpecifier => Self::override_specifier.parse(self, input, kind), - NonterminalKind::Parameter => Self::parameter.parse(self, input, kind), - NonterminalKind::Parameters => Self::parameters.parse(self, input, kind), - NonterminalKind::ParametersDeclaration => { - Self::parameters_declaration.parse(self, input, kind) - } - NonterminalKind::PathImport => Self::path_import.parse(self, input, kind), - NonterminalKind::PositionalArguments => { - Self::positional_arguments.parse(self, input, kind) - } - NonterminalKind::PositionalArgumentsDeclaration => { - Self::positional_arguments_declaration.parse(self, input, kind) - } - NonterminalKind::PostfixExpression => Self::postfix_expression.parse(self, input, kind), - NonterminalKind::Pragma => Self::pragma.parse(self, input, kind), - NonterminalKind::PragmaDirective => Self::pragma_directive.parse(self, input, kind), - NonterminalKind::PrefixExpression => Self::prefix_expression.parse(self, input, kind), - NonterminalKind::ReceiveFunctionAttribute => { - Self::receive_function_attribute.parse(self, input, kind) - } - NonterminalKind::ReceiveFunctionAttributes => { - Self::receive_function_attributes.parse(self, input, kind) - } - NonterminalKind::ReceiveFunctionDefinition => { - Self::receive_function_definition.parse(self, input, kind) - } - NonterminalKind::ReturnStatement => Self::return_statement.parse(self, input, kind), - NonterminalKind::ReturnsDeclaration => { - Self::returns_declaration.parse(self, input, kind) - } - NonterminalKind::RevertStatement => Self::revert_statement.parse(self, input, kind), - NonterminalKind::ShiftExpression => Self::shift_expression.parse(self, input, kind), - NonterminalKind::SimpleVersionLiteral => { - Self::simple_version_literal.parse(self, input, kind) - } - NonterminalKind::SourceUnit => Self::source_unit.parse(self, input, kind), - NonterminalKind::SourceUnitMember => Self::source_unit_member.parse(self, input, kind), - NonterminalKind::SourceUnitMembers => { - Self::source_unit_members.parse(self, input, kind) - } - NonterminalKind::StateVariableAttribute => { - Self::state_variable_attribute.parse(self, input, kind) - } - NonterminalKind::StateVariableAttributes => { - Self::state_variable_attributes.parse(self, input, kind) + + #[allow(unused_assignments, unused_parens)] + fn unnamed_function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_6_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::FunctionKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::FunctionKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Parameters, self.parameters_declaration(input))?; + seq.elem_labeled( + EdgeLabel::Attributes, + self.unnamed_function_attributes(input), + )?; + seq.elem_labeled(EdgeLabel::Body, self.function_body(input))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UnnamedFunctionDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn untyped_tuple_member(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::StorageLocation, + OptionalHelper::transform(self.storage_location(input)), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::UntypedTupleMember) + } + + #[allow(unused_assignments, unused_parens)] + fn user_defined_value_type_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_8 { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::TypeKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::TypeKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::IsKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::IsKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::ValueType, self.elementary_type(input))?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UserDefinedValueTypeDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn using_alias(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_19 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::AsKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::AsKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Operator, self.using_operator(input))?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UsingAlias) + } + + #[allow(unused_assignments, unused_parens)] + fn using_clause(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.identifier_path(input); + choice.consider(input, result)?; + if self.version_is_at_least_0_8_13 { + let result = self.using_deconstruction(input); + choice.consider(input, result)?; } - NonterminalKind::StateVariableDefinition => { - Self::state_variable_definition.parse(self, input, kind) + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::UsingClause) + } + + #[allow(unused_assignments, unused_parens)] + fn using_deconstruction(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_13 { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.using_deconstruction_symbols(input) + .with_label(EdgeLabel::Symbols) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UsingDeconstruction) + } + + #[allow(unused_assignments, unused_parens)] + fn using_deconstruction_symbol(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_13 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::Name, self.identifier_path(input))?; + if self.version_is_at_least_0_8_19 { + seq.elem_labeled( + EdgeLabel::Alias, + OptionalHelper::transform(self.using_alias(input)), + )?; + } + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UsingDeconstructionSymbol) + } + + #[allow(unused_assignments, unused_parens)] + fn using_deconstruction_symbols(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_13 { + SeparatedHelper::run::<_, LexicalContextType::Default>( + input, + self, + |input| { + self.using_deconstruction_symbol(input) + .with_label(EdgeLabel::Item) + }, + TerminalKind::Comma, + EdgeLabel::Separator, + ) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UsingDeconstructionSymbols) + } + + #[allow(unused_assignments, unused_parens)] + fn using_directive(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::UsingKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::UsingKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Clause, self.using_clause(input))?; + seq.elem_labeled( + EdgeLabel::ForKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::ForKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Target, self.using_target(input))?; + if self.version_is_at_least_0_8_13 { + seq.elem_labeled( + EdgeLabel::GlobalKeyword, + OptionalHelper::transform( + self.parse_terminal_with_trivia::( + input, + TerminalKind::GlobalKeyword, + ), + ), + )?; + } + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::UsingDirective) + } + + #[allow(unused_assignments, unused_parens)] + fn using_operator(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_8_19 { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Ampersand, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Asterisk, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::BangEqual, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Bar, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Caret, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::EqualEqual, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThan, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThanEqual, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::LessThan, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::LessThanEqual, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Minus, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Percent, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Plus, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Slash, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Tilde, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::UsingOperator) + } + + #[allow(unused_assignments, unused_parens)] + fn using_target(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.type_name(input); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Asterisk, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::UsingTarget) + } + + #[allow(unused_assignments, unused_parens)] + fn variable_declaration_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem( + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::VariableType, + self.variable_declaration_type(input), + )?; + seq.elem_labeled( + EdgeLabel::StorageLocation, + OptionalHelper::transform(self.storage_location(input)), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Identifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Value, + OptionalHelper::transform(self.variable_declaration_value(input)), + )?; + seq.finish() + }) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::Semicolon, + TerminalAcceptanceThreshold(1u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::Semicolon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Semicolon, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::VariableDeclarationStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn variable_declaration_type(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.type_name(input); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::VarKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::StateVariableDefinitionValue => { - Self::state_variable_definition_value.parse(self, input, kind) + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::VariableDeclarationType) + } + + #[allow(unused_assignments, unused_parens)] + fn variable_declaration_value(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Equal, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Equal, + ), + )?; + seq.elem_labeled(EdgeLabel::Expression, self.expression(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::VariableDeclarationValue) + } + + #[allow(unused_assignments, unused_parens)] + fn version_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.version_range(input); + choice.consider(input, result)?; + let result = self.version_term(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::VersionExpression) + } + + #[allow(unused_assignments, unused_parens)] + fn version_expression_set(&self, input: &mut ParserContext<'_>) -> ParserResult { + OneOrMoreHelper::run(input, |input| { + self.version_expression(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::VersionExpressionSet) + } + + #[allow(unused_assignments, unused_parens)] + fn version_expression_sets(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Pragma>( + input, + self, + |input| { + self.version_expression_set(input) + .with_label(EdgeLabel::Item) + }, + TerminalKind::BarBar, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::VersionExpressionSets) + } + + #[allow(unused_assignments, unused_parens)] + fn version_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.simple_version_literal(input); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::SingleQuotedVersionLiteral, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::DoubleQuotedVersionLiteral, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::VersionLiteral) + } + + #[allow(unused_assignments, unused_parens)] + fn version_operator(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Caret, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Tilde, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::Equal, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::LessThan, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThan, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::LessThanEqual, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::GreaterThanEqual, + ); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::VersionOperator) + } + + #[allow(unused_assignments, unused_parens)] + fn version_pragma(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::SolidityKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::SolidityKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Sets, self.version_expression_sets(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::VersionPragma) + } + + #[allow(unused_assignments, unused_parens)] + fn version_range(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::Start, self.version_literal(input))?; + seq.elem_labeled( + EdgeLabel::Minus, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Minus, + ), + )?; + seq.elem_labeled(EdgeLabel::End, self.version_literal(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::VersionRange) + } + + #[allow(unused_assignments, unused_parens)] + fn version_term(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Operator, + OptionalHelper::transform(self.version_operator(input)), + )?; + seq.elem_labeled(EdgeLabel::Literal, self.version_literal(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::VersionTerm) + } + + #[allow(unused_assignments, unused_parens)] + fn while_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::WhileKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::WhileKeyword, + ), + )?; + seq.elem(SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.expression(input) + .with_label(EdgeLabel::Condition) + .recover_until_with_nested_delims::<_, LexicalContextType::Default>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }))?; + seq.elem_labeled(EdgeLabel::Body, self.statement(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::WhileStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_arguments(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Yul>( + input, + self, + |input| self.yul_expression(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + )) + .with_kind(NonterminalKind::YulArguments) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_assignment_operator(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::ColonEqual, + ); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_5 { + let result = self.yul_colon_and_equal(input); + choice.consider(input, result)?; } - NonterminalKind::Statement => Self::statement.parse(self, input, kind), - NonterminalKind::Statements => Self::statements.parse(self, input, kind), - NonterminalKind::StorageLocation => Self::storage_location.parse(self, input, kind), - NonterminalKind::StringExpression => Self::string_expression.parse(self, input, kind), - NonterminalKind::StringLiteral => Self::string_literal.parse(self, input, kind), - NonterminalKind::StringLiterals => Self::string_literals.parse(self, input, kind), - NonterminalKind::StructDefinition => Self::struct_definition.parse(self, input, kind), - NonterminalKind::StructMember => Self::struct_member.parse(self, input, kind), - NonterminalKind::StructMembers => Self::struct_members.parse(self, input, kind), - NonterminalKind::ThrowStatement => Self::throw_statement.parse(self, input, kind), - NonterminalKind::TryStatement => Self::try_statement.parse(self, input, kind), - NonterminalKind::TupleDeconstructionElement => { - Self::tuple_deconstruction_element.parse(self, input, kind) + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::YulAssignmentOperator) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_block(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseBrace); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenBrace, + ), + )?; + seq.elem( + self.yul_statements(input) + .with_label(EdgeLabel::Statements) + .recover_until_with_nested_delims::<_, LexicalContextType::Yul>( + input, + self, + TerminalKind::CloseBrace, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseBrace, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseBrace, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::YulBlock) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_break_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulBreakKeyword, + ) + .with_label(EdgeLabel::BreakKeyword) + .with_kind(NonterminalKind::YulBreakStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_built_in_function(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulAddKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulAddModKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulAddressKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulAndKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulBalanceKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulBlockHashKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulByteKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCallCodeKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCallDataCopyKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCallDataLoadKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCallDataSizeKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCallerKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCallKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCallValueKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCoinBaseKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCreateKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulDelegateCallKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulDivKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulEqKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulExpKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulExtCodeCopyKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulExtCodeSizeKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulGasKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulGasLimitKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulGasPriceKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulGtKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulInvalidKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulIsZeroKeyword, + ); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulJumpKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::TupleDeconstructionElements => { - Self::tuple_deconstruction_elements.parse(self, input, kind) + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulJumpiKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::TupleDeconstructionStatement => { - Self::tuple_deconstruction_statement.parse(self, input, kind) + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulLog0Keyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulLog1Keyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulLog2Keyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulLog3Keyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulLog4Keyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulLtKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulMLoadKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulModKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulMSizeKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulMStore8Keyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulMStoreKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulMulKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulMulModKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulNotKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulNumberKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulOriginKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulOrKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulPopKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulReturnKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulRevertKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSDivKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSelfDestructKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSgtKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSignExtendKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSLoadKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSltKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSModKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSStoreKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulStopKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSubKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulTimestampKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulXorKeyword, + ); + choice.consider(input, result)?; + if self.version_is_at_least_0_4_12 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulKeccak256Keyword, + ); + choice.consider(input, result)?; } - NonterminalKind::TupleExpression => Self::tuple_expression.parse(self, input, kind), - NonterminalKind::TupleMember => Self::tuple_member.parse(self, input, kind), - NonterminalKind::TupleValue => Self::tuple_value.parse(self, input, kind), - NonterminalKind::TupleValues => Self::tuple_values.parse(self, input, kind), - NonterminalKind::TypeExpression => Self::type_expression.parse(self, input, kind), - NonterminalKind::TypeName => Self::type_name.parse(self, input, kind), - NonterminalKind::TypedTupleMember => Self::typed_tuple_member.parse(self, input, kind), - NonterminalKind::UncheckedBlock => Self::unchecked_block.parse(self, input, kind), - NonterminalKind::UnicodeStringLiteral => { - Self::unicode_string_literal.parse(self, input, kind) + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSha3Keyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UnicodeStringLiterals => { - Self::unicode_string_literals.parse(self, input, kind) + if !self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSuicideKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UnnamedFunctionAttribute => { - Self::unnamed_function_attribute.parse(self, input, kind) + if self.version_is_at_least_0_4_12 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulReturnDataCopyKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UnnamedFunctionAttributes => { - Self::unnamed_function_attributes.parse(self, input, kind) + if self.version_is_at_least_0_4_12 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulReturnDataSizeKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UnnamedFunctionDefinition => { - Self::unnamed_function_definition.parse(self, input, kind) + if self.version_is_at_least_0_4_12 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulStaticCallKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UntypedTupleMember => { - Self::untyped_tuple_member.parse(self, input, kind) + if self.version_is_at_least_0_4_12 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCreate2Keyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UserDefinedValueTypeDefinition => { - Self::user_defined_value_type_definition.parse(self, input, kind) + if self.version_is_at_least_0_5_0 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulExtCodeHashKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UsingAlias => Self::using_alias.parse(self, input, kind), - NonterminalKind::UsingClause => Self::using_clause.parse(self, input, kind), - NonterminalKind::UsingDeconstruction => { - Self::using_deconstruction.parse(self, input, kind) + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSarKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulShlKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulShrKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulChainIdKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSelfBalanceKeyword, + ); + choice.consider(input, result)?; + if self.version_is_at_least_0_8_7 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulBaseFeeKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UsingDeconstructionSymbol => { - Self::using_deconstruction_symbol.parse(self, input, kind) + if !self.version_is_at_least_0_8_18 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulDifficultyKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UsingDeconstructionSymbols => { - Self::using_deconstruction_symbols.parse(self, input, kind) + if self.version_is_at_least_0_8_18 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulPrevRandaoKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::UsingDirective => Self::using_directive.parse(self, input, kind), - NonterminalKind::UsingOperator => Self::using_operator.parse(self, input, kind), - NonterminalKind::UsingTarget => Self::using_target.parse(self, input, kind), - NonterminalKind::VariableDeclarationStatement => { - Self::variable_declaration_statement.parse(self, input, kind) + if self.version_is_at_least_0_8_24 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulBlobBaseFeeKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::VariableDeclarationType => { - Self::variable_declaration_type.parse(self, input, kind) + if self.version_is_at_least_0_8_24 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulBlobHashKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::VariableDeclarationValue => { - Self::variable_declaration_value.parse(self, input, kind) + if self.version_is_at_least_0_8_24 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulTLoadKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::VersionExpression => Self::version_expression.parse(self, input, kind), - NonterminalKind::VersionExpressionSet => { - Self::version_expression_set.parse(self, input, kind) + if self.version_is_at_least_0_8_24 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulTStoreKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::VersionExpressionSets => { - Self::version_expression_sets.parse(self, input, kind) + if self.version_is_at_least_0_8_24 { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulMCopyKeyword, + ); + choice.consider(input, result)?; } - NonterminalKind::VersionLiteral => Self::version_literal.parse(self, input, kind), - NonterminalKind::VersionOperator => Self::version_operator.parse(self, input, kind), - NonterminalKind::VersionPragma => Self::version_pragma.parse(self, input, kind), - NonterminalKind::VersionRange => Self::version_range.parse(self, input, kind), - NonterminalKind::VersionTerm => Self::version_term.parse(self, input, kind), - NonterminalKind::WhileStatement => Self::while_statement.parse(self, input, kind), - NonterminalKind::YulArguments => Self::yul_arguments.parse(self, input, kind), - NonterminalKind::YulAssignmentOperator => { - Self::yul_assignment_operator.parse(self, input, kind) + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::YulBuiltInFunction) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_colon_and_equal(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_5_5 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Colon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Colon, + ), + )?; + seq.elem_labeled( + EdgeLabel::Equal, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Equal, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::YulColonAndEqual) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_continue_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulContinueKeyword, + ) + .with_label(EdgeLabel::ContinueKeyword) + .with_kind(NonterminalKind::YulContinueStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_default_case(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::DefaultKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulDefaultKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulDefaultCase) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_equal_and_colon(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_5_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Equal, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Equal, + ), + )?; + seq.elem_labeled( + EdgeLabel::Colon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Colon, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::YulEqualAndColon) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let parse_postfix_yul_function_call_expression = |input: &mut ParserContext<'_>| { + PrecedenceHelper::to_postfix_operator( + NonterminalKind::YulFunctionCallExpression, + 1u8, + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.yul_arguments(input) + .with_label(EdgeLabel::Arguments) + .recover_until_with_nested_delims::<_, LexicalContextType::Yul>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }), + ) + }; + let primary_expression_parser = |input: &mut ParserContext<'_>| { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.yul_literal(input); + choice.consider(input, result)?; + let result = self.yul_built_in_function(input); + choice.consider(input, result)?; + let result = self.yul_path(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + }; + let postfix_operator_parser = |input: &mut ParserContext<'_>| { + ChoiceHelper::run(input, |mut choice, input| { + let result = parse_postfix_yul_function_call_expression(input); + choice.consider(input, result)?; + choice.finish(input) + }) + }; + let linear_expression_parser = |input: &mut ParserContext<'_>| { + SequenceHelper::run(|mut seq| { + seq.elem(primary_expression_parser(input))?; + seq.elem(ZeroOrMoreHelper::run(input, postfix_operator_parser))?; + seq.finish() + }) + }; + PrecedenceHelper::reduce_precedence_result( + NonterminalKind::YulExpression, + linear_expression_parser(input), + ) + .with_kind(NonterminalKind::YulExpression) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_for_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::ForKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulForKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Initialization, self.yul_block(input))?; + seq.elem_labeled(EdgeLabel::Condition, self.yul_expression(input))?; + seq.elem_labeled(EdgeLabel::Iterator, self.yul_block(input))?; + seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulForStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_function_call_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { + let result = self.yul_expression(input); + let ParserResult::Match(r#match) = &result else { + return result; + }; + match &r#match.nodes[..] { + [cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::YulExpression => match &node.children[..] { + [inner @ cst::Edge { + node: cst::Node::Nonterminal(node), + .. + }] if node.kind == NonterminalKind::YulFunctionCallExpression => { + ParserResult::r#match(vec![inner.clone()], r#match.expected_terminals.clone()) + } + _ => ParserResult::default(), + }, + _ => ParserResult::default(), + } + } + + #[allow(unused_assignments, unused_parens)] + fn yul_function_definition(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::FunctionKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulFunctionKeyword, + ), + )?; + seq.elem_labeled( + EdgeLabel::Name, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulIdentifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Parameters, + self.yul_parameters_declaration(input), + )?; + seq.elem_labeled( + EdgeLabel::Returns, + OptionalHelper::transform(self.yul_returns_declaration(input)), + )?; + seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulFunctionDefinition) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_if_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::IfKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulIfKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Condition, self.yul_expression(input))?; + seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulIfStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_label(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_5_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Label, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulIdentifier, + ), + )?; + seq.elem_labeled( + EdgeLabel::Colon, + self.parse_terminal_with_trivia::( + input, + TerminalKind::Colon, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::YulLabel) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_leave_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + if self.version_is_at_least_0_6_0 { + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulLeaveKeyword, + ) + .with_label(EdgeLabel::LeaveKeyword) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::YulLeaveStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_literal(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulTrueKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulFalseKeyword, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulDecimalLiteral, + ); + choice.consider(input, result)?; + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::YulHexLiteral, + ); + choice.consider(input, result)?; + let result = self.hex_string_literal(input); + choice.consider(input, result)?; + let result = self.string_literal(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::YulLiteral) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_parameters(&self, input: &mut ParserContext<'_>) -> ParserResult { + OptionalHelper::transform(SeparatedHelper::run::<_, LexicalContextType::Yul>( + input, + self, + |input| { + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulIdentifier, + ) + .with_label(EdgeLabel::Item) + }, + TerminalKind::Comma, + EdgeLabel::Separator, + )) + .with_kind(NonterminalKind::YulParameters) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_parameters_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + let mut delim_guard = input.open_delim(TerminalKind::CloseParen); + let input = delim_guard.ctx(); + seq.elem_labeled( + EdgeLabel::OpenParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::OpenParen, + ), + )?; + seq.elem( + self.yul_parameters(input) + .with_label(EdgeLabel::Parameters) + .recover_until_with_nested_delims::<_, LexicalContextType::Yul>( + input, + self, + TerminalKind::CloseParen, + TerminalAcceptanceThreshold(0u8), + ), + )?; + seq.elem_labeled( + EdgeLabel::CloseParen, + self.parse_terminal_with_trivia::( + input, + TerminalKind::CloseParen, + ), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::YulParametersDeclaration) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_path(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Yul>( + input, + self, + |input| { + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulIdentifier, + ) + .with_label(EdgeLabel::Item) + }, + TerminalKind::Period, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::YulPath) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_paths(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Yul>( + input, + self, + |input| self.yul_path(input).with_label(EdgeLabel::Item), + TerminalKind::Comma, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::YulPaths) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_returns_declaration(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::MinusGreaterThan, + self.parse_terminal_with_trivia::( + input, + TerminalKind::MinusGreaterThan, + ), + )?; + seq.elem_labeled(EdgeLabel::Variables, self.yul_variable_names(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulReturnsDeclaration) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_stack_assignment_operator(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_5_0 { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.parse_terminal_with_trivia::( + input, + TerminalKind::EqualColon, + ); + choice.consider(input, result)?; + let result = self.yul_equal_and_colon(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::YulStackAssignmentOperator) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_stack_assignment_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_5_0 { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::Assignment, + self.yul_stack_assignment_operator(input), + )?; + seq.elem_labeled( + EdgeLabel::Variable, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulIdentifier, + ), + )?; + seq.finish() + }) + } else { + ParserResult::disabled() + } + .with_kind(NonterminalKind::YulStackAssignmentStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.yul_block(input); + choice.consider(input, result)?; + let result = self.yul_function_definition(input); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.yul_stack_assignment_statement(input); + choice.consider(input, result)?; } - NonterminalKind::YulBlock => Self::yul_block.parse(self, input, kind), - NonterminalKind::YulBreakStatement => { - Self::yul_break_statement.parse(self, input, kind) + let result = self.yul_if_statement(input); + choice.consider(input, result)?; + let result = self.yul_for_statement(input); + choice.consider(input, result)?; + let result = self.yul_switch_statement(input); + choice.consider(input, result)?; + if self.version_is_at_least_0_6_0 { + let result = self.yul_leave_statement(input); + choice.consider(input, result)?; } - NonterminalKind::YulBuiltInFunction => { - Self::yul_built_in_function.parse(self, input, kind) + let result = self.yul_break_statement(input); + choice.consider(input, result)?; + let result = self.yul_continue_statement(input); + choice.consider(input, result)?; + let result = self.yul_variable_assignment_statement(input); + choice.consider(input, result)?; + if !self.version_is_at_least_0_5_0 { + let result = self.yul_label(input); + choice.consider(input, result)?; } - NonterminalKind::YulColonAndEqual => Self::yul_colon_and_equal.parse(self, input, kind), - NonterminalKind::YulContinueStatement => { - Self::yul_continue_statement.parse(self, input, kind) + let result = self.yul_variable_declaration_statement(input); + choice.consider(input, result)?; + let result = self.yul_expression(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::YulStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_statements(&self, input: &mut ParserContext<'_>) -> ParserResult { + ZeroOrMoreHelper::run(input, |input| { + self.yul_statement(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::YulStatements) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_switch_case(&self, input: &mut ParserContext<'_>) -> ParserResult { + ChoiceHelper::run(input, |mut choice, input| { + let result = self.yul_default_case(input); + choice.consider(input, result)?; + let result = self.yul_value_case(input); + choice.consider(input, result)?; + choice.finish(input) + }) + .with_label(EdgeLabel::Variant) + .with_kind(NonterminalKind::YulSwitchCase) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_switch_cases(&self, input: &mut ParserContext<'_>) -> ParserResult { + OneOrMoreHelper::run(input, |input| { + self.yul_switch_case(input).with_label(EdgeLabel::Item) + }) + .with_kind(NonterminalKind::YulSwitchCases) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_switch_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::SwitchKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulSwitchKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Expression, self.yul_expression(input))?; + seq.elem_labeled(EdgeLabel::Cases, self.yul_switch_cases(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulSwitchStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_value_case(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::CaseKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulCaseKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Value, self.yul_literal(input))?; + seq.elem_labeled(EdgeLabel::Body, self.yul_block(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulValueCase) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_variable_assignment_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::Variables, self.yul_paths(input))?; + seq.elem_labeled(EdgeLabel::Assignment, self.yul_assignment_operator(input))?; + seq.elem_labeled(EdgeLabel::Expression, self.yul_expression(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulVariableAssignmentStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_variable_declaration_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled( + EdgeLabel::LetKeyword, + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulLetKeyword, + ), + )?; + seq.elem_labeled(EdgeLabel::Variables, self.yul_variable_names(input))?; + seq.elem_labeled( + EdgeLabel::Value, + OptionalHelper::transform(self.yul_variable_declaration_value(input)), + )?; + seq.finish() + }) + .with_kind(NonterminalKind::YulVariableDeclarationStatement) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_variable_declaration_value(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(EdgeLabel::Assignment, self.yul_assignment_operator(input))?; + seq.elem_labeled(EdgeLabel::Expression, self.yul_expression(input))?; + seq.finish() + }) + .with_kind(NonterminalKind::YulVariableDeclarationValue) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_variable_names(&self, input: &mut ParserContext<'_>) -> ParserResult { + SeparatedHelper::run::<_, LexicalContextType::Yul>( + input, + self, + |input| { + self.parse_terminal_with_trivia::( + input, + TerminalKind::YulIdentifier, + ) + .with_label(EdgeLabel::Item) + }, + TerminalKind::Comma, + EdgeLabel::Separator, + ) + .with_kind(NonterminalKind::YulVariableNames) + } + + #[allow(unused_assignments, unused_parens)] + fn leading_trivia(&self, input: &mut ParserContext<'_>) -> ParserResult { + OneOrMoreHelper::run(input, |input| { + ChoiceHelper::run(input, |mut choice, input| { + let result = self + .parse_terminal::(input, TerminalKind::Whitespace) + .with_label(EdgeLabel::LeadingTrivia); + choice.consider(input, result)?; + let result = self + .parse_terminal::(input, TerminalKind::EndOfLine) + .with_label(EdgeLabel::LeadingTrivia); + choice.consider(input, result)?; + let result = self + .parse_terminal::( + input, + TerminalKind::SingleLineComment, + ) + .with_label(EdgeLabel::LeadingTrivia); + choice.consider(input, result)?; + let result = self + .parse_terminal::( + input, + TerminalKind::MultiLineComment, + ) + .with_label(EdgeLabel::LeadingTrivia); + choice.consider(input, result)?; + let result = self + .parse_terminal::( + input, + TerminalKind::SingleLineNatSpecComment, + ) + .with_label(EdgeLabel::LeadingTrivia); + choice.consider(input, result)?; + let result = self + .parse_terminal::( + input, + TerminalKind::MultiLineNatSpecComment, + ) + .with_label(EdgeLabel::LeadingTrivia); + choice.consider(input, result)?; + choice.finish(input) + }) + }) + } + + #[allow(unused_assignments, unused_parens)] + fn trailing_trivia(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem(OptionalHelper::transform( + self.parse_terminal::(input, TerminalKind::Whitespace) + .with_label(EdgeLabel::TrailingTrivia), + ))?; + seq.elem(OptionalHelper::transform( + self.parse_terminal::( + input, + TerminalKind::SingleLineComment, + ) + .with_label(EdgeLabel::TrailingTrivia), + ))?; + seq.elem( + self.parse_terminal::(input, TerminalKind::EndOfLine) + .with_label(EdgeLabel::TrailingTrivia), + )?; + seq.finish() + }) + } + + /******************************************** + * Scanner Functions + ********************************************/ + + #[allow(unused_assignments, unused_parens)] + fn ascii_escape(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + scan_chars!(input, 't'), + scan_chars!(input, 'r'), + scan_chars!(input, 'n'), + scan_chars!(input, '\\'), + scan_chars!(input, '\''), + scan_chars!(input, '"'), + scan_chars!(input, '\r', '\n'), + scan_chars!(input, '\r'), + scan_chars!(input, '\n') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn decimal_digits(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_one_or_more!(input, scan_char_range!(input, '0'..='9')), + scan_zero_or_more!( + input, + scan_sequence!( + scan_chars!(input, '_'), + scan_one_or_more!(input, scan_char_range!(input, '0'..='9')) + ) + ) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn decimal_exponent(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_choice!(input, scan_chars!(input, 'e'), scan_chars!(input, 'E')), + scan_optional!(input, scan_chars!(input, '-')), + self.decimal_digits(input) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn decimal_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + scan_not_followed_by!( + input, + scan_sequence!( + scan_chars!(input, '.'), + self.decimal_digits(input), + scan_optional!(input, self.decimal_exponent(input)) + ), + self.identifier_start(input) + ), + scan_not_followed_by!( + input, + scan_sequence!( + scan_not_followed_by!( + input, + self.decimal_digits(input), + scan_chars!(input, '.') + ), + scan_optional!(input, self.decimal_exponent(input)) + ), + self.identifier_start(input) + ), + if !self.version_is_at_least_0_5_0 { + scan_not_followed_by!( + input, + scan_sequence!( + scan_not_followed_by!( + input, + scan_sequence!(self.decimal_digits(input), scan_chars!(input, '.')), + self.decimal_digits(input) + ), + scan_optional!(input, self.decimal_exponent(input)) + ), + self.identifier_start(input) + ) + } else { + false + }, + if !self.version_is_at_least_0_5_0 { + scan_not_followed_by!( + input, + scan_sequence!( + self.decimal_digits(input), + scan_chars!(input, '.'), + self.decimal_digits(input), + scan_optional!(input, self.decimal_exponent(input)) + ), + self.identifier_start(input) + ) + } else { + false + }, + if self.version_is_at_least_0_5_0 { + scan_not_followed_by!( + input, + scan_sequence!( + self.decimal_digits(input), + scan_optional!( + input, + scan_sequence!(scan_chars!(input, '.'), self.decimal_digits(input)) + ), + scan_optional!(input, self.decimal_exponent(input)) + ), + self.identifier_start(input) + ) + } else { + false } - NonterminalKind::YulDefaultCase => Self::yul_default_case.parse(self, input, kind), - NonterminalKind::YulEqualAndColon => Self::yul_equal_and_colon.parse(self, input, kind), - NonterminalKind::YulExpression => Self::yul_expression.parse(self, input, kind), - NonterminalKind::YulForStatement => Self::yul_for_statement.parse(self, input, kind), - NonterminalKind::YulFunctionCallExpression => { - Self::yul_function_call_expression.parse(self, input, kind) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn double_quoted_hex_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, 'h', 'e', 'x', '"'), + scan_optional!(input, self.hex_string_contents(input)), + scan_chars!(input, '"') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn double_quoted_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + if !self.version_is_at_least_0_4_25 { + scan_sequence!( + scan_chars!(input, '"'), + scan_zero_or_more!( + input, + scan_choice!( + input, + self.escape_sequence_arbitrary(input), + scan_none_of!(input, '"', '\\', '\r', '\n') + ) + ), + scan_chars!(input, '"') + ) + } else { + false + }, + if self.version_is_at_least_0_4_25 && !self.version_is_at_least_0_7_0 { + scan_sequence!( + scan_chars!(input, '"'), + scan_zero_or_more!( + input, + scan_choice!( + input, + self.escape_sequence(input), + scan_none_of!(input, '"', '\\', '\r', '\n') + ) + ), + scan_chars!(input, '"') + ) + } else { + false + }, + scan_sequence!( + scan_chars!(input, '"'), + scan_zero_or_more!( + input, + scan_choice!( + input, + self.escape_sequence(input), + scan_char_range!(input, ' '..='!'), + scan_char_range!(input, '#'..='['), + scan_char_range!(input, ']'..='~') + ) + ), + scan_chars!(input, '"') + ) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn double_quoted_unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + if self.version_is_at_least_0_7_0 { + scan_sequence!( + scan_chars!(input, 'u', 'n', 'i', 'c', 'o', 'd', 'e', '"'), + scan_zero_or_more!( + input, + scan_choice!( + input, + self.escape_sequence(input), + scan_none_of!(input, '"', '\\', '\r', '\n') + ) + ), + scan_chars!(input, '"') + ) + } else { + false + } + } + + #[allow(unused_assignments, unused_parens)] + fn double_quoted_version_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, '"'), + self.version_specifier_fragment(input), + scan_zero_or_more!( + input, + scan_sequence!( + scan_chars!(input, '.'), + self.version_specifier_fragment(input) + ) + ), + scan_chars!(input, '"') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn end_of_line(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + scan_chars!(input, '\n'), + scan_sequence!( + scan_chars!(input, '\r'), + scan_optional!(input, scan_chars!(input, '\n')) + ) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn escape_sequence(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, '\\'), + scan_choice!( + input, + self.ascii_escape(input), + self.hex_byte_escape(input), + self.unicode_escape(input) + ) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn escape_sequence_arbitrary(&self, input: &mut ParserContext<'_>) -> bool { + if !self.version_is_at_least_0_4_25 { + scan_sequence!( + scan_chars!(input, '\\'), + scan_choice!( + input, + scan_none_of!(input, 'x', 'u'), + self.hex_byte_escape(input), + self.unicode_escape(input) + ) + ) + } else { + false + } + } + + #[allow(unused_assignments, unused_parens)] + fn hex_byte_escape(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, 'x'), + self.hex_character(input), + self.hex_character(input) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn hex_character(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + scan_char_range!(input, '0'..='9'), + scan_char_range!(input, 'a'..='f'), + scan_char_range!(input, 'A'..='F') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn hex_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + scan_not_followed_by!( + input, + scan_sequence!( + scan_chars!(input, '0', 'x'), + scan_one_or_more!(input, self.hex_character(input)), + scan_zero_or_more!( + input, + scan_sequence!( + scan_chars!(input, '_'), + scan_one_or_more!(input, self.hex_character(input)) + ) + ) + ), + self.identifier_start(input) + ), + if !self.version_is_at_least_0_5_0 { + scan_not_followed_by!( + input, + scan_sequence!( + scan_chars!(input, '0', 'X'), + scan_one_or_more!(input, self.hex_character(input)), + scan_zero_or_more!( + input, + scan_sequence!( + scan_chars!(input, '_'), + scan_one_or_more!(input, self.hex_character(input)) + ) + ) + ), + self.identifier_start(input) + ) + } else { + false } - NonterminalKind::YulFunctionDefinition => { - Self::yul_function_definition.parse(self, input, kind) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn hex_string_contents(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + self.hex_character(input), + self.hex_character(input), + scan_zero_or_more!( + input, + scan_sequence!( + scan_optional!(input, scan_chars!(input, '_')), + self.hex_character(input), + self.hex_character(input) + ) + ) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn identifier(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + self.identifier_start(input), + scan_zero_or_more!(input, self.identifier_part(input)) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn identifier_part(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + self.identifier_start(input), + scan_char_range!(input, '0'..='9') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn identifier_start(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + scan_chars!(input, '_'), + scan_chars!(input, '$'), + scan_char_range!(input, 'a'..='z'), + scan_char_range!(input, 'A'..='Z') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn multi_line_comment(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_not_followed_by!( + input, + scan_chars!(input, '/', '*'), + scan_sequence!(scan_chars!(input, '*'), scan_none_of!(input, '/')) + ), + scan_zero_or_more!( + input, + scan_choice!( + input, + scan_none_of!(input, '*'), + scan_not_followed_by!(input, scan_chars!(input, '*'), scan_chars!(input, '/')) + ) + ), + scan_chars!(input, '*', '/') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn multi_line_nat_spec_comment(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_not_followed_by!( + input, + scan_chars!(input, '/', '*', '*'), + scan_chars!(input, '/') + ), + scan_zero_or_more!( + input, + scan_choice!( + input, + scan_none_of!(input, '*'), + scan_not_followed_by!(input, scan_chars!(input, '*'), scan_chars!(input, '/')) + ) + ), + scan_chars!(input, '*', '/') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn single_line_comment(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_not_followed_by!(input, scan_chars!(input, '/', '/'), scan_chars!(input, '/')), + scan_zero_or_more!(input, scan_none_of!(input, '\r', '\n')) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn single_line_nat_spec_comment(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, '/', '/', '/'), + scan_zero_or_more!(input, scan_none_of!(input, '\r', '\n')) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn single_quoted_hex_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, 'h', 'e', 'x', '\''), + scan_optional!(input, self.hex_string_contents(input)), + scan_chars!(input, '\'') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn single_quoted_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + if !self.version_is_at_least_0_4_25 { + scan_sequence!( + scan_chars!(input, '\''), + scan_zero_or_more!( + input, + scan_choice!( + input, + self.escape_sequence_arbitrary(input), + scan_none_of!(input, '\'', '\\', '\r', '\n') + ) + ), + scan_chars!(input, '\'') + ) + } else { + false + }, + if self.version_is_at_least_0_4_25 && !self.version_is_at_least_0_7_0 { + scan_sequence!( + scan_chars!(input, '\''), + scan_zero_or_more!( + input, + scan_choice!( + input, + self.escape_sequence(input), + scan_none_of!(input, '\'', '\\', '\r', '\n') + ) + ), + scan_chars!(input, '\'') + ) + } else { + false + }, + scan_sequence!( + scan_chars!(input, '\''), + scan_zero_or_more!( + input, + scan_choice!( + input, + self.escape_sequence(input), + scan_char_range!(input, ' '..='&'), + scan_char_range!(input, '('..='['), + scan_char_range!(input, ']'..='~') + ) + ), + scan_chars!(input, '\'') + ) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn single_quoted_unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + if self.version_is_at_least_0_7_0 { + scan_sequence!( + scan_chars!(input, 'u', 'n', 'i', 'c', 'o', 'd', 'e', '\''), + scan_zero_or_more!( + input, + scan_choice!( + input, + self.escape_sequence(input), + scan_none_of!(input, '\'', '\\', '\r', '\n') + ) + ), + scan_chars!(input, '\'') + ) + } else { + false + } + } + + #[allow(unused_assignments, unused_parens)] + fn single_quoted_version_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, '\''), + self.version_specifier_fragment(input), + scan_zero_or_more!( + input, + scan_sequence!( + scan_chars!(input, '.'), + self.version_specifier_fragment(input) + ) + ), + scan_chars!(input, '\'') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn slash(&self, input: &mut ParserContext<'_>) -> bool { + scan_not_followed_by!( + input, + scan_chars!(input, '/'), + scan_choice!( + input, + scan_chars!(input, '='), + scan_chars!(input, '/'), + scan_chars!(input, '*') + ) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn unicode_escape(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, 'u'), + self.hex_character(input), + self.hex_character(input), + self.hex_character(input), + self.hex_character(input) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn version_specifier(&self, input: &mut ParserContext<'_>) -> bool { + self.version_specifier_fragment(input) + } + + #[allow(unused_assignments, unused_parens)] + fn version_specifier_fragment(&self, input: &mut ParserContext<'_>) -> bool { + scan_one_or_more!( + input, + scan_choice!( + input, + scan_chars!(input, 'x'), + scan_chars!(input, 'X'), + scan_chars!(input, '*'), + scan_char_range!(input, '0'..='9') + ) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn whitespace(&self, input: &mut ParserContext<'_>) -> bool { + scan_one_or_more!( + input, + scan_choice!(input, scan_chars!(input, ' '), scan_chars!(input, '\t')) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_decimal_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_not_followed_by!( + input, + scan_choice!( + input, + scan_chars!(input, '0'), + scan_sequence!( + scan_char_range!(input, '1'..='9'), + scan_zero_or_more!(input, scan_char_range!(input, '0'..='9')) + ) + ), + self.identifier_start(input) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_hex_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_not_followed_by!( + input, + scan_sequence!( + scan_chars!(input, '0', 'x'), + scan_one_or_more!(input, self.hex_character(input)) + ), + self.identifier_start(input) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn yul_identifier(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + if self.version_is_at_least_0_5_8 && !self.version_is_at_least_0_7_0 { + scan_sequence!( + self.identifier_start(input), + scan_zero_or_more!( + input, + scan_choice!(input, scan_chars!(input, '.'), self.identifier_part(input)) + ) + ) + } else { + false + }, + scan_sequence!( + self.identifier_start(input), + scan_zero_or_more!(input, self.identifier_part(input)) + ) + ) + } + + #[inline] + fn bytes_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if scan_sequence!( + scan_chars!(input, 'b', 'y', 't', 'e', 's'), + scan_optional!( + input, + scan_choice!( + input, + scan_chars!(input, '9'), + scan_chars!(input, '8'), + scan_chars!(input, '7'), + scan_chars!(input, '6'), + scan_chars!(input, '5'), + scan_chars!(input, '4'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '3', '1'), + scan_chars!(input, '3', '0'), + scan_chars!(input, '3'), + scan_chars!(input, '2', '9'), + scan_chars!(input, '2', '8'), + scan_chars!(input, '2', '7'), + scan_chars!(input, '2', '6'), + scan_chars!(input, '2', '5'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3'), + scan_chars!(input, '2', '2'), + scan_chars!(input, '2', '1'), + scan_chars!(input, '2', '0'), + scan_chars!(input, '2'), + scan_chars!(input, '1', '9'), + scan_chars!(input, '1', '8'), + scan_chars!(input, '1', '7'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5'), + scan_chars!(input, '1', '4'), + scan_chars!(input, '1', '3'), + scan_chars!(input, '1', '2'), + scan_chars!(input, '1', '1'), + scan_chars!(input, '1', '0'), + scan_chars!(input, '1') + ) + ) + ) { + KeywordScan::Reserved(TerminalKind::BytesKeyword) + } else { + KeywordScan::Absent } - NonterminalKind::YulIfStatement => Self::yul_if_statement.parse(self, input, kind), - NonterminalKind::YulLabel => Self::yul_label.parse(self, input, kind), - NonterminalKind::YulLeaveStatement => { - Self::yul_leave_statement.parse(self, input, kind) + ) + } + + #[inline] + fn fixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if scan_chars!(input, 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TerminalKind::FixedKeyword) + } else { + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ), + scan_chars!(input, 'x'), + scan_choice!( + input, + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '1', '6') + ) + ) { + KeywordScan::Reserved(TerminalKind::FixedKeyword) + } else { + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '2', '4', '8', 'x', '8'), + scan_chars!(input, '2', '4', '0', 'x', '8'), + scan_chars!(input, '2', '4', '0', 'x', '1', '6'), + scan_chars!(input, '2', '3', '2', 'x', '8'), + scan_chars!(input, '2', '3', '2', 'x', '2', '4'), + scan_chars!(input, '2', '3', '2', 'x', '1', '6'), + scan_chars!(input, '2', '2', '4', 'x', '8'), + scan_chars!(input, '2', '2', '4', 'x', '3', '2'), + scan_chars!(input, '2', '2', '4', 'x', '2', '4'), + scan_chars!(input, '2', '2', '4', 'x', '1', '6'), + scan_chars!(input, '2', '1', '6', 'x', '8'), + scan_chars!(input, '2', '1', '6', 'x', '4', '0'), + scan_chars!(input, '2', '1', '6', 'x', '3', '2'), + scan_chars!(input, '2', '1', '6', 'x', '2', '4'), + scan_chars!(input, '2', '1', '6', 'x', '1', '6'), + scan_chars!(input, '2', '0', '8', 'x', '8'), + scan_chars!(input, '2', '0', '8', 'x', '4', '8'), + scan_chars!(input, '2', '0', '8', 'x', '4', '0'), + scan_chars!(input, '2', '0', '8', 'x', '3', '2'), + scan_chars!(input, '2', '0', '8', 'x', '2', '4'), + scan_chars!(input, '2', '0', '8', 'x', '1', '6'), + scan_chars!(input, '2', '0', '0', 'x', '8'), + scan_chars!(input, '2', '0', '0', 'x', '5', '6'), + scan_chars!(input, '2', '0', '0', 'x', '4', '8'), + scan_chars!(input, '2', '0', '0', 'x', '4', '0'), + scan_chars!(input, '2', '0', '0', 'x', '3', '2'), + scan_chars!(input, '2', '0', '0', 'x', '2', '4'), + scan_chars!(input, '2', '0', '0', 'x', '1', '6'), + scan_chars!(input, '1', '9', '2', 'x', '8'), + scan_chars!(input, '1', '9', '2', 'x', '6', '4'), + scan_chars!(input, '1', '9', '2', 'x', '5', '6'), + scan_chars!(input, '1', '9', '2', 'x', '4', '8'), + scan_chars!(input, '1', '9', '2', 'x', '4', '0'), + scan_chars!(input, '1', '9', '2', 'x', '3', '2'), + scan_chars!(input, '1', '9', '2', 'x', '2', '4'), + scan_chars!(input, '1', '9', '2', 'x', '1', '6'), + scan_chars!(input, '1', '8', '4', 'x', '8'), + scan_chars!(input, '1', '8', '4', 'x', '7', '2'), + scan_chars!(input, '1', '8', '4', 'x', '6', '4'), + scan_chars!(input, '1', '8', '4', 'x', '5', '6'), + scan_chars!(input, '1', '8', '4', 'x', '4', '8'), + scan_chars!(input, '1', '8', '4', 'x', '4', '0'), + scan_chars!(input, '1', '8', '4', 'x', '3', '2'), + scan_chars!(input, '1', '8', '4', 'x', '2', '4'), + scan_chars!(input, '1', '8', '4', 'x', '1', '6') + ) + ) { + KeywordScan::Reserved(TerminalKind::FixedKeyword) + } else { + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '2', '5', '6', 'x', '8', '0'), + scan_chars!(input, '2', '5', '6', 'x', '8'), + scan_chars!(input, '2', '5', '6', 'x', '7', '2'), + scan_chars!(input, '2', '5', '6', 'x', '6', '4'), + scan_chars!(input, '2', '5', '6', 'x', '5', '6'), + scan_chars!(input, '2', '5', '6', 'x', '4', '8'), + scan_chars!(input, '2', '5', '6', 'x', '4', '0'), + scan_chars!(input, '2', '5', '6', 'x', '3', '2'), + scan_chars!(input, '2', '5', '6', 'x', '2', '4'), + scan_chars!(input, '2', '5', '6', 'x', '1', '6'), + scan_chars!(input, '2', '4', '8', 'x', '8', '0'), + scan_chars!(input, '2', '4', '8', 'x', '7', '2'), + scan_chars!(input, '2', '4', '8', 'x', '6', '4'), + scan_chars!(input, '2', '4', '8', 'x', '5', '6'), + scan_chars!(input, '2', '4', '8', 'x', '4', '8'), + scan_chars!(input, '2', '4', '8', 'x', '4', '0'), + scan_chars!(input, '2', '4', '8', 'x', '3', '2'), + scan_chars!(input, '2', '4', '8', 'x', '2', '4'), + scan_chars!(input, '2', '4', '8', 'x', '1', '6'), + scan_chars!(input, '2', '4', '0', 'x', '8', '0'), + scan_chars!(input, '2', '4', '0', 'x', '7', '2'), + scan_chars!(input, '2', '4', '0', 'x', '6', '4'), + scan_chars!(input, '2', '4', '0', 'x', '5', '6'), + scan_chars!(input, '2', '4', '0', 'x', '4', '8'), + scan_chars!(input, '2', '4', '0', 'x', '4', '0'), + scan_chars!(input, '2', '4', '0', 'x', '3', '2'), + scan_chars!(input, '2', '4', '0', 'x', '2', '4'), + scan_chars!(input, '2', '3', '2', 'x', '8', '0'), + scan_chars!(input, '2', '3', '2', 'x', '7', '2'), + scan_chars!(input, '2', '3', '2', 'x', '6', '4'), + scan_chars!(input, '2', '3', '2', 'x', '5', '6'), + scan_chars!(input, '2', '3', '2', 'x', '4', '8'), + scan_chars!(input, '2', '3', '2', 'x', '4', '0'), + scan_chars!(input, '2', '3', '2', 'x', '3', '2'), + scan_chars!(input, '2', '2', '4', 'x', '8', '0'), + scan_chars!(input, '2', '2', '4', 'x', '7', '2'), + scan_chars!(input, '2', '2', '4', 'x', '6', '4'), + scan_chars!(input, '2', '2', '4', 'x', '5', '6'), + scan_chars!(input, '2', '2', '4', 'x', '4', '8'), + scan_chars!(input, '2', '2', '4', 'x', '4', '0'), + scan_chars!(input, '2', '1', '6', 'x', '8', '0'), + scan_chars!(input, '2', '1', '6', 'x', '7', '2'), + scan_chars!(input, '2', '1', '6', 'x', '6', '4'), + scan_chars!(input, '2', '1', '6', 'x', '5', '6'), + scan_chars!(input, '2', '1', '6', 'x', '4', '8'), + scan_chars!(input, '2', '0', '8', 'x', '8', '0'), + scan_chars!(input, '2', '0', '8', 'x', '7', '2'), + scan_chars!(input, '2', '0', '8', 'x', '6', '4'), + scan_chars!(input, '2', '0', '8', 'x', '5', '6'), + scan_chars!(input, '2', '0', '0', 'x', '8', '0'), + scan_chars!(input, '2', '0', '0', 'x', '7', '2'), + scan_chars!(input, '2', '0', '0', 'x', '6', '4'), + scan_chars!(input, '1', '9', '2', 'x', '8', '0'), + scan_chars!(input, '1', '9', '2', 'x', '7', '2'), + scan_chars!(input, '1', '8', '4', 'x', '8', '0') + ) + ) { + if self.version_is_at_least_0_4_14 { + KeywordScan::Reserved(TerminalKind::FixedKeyword) + } else { + KeywordScan::Present(TerminalKind::FixedKeyword) + } + } else { + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3', '2'), + scan_chars!(input, '2', '2', '4'), + scan_chars!(input, '2', '1', '6'), + scan_chars!(input, '2', '0', '8'), + scan_chars!(input, '2', '0', '0'), + scan_chars!(input, '1', '9', '2'), + scan_chars!(input, '1', '8', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ), + scan_chars!(input, 'x'), + scan_choice!( + input, + scan_chars!(input, '9'), + scan_chars!(input, '7', '9'), + scan_chars!(input, '7', '8'), + scan_chars!(input, '7', '7'), + scan_chars!(input, '7', '6'), + scan_chars!(input, '7', '5'), + scan_chars!(input, '7', '4'), + scan_chars!(input, '7', '3'), + scan_chars!(input, '7', '1'), + scan_chars!(input, '7', '0'), + scan_chars!(input, '7'), + scan_chars!(input, '6', '9'), + scan_chars!(input, '6', '8'), + scan_chars!(input, '6', '7'), + scan_chars!(input, '6', '6'), + scan_chars!(input, '6', '5'), + scan_chars!(input, '6', '3'), + scan_chars!(input, '6', '2'), + scan_chars!(input, '6', '1'), + scan_chars!(input, '6', '0'), + scan_chars!(input, '6'), + scan_chars!(input, '5', '9'), + scan_chars!(input, '5', '8'), + scan_chars!(input, '5', '7'), + scan_chars!(input, '5', '5'), + scan_chars!(input, '5', '4'), + scan_chars!(input, '5', '3'), + scan_chars!(input, '5', '2'), + scan_chars!(input, '5', '1'), + scan_chars!(input, '5', '0'), + scan_chars!(input, '5'), + scan_chars!(input, '4', '9'), + scan_chars!(input, '4', '7'), + scan_chars!(input, '4', '6'), + scan_chars!(input, '4', '5'), + scan_chars!(input, '4', '4'), + scan_chars!(input, '4', '3'), + scan_chars!(input, '4', '2'), + scan_chars!(input, '4', '1'), + scan_chars!(input, '4'), + scan_chars!(input, '3', '9'), + scan_chars!(input, '3', '8'), + scan_chars!(input, '3', '7'), + scan_chars!(input, '3', '6'), + scan_chars!(input, '3', '5'), + scan_chars!(input, '3', '4'), + scan_chars!(input, '3', '3'), + scan_chars!(input, '3', '1'), + scan_chars!(input, '3', '0'), + scan_chars!(input, '3'), + scan_chars!(input, '2', '9'), + scan_chars!(input, '2', '8'), + scan_chars!(input, '2', '7'), + scan_chars!(input, '2', '6'), + scan_chars!(input, '2', '5'), + scan_chars!(input, '2', '3'), + scan_chars!(input, '2', '2'), + scan_chars!(input, '2', '1'), + scan_chars!(input, '2', '0'), + scan_chars!(input, '2'), + scan_chars!(input, '1', '9'), + scan_chars!(input, '1', '8'), + scan_chars!(input, '1', '7'), + scan_chars!(input, '1', '5'), + scan_chars!(input, '1', '4'), + scan_chars!(input, '1', '3'), + scan_chars!(input, '1', '2'), + scan_chars!(input, '1', '1'), + scan_chars!(input, '1', '0'), + scan_chars!(input, '1'), + scan_chars!(input, '0') + ) + ) { + if self.version_is_at_least_0_4_14 { + KeywordScan::Reserved(TerminalKind::FixedKeyword) + } else { + KeywordScan::Present(TerminalKind::FixedKeyword) + } + } else { + KeywordScan::Absent } - NonterminalKind::YulLiteral => Self::yul_literal.parse(self, input, kind), - NonterminalKind::YulParameters => Self::yul_parameters.parse(self, input, kind), - NonterminalKind::YulParametersDeclaration => { - Self::yul_parameters_declaration.parse(self, input, kind) + ) + } + + #[inline] + fn int_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if scan_sequence!( + scan_chars!(input, 'i', 'n', 't'), + scan_optional!( + input, + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3', '2'), + scan_chars!(input, '2', '2', '4'), + scan_chars!(input, '2', '1', '6'), + scan_chars!(input, '2', '0', '8'), + scan_chars!(input, '2', '0', '0'), + scan_chars!(input, '1', '9', '2'), + scan_chars!(input, '1', '8', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ) + ) + ) { + KeywordScan::Reserved(TerminalKind::IntKeyword) + } else { + KeywordScan::Absent } - NonterminalKind::YulPath => Self::yul_path.parse(self, input, kind), - NonterminalKind::YulPaths => Self::yul_paths.parse(self, input, kind), - NonterminalKind::YulReturnsDeclaration => { - Self::yul_returns_declaration.parse(self, input, kind) + ) + } + + #[inline] + fn ufixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TerminalKind::UfixedKeyword) + } else { + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ), + scan_chars!(input, 'x'), + scan_choice!( + input, + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '1', '6') + ) + ) { + KeywordScan::Reserved(TerminalKind::UfixedKeyword) + } else { + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '2', '4', '8', 'x', '8'), + scan_chars!(input, '2', '4', '0', 'x', '8'), + scan_chars!(input, '2', '4', '0', 'x', '1', '6'), + scan_chars!(input, '2', '3', '2', 'x', '8'), + scan_chars!(input, '2', '3', '2', 'x', '2', '4'), + scan_chars!(input, '2', '3', '2', 'x', '1', '6'), + scan_chars!(input, '2', '2', '4', 'x', '8'), + scan_chars!(input, '2', '2', '4', 'x', '3', '2'), + scan_chars!(input, '2', '2', '4', 'x', '2', '4'), + scan_chars!(input, '2', '2', '4', 'x', '1', '6'), + scan_chars!(input, '2', '1', '6', 'x', '8'), + scan_chars!(input, '2', '1', '6', 'x', '4', '0'), + scan_chars!(input, '2', '1', '6', 'x', '3', '2'), + scan_chars!(input, '2', '1', '6', 'x', '2', '4'), + scan_chars!(input, '2', '1', '6', 'x', '1', '6'), + scan_chars!(input, '2', '0', '8', 'x', '8'), + scan_chars!(input, '2', '0', '8', 'x', '4', '8'), + scan_chars!(input, '2', '0', '8', 'x', '4', '0'), + scan_chars!(input, '2', '0', '8', 'x', '3', '2'), + scan_chars!(input, '2', '0', '8', 'x', '2', '4'), + scan_chars!(input, '2', '0', '8', 'x', '1', '6'), + scan_chars!(input, '2', '0', '0', 'x', '8'), + scan_chars!(input, '2', '0', '0', 'x', '5', '6'), + scan_chars!(input, '2', '0', '0', 'x', '4', '8'), + scan_chars!(input, '2', '0', '0', 'x', '4', '0'), + scan_chars!(input, '2', '0', '0', 'x', '3', '2'), + scan_chars!(input, '2', '0', '0', 'x', '2', '4'), + scan_chars!(input, '2', '0', '0', 'x', '1', '6'), + scan_chars!(input, '1', '9', '2', 'x', '8'), + scan_chars!(input, '1', '9', '2', 'x', '6', '4'), + scan_chars!(input, '1', '9', '2', 'x', '5', '6'), + scan_chars!(input, '1', '9', '2', 'x', '4', '8'), + scan_chars!(input, '1', '9', '2', 'x', '4', '0'), + scan_chars!(input, '1', '9', '2', 'x', '3', '2'), + scan_chars!(input, '1', '9', '2', 'x', '2', '4'), + scan_chars!(input, '1', '9', '2', 'x', '1', '6'), + scan_chars!(input, '1', '8', '4', 'x', '8'), + scan_chars!(input, '1', '8', '4', 'x', '7', '2'), + scan_chars!(input, '1', '8', '4', 'x', '6', '4'), + scan_chars!(input, '1', '8', '4', 'x', '5', '6'), + scan_chars!(input, '1', '8', '4', 'x', '4', '8'), + scan_chars!(input, '1', '8', '4', 'x', '4', '0'), + scan_chars!(input, '1', '8', '4', 'x', '3', '2'), + scan_chars!(input, '1', '8', '4', 'x', '2', '4'), + scan_chars!(input, '1', '8', '4', 'x', '1', '6') + ) + ) { + KeywordScan::Reserved(TerminalKind::UfixedKeyword) + } else { + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '2', '5', '6', 'x', '8', '0'), + scan_chars!(input, '2', '5', '6', 'x', '8'), + scan_chars!(input, '2', '5', '6', 'x', '7', '2'), + scan_chars!(input, '2', '5', '6', 'x', '6', '4'), + scan_chars!(input, '2', '5', '6', 'x', '5', '6'), + scan_chars!(input, '2', '5', '6', 'x', '4', '8'), + scan_chars!(input, '2', '5', '6', 'x', '4', '0'), + scan_chars!(input, '2', '5', '6', 'x', '3', '2'), + scan_chars!(input, '2', '5', '6', 'x', '2', '4'), + scan_chars!(input, '2', '5', '6', 'x', '1', '6'), + scan_chars!(input, '2', '4', '8', 'x', '8', '0'), + scan_chars!(input, '2', '4', '8', 'x', '7', '2'), + scan_chars!(input, '2', '4', '8', 'x', '6', '4'), + scan_chars!(input, '2', '4', '8', 'x', '5', '6'), + scan_chars!(input, '2', '4', '8', 'x', '4', '8'), + scan_chars!(input, '2', '4', '8', 'x', '4', '0'), + scan_chars!(input, '2', '4', '8', 'x', '3', '2'), + scan_chars!(input, '2', '4', '8', 'x', '2', '4'), + scan_chars!(input, '2', '4', '8', 'x', '1', '6'), + scan_chars!(input, '2', '4', '0', 'x', '8', '0'), + scan_chars!(input, '2', '4', '0', 'x', '7', '2'), + scan_chars!(input, '2', '4', '0', 'x', '6', '4'), + scan_chars!(input, '2', '4', '0', 'x', '5', '6'), + scan_chars!(input, '2', '4', '0', 'x', '4', '8'), + scan_chars!(input, '2', '4', '0', 'x', '4', '0'), + scan_chars!(input, '2', '4', '0', 'x', '3', '2'), + scan_chars!(input, '2', '4', '0', 'x', '2', '4'), + scan_chars!(input, '2', '3', '2', 'x', '8', '0'), + scan_chars!(input, '2', '3', '2', 'x', '7', '2'), + scan_chars!(input, '2', '3', '2', 'x', '6', '4'), + scan_chars!(input, '2', '3', '2', 'x', '5', '6'), + scan_chars!(input, '2', '3', '2', 'x', '4', '8'), + scan_chars!(input, '2', '3', '2', 'x', '4', '0'), + scan_chars!(input, '2', '3', '2', 'x', '3', '2'), + scan_chars!(input, '2', '2', '4', 'x', '8', '0'), + scan_chars!(input, '2', '2', '4', 'x', '7', '2'), + scan_chars!(input, '2', '2', '4', 'x', '6', '4'), + scan_chars!(input, '2', '2', '4', 'x', '5', '6'), + scan_chars!(input, '2', '2', '4', 'x', '4', '8'), + scan_chars!(input, '2', '2', '4', 'x', '4', '0'), + scan_chars!(input, '2', '1', '6', 'x', '8', '0'), + scan_chars!(input, '2', '1', '6', 'x', '7', '2'), + scan_chars!(input, '2', '1', '6', 'x', '6', '4'), + scan_chars!(input, '2', '1', '6', 'x', '5', '6'), + scan_chars!(input, '2', '1', '6', 'x', '4', '8'), + scan_chars!(input, '2', '0', '8', 'x', '8', '0'), + scan_chars!(input, '2', '0', '8', 'x', '7', '2'), + scan_chars!(input, '2', '0', '8', 'x', '6', '4'), + scan_chars!(input, '2', '0', '8', 'x', '5', '6'), + scan_chars!(input, '2', '0', '0', 'x', '8', '0'), + scan_chars!(input, '2', '0', '0', 'x', '7', '2'), + scan_chars!(input, '2', '0', '0', 'x', '6', '4'), + scan_chars!(input, '1', '9', '2', 'x', '8', '0'), + scan_chars!(input, '1', '9', '2', 'x', '7', '2'), + scan_chars!(input, '1', '8', '4', 'x', '8', '0') + ) + ) { + if self.version_is_at_least_0_4_14 { + KeywordScan::Reserved(TerminalKind::UfixedKeyword) + } else { + KeywordScan::Present(TerminalKind::UfixedKeyword) + } + } else { + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3', '2'), + scan_chars!(input, '2', '2', '4'), + scan_chars!(input, '2', '1', '6'), + scan_chars!(input, '2', '0', '8'), + scan_chars!(input, '2', '0', '0'), + scan_chars!(input, '1', '9', '2'), + scan_chars!(input, '1', '8', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ), + scan_chars!(input, 'x'), + scan_choice!( + input, + scan_chars!(input, '9'), + scan_chars!(input, '7', '9'), + scan_chars!(input, '7', '8'), + scan_chars!(input, '7', '7'), + scan_chars!(input, '7', '6'), + scan_chars!(input, '7', '5'), + scan_chars!(input, '7', '4'), + scan_chars!(input, '7', '3'), + scan_chars!(input, '7', '1'), + scan_chars!(input, '7', '0'), + scan_chars!(input, '7'), + scan_chars!(input, '6', '9'), + scan_chars!(input, '6', '8'), + scan_chars!(input, '6', '7'), + scan_chars!(input, '6', '6'), + scan_chars!(input, '6', '5'), + scan_chars!(input, '6', '3'), + scan_chars!(input, '6', '2'), + scan_chars!(input, '6', '1'), + scan_chars!(input, '6', '0'), + scan_chars!(input, '6'), + scan_chars!(input, '5', '9'), + scan_chars!(input, '5', '8'), + scan_chars!(input, '5', '7'), + scan_chars!(input, '5', '5'), + scan_chars!(input, '5', '4'), + scan_chars!(input, '5', '3'), + scan_chars!(input, '5', '2'), + scan_chars!(input, '5', '1'), + scan_chars!(input, '5', '0'), + scan_chars!(input, '5'), + scan_chars!(input, '4', '9'), + scan_chars!(input, '4', '7'), + scan_chars!(input, '4', '6'), + scan_chars!(input, '4', '5'), + scan_chars!(input, '4', '4'), + scan_chars!(input, '4', '3'), + scan_chars!(input, '4', '2'), + scan_chars!(input, '4', '1'), + scan_chars!(input, '4'), + scan_chars!(input, '3', '9'), + scan_chars!(input, '3', '8'), + scan_chars!(input, '3', '7'), + scan_chars!(input, '3', '6'), + scan_chars!(input, '3', '5'), + scan_chars!(input, '3', '4'), + scan_chars!(input, '3', '3'), + scan_chars!(input, '3', '1'), + scan_chars!(input, '3', '0'), + scan_chars!(input, '3'), + scan_chars!(input, '2', '9'), + scan_chars!(input, '2', '8'), + scan_chars!(input, '2', '7'), + scan_chars!(input, '2', '6'), + scan_chars!(input, '2', '5'), + scan_chars!(input, '2', '3'), + scan_chars!(input, '2', '2'), + scan_chars!(input, '2', '1'), + scan_chars!(input, '2', '0'), + scan_chars!(input, '2'), + scan_chars!(input, '1', '9'), + scan_chars!(input, '1', '8'), + scan_chars!(input, '1', '7'), + scan_chars!(input, '1', '5'), + scan_chars!(input, '1', '4'), + scan_chars!(input, '1', '3'), + scan_chars!(input, '1', '2'), + scan_chars!(input, '1', '1'), + scan_chars!(input, '1', '0'), + scan_chars!(input, '1'), + scan_chars!(input, '0') + ) + ) { + if self.version_is_at_least_0_4_14 { + KeywordScan::Reserved(TerminalKind::UfixedKeyword) + } else { + KeywordScan::Present(TerminalKind::UfixedKeyword) + } + } else { + KeywordScan::Absent } - NonterminalKind::YulStackAssignmentOperator => { - Self::yul_stack_assignment_operator.parse(self, input, kind) + ) + } + + #[inline] + fn uint_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if scan_sequence!( + scan_chars!(input, 'u', 'i', 'n', 't'), + scan_optional!( + input, + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3', '2'), + scan_chars!(input, '2', '2', '4'), + scan_chars!(input, '2', '1', '6'), + scan_chars!(input, '2', '0', '8'), + scan_chars!(input, '2', '0', '0'), + scan_chars!(input, '1', '9', '2'), + scan_chars!(input, '1', '8', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ) + ) + ) { + KeywordScan::Reserved(TerminalKind::UintKeyword) + } else { + KeywordScan::Absent } - NonterminalKind::YulStackAssignmentStatement => { - Self::yul_stack_assignment_statement.parse(self, input, kind) + ) + } + + #[inline] + fn yul_bytes_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'b', 'y', 't', 'e', 's'), + scan_optional!( + input, + scan_choice!( + input, + scan_chars!(input, '9'), + scan_chars!(input, '8'), + scan_chars!(input, '7'), + scan_chars!(input, '6'), + scan_chars!(input, '5'), + scan_chars!(input, '4'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '3', '1'), + scan_chars!(input, '3', '0'), + scan_chars!(input, '3'), + scan_chars!(input, '2', '9'), + scan_chars!(input, '2', '8'), + scan_chars!(input, '2', '7'), + scan_chars!(input, '2', '6'), + scan_chars!(input, '2', '5'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3'), + scan_chars!(input, '2', '2'), + scan_chars!(input, '2', '1'), + scan_chars!(input, '2', '0'), + scan_chars!(input, '2'), + scan_chars!(input, '1', '9'), + scan_chars!(input, '1', '8'), + scan_chars!(input, '1', '7'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5'), + scan_chars!(input, '1', '4'), + scan_chars!(input, '1', '3'), + scan_chars!(input, '1', '2'), + scan_chars!(input, '1', '1'), + scan_chars!(input, '1', '0'), + scan_chars!(input, '1') + ) + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulBytesKeyword) + } else { + KeywordScan::Absent } - NonterminalKind::YulStatement => Self::yul_statement.parse(self, input, kind), - NonterminalKind::YulStatements => Self::yul_statements.parse(self, input, kind), - NonterminalKind::YulSwitchCase => Self::yul_switch_case.parse(self, input, kind), - NonterminalKind::YulSwitchCases => Self::yul_switch_cases.parse(self, input, kind), - NonterminalKind::YulSwitchStatement => { - Self::yul_switch_statement.parse(self, input, kind) + ) + } + + #[inline] + fn yul_fixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if !self.version_is_at_least_0_7_1 && scan_chars!(input, 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TerminalKind::YulFixedKeyword) + } else { + KeywordScan::Absent + }, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ), + scan_chars!(input, 'x'), + scan_choice!( + input, + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '1', '6') + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulFixedKeyword) + } else { + KeywordScan::Absent + }, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '2', '4', '8', 'x', '8'), + scan_chars!(input, '2', '4', '0', 'x', '8'), + scan_chars!(input, '2', '4', '0', 'x', '1', '6'), + scan_chars!(input, '2', '3', '2', 'x', '8'), + scan_chars!(input, '2', '3', '2', 'x', '2', '4'), + scan_chars!(input, '2', '3', '2', 'x', '1', '6'), + scan_chars!(input, '2', '2', '4', 'x', '8'), + scan_chars!(input, '2', '2', '4', 'x', '3', '2'), + scan_chars!(input, '2', '2', '4', 'x', '2', '4'), + scan_chars!(input, '2', '2', '4', 'x', '1', '6'), + scan_chars!(input, '2', '1', '6', 'x', '8'), + scan_chars!(input, '2', '1', '6', 'x', '4', '0'), + scan_chars!(input, '2', '1', '6', 'x', '3', '2'), + scan_chars!(input, '2', '1', '6', 'x', '2', '4'), + scan_chars!(input, '2', '1', '6', 'x', '1', '6'), + scan_chars!(input, '2', '0', '8', 'x', '8'), + scan_chars!(input, '2', '0', '8', 'x', '4', '8'), + scan_chars!(input, '2', '0', '8', 'x', '4', '0'), + scan_chars!(input, '2', '0', '8', 'x', '3', '2'), + scan_chars!(input, '2', '0', '8', 'x', '2', '4'), + scan_chars!(input, '2', '0', '8', 'x', '1', '6'), + scan_chars!(input, '2', '0', '0', 'x', '8'), + scan_chars!(input, '2', '0', '0', 'x', '5', '6'), + scan_chars!(input, '2', '0', '0', 'x', '4', '8'), + scan_chars!(input, '2', '0', '0', 'x', '4', '0'), + scan_chars!(input, '2', '0', '0', 'x', '3', '2'), + scan_chars!(input, '2', '0', '0', 'x', '2', '4'), + scan_chars!(input, '2', '0', '0', 'x', '1', '6'), + scan_chars!(input, '1', '9', '2', 'x', '8'), + scan_chars!(input, '1', '9', '2', 'x', '6', '4'), + scan_chars!(input, '1', '9', '2', 'x', '5', '6'), + scan_chars!(input, '1', '9', '2', 'x', '4', '8'), + scan_chars!(input, '1', '9', '2', 'x', '4', '0'), + scan_chars!(input, '1', '9', '2', 'x', '3', '2'), + scan_chars!(input, '1', '9', '2', 'x', '2', '4'), + scan_chars!(input, '1', '9', '2', 'x', '1', '6'), + scan_chars!(input, '1', '8', '4', 'x', '8'), + scan_chars!(input, '1', '8', '4', 'x', '7', '2'), + scan_chars!(input, '1', '8', '4', 'x', '6', '4'), + scan_chars!(input, '1', '8', '4', 'x', '5', '6'), + scan_chars!(input, '1', '8', '4', 'x', '4', '8'), + scan_chars!(input, '1', '8', '4', 'x', '4', '0'), + scan_chars!(input, '1', '8', '4', 'x', '3', '2'), + scan_chars!(input, '1', '8', '4', 'x', '2', '4'), + scan_chars!(input, '1', '8', '4', 'x', '1', '6') + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulFixedKeyword) + } else { + KeywordScan::Absent + }, + if self.version_is_at_least_0_4_14 + && !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '2', '5', '6', 'x', '8', '0'), + scan_chars!(input, '2', '5', '6', 'x', '8'), + scan_chars!(input, '2', '5', '6', 'x', '7', '2'), + scan_chars!(input, '2', '5', '6', 'x', '6', '4'), + scan_chars!(input, '2', '5', '6', 'x', '5', '6'), + scan_chars!(input, '2', '5', '6', 'x', '4', '8'), + scan_chars!(input, '2', '5', '6', 'x', '4', '0'), + scan_chars!(input, '2', '5', '6', 'x', '3', '2'), + scan_chars!(input, '2', '5', '6', 'x', '2', '4'), + scan_chars!(input, '2', '5', '6', 'x', '1', '6'), + scan_chars!(input, '2', '4', '8', 'x', '8', '0'), + scan_chars!(input, '2', '4', '8', 'x', '7', '2'), + scan_chars!(input, '2', '4', '8', 'x', '6', '4'), + scan_chars!(input, '2', '4', '8', 'x', '5', '6'), + scan_chars!(input, '2', '4', '8', 'x', '4', '8'), + scan_chars!(input, '2', '4', '8', 'x', '4', '0'), + scan_chars!(input, '2', '4', '8', 'x', '3', '2'), + scan_chars!(input, '2', '4', '8', 'x', '2', '4'), + scan_chars!(input, '2', '4', '8', 'x', '1', '6'), + scan_chars!(input, '2', '4', '0', 'x', '8', '0'), + scan_chars!(input, '2', '4', '0', 'x', '7', '2'), + scan_chars!(input, '2', '4', '0', 'x', '6', '4'), + scan_chars!(input, '2', '4', '0', 'x', '5', '6'), + scan_chars!(input, '2', '4', '0', 'x', '4', '8'), + scan_chars!(input, '2', '4', '0', 'x', '4', '0'), + scan_chars!(input, '2', '4', '0', 'x', '3', '2'), + scan_chars!(input, '2', '4', '0', 'x', '2', '4'), + scan_chars!(input, '2', '3', '2', 'x', '8', '0'), + scan_chars!(input, '2', '3', '2', 'x', '7', '2'), + scan_chars!(input, '2', '3', '2', 'x', '6', '4'), + scan_chars!(input, '2', '3', '2', 'x', '5', '6'), + scan_chars!(input, '2', '3', '2', 'x', '4', '8'), + scan_chars!(input, '2', '3', '2', 'x', '4', '0'), + scan_chars!(input, '2', '3', '2', 'x', '3', '2'), + scan_chars!(input, '2', '2', '4', 'x', '8', '0'), + scan_chars!(input, '2', '2', '4', 'x', '7', '2'), + scan_chars!(input, '2', '2', '4', 'x', '6', '4'), + scan_chars!(input, '2', '2', '4', 'x', '5', '6'), + scan_chars!(input, '2', '2', '4', 'x', '4', '8'), + scan_chars!(input, '2', '2', '4', 'x', '4', '0'), + scan_chars!(input, '2', '1', '6', 'x', '8', '0'), + scan_chars!(input, '2', '1', '6', 'x', '7', '2'), + scan_chars!(input, '2', '1', '6', 'x', '6', '4'), + scan_chars!(input, '2', '1', '6', 'x', '5', '6'), + scan_chars!(input, '2', '1', '6', 'x', '4', '8'), + scan_chars!(input, '2', '0', '8', 'x', '8', '0'), + scan_chars!(input, '2', '0', '8', 'x', '7', '2'), + scan_chars!(input, '2', '0', '8', 'x', '6', '4'), + scan_chars!(input, '2', '0', '8', 'x', '5', '6'), + scan_chars!(input, '2', '0', '0', 'x', '8', '0'), + scan_chars!(input, '2', '0', '0', 'x', '7', '2'), + scan_chars!(input, '2', '0', '0', 'x', '6', '4'), + scan_chars!(input, '1', '9', '2', 'x', '8', '0'), + scan_chars!(input, '1', '9', '2', 'x', '7', '2'), + scan_chars!(input, '1', '8', '4', 'x', '8', '0') + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulFixedKeyword) + } else { + KeywordScan::Absent + }, + if self.version_is_at_least_0_4_14 + && !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3', '2'), + scan_chars!(input, '2', '2', '4'), + scan_chars!(input, '2', '1', '6'), + scan_chars!(input, '2', '0', '8'), + scan_chars!(input, '2', '0', '0'), + scan_chars!(input, '1', '9', '2'), + scan_chars!(input, '1', '8', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ), + scan_chars!(input, 'x'), + scan_choice!( + input, + scan_chars!(input, '9'), + scan_chars!(input, '7', '9'), + scan_chars!(input, '7', '8'), + scan_chars!(input, '7', '7'), + scan_chars!(input, '7', '6'), + scan_chars!(input, '7', '5'), + scan_chars!(input, '7', '4'), + scan_chars!(input, '7', '3'), + scan_chars!(input, '7', '1'), + scan_chars!(input, '7', '0'), + scan_chars!(input, '7'), + scan_chars!(input, '6', '9'), + scan_chars!(input, '6', '8'), + scan_chars!(input, '6', '7'), + scan_chars!(input, '6', '6'), + scan_chars!(input, '6', '5'), + scan_chars!(input, '6', '3'), + scan_chars!(input, '6', '2'), + scan_chars!(input, '6', '1'), + scan_chars!(input, '6', '0'), + scan_chars!(input, '6'), + scan_chars!(input, '5', '9'), + scan_chars!(input, '5', '8'), + scan_chars!(input, '5', '7'), + scan_chars!(input, '5', '5'), + scan_chars!(input, '5', '4'), + scan_chars!(input, '5', '3'), + scan_chars!(input, '5', '2'), + scan_chars!(input, '5', '1'), + scan_chars!(input, '5', '0'), + scan_chars!(input, '5'), + scan_chars!(input, '4', '9'), + scan_chars!(input, '4', '7'), + scan_chars!(input, '4', '6'), + scan_chars!(input, '4', '5'), + scan_chars!(input, '4', '4'), + scan_chars!(input, '4', '3'), + scan_chars!(input, '4', '2'), + scan_chars!(input, '4', '1'), + scan_chars!(input, '4'), + scan_chars!(input, '3', '9'), + scan_chars!(input, '3', '8'), + scan_chars!(input, '3', '7'), + scan_chars!(input, '3', '6'), + scan_chars!(input, '3', '5'), + scan_chars!(input, '3', '4'), + scan_chars!(input, '3', '3'), + scan_chars!(input, '3', '1'), + scan_chars!(input, '3', '0'), + scan_chars!(input, '3'), + scan_chars!(input, '2', '9'), + scan_chars!(input, '2', '8'), + scan_chars!(input, '2', '7'), + scan_chars!(input, '2', '6'), + scan_chars!(input, '2', '5'), + scan_chars!(input, '2', '3'), + scan_chars!(input, '2', '2'), + scan_chars!(input, '2', '1'), + scan_chars!(input, '2', '0'), + scan_chars!(input, '2'), + scan_chars!(input, '1', '9'), + scan_chars!(input, '1', '8'), + scan_chars!(input, '1', '7'), + scan_chars!(input, '1', '5'), + scan_chars!(input, '1', '4'), + scan_chars!(input, '1', '3'), + scan_chars!(input, '1', '2'), + scan_chars!(input, '1', '1'), + scan_chars!(input, '1', '0'), + scan_chars!(input, '1'), + scan_chars!(input, '0') + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulFixedKeyword) + } else { + KeywordScan::Absent } - NonterminalKind::YulValueCase => Self::yul_value_case.parse(self, input, kind), - NonterminalKind::YulVariableAssignmentStatement => { - Self::yul_variable_assignment_statement.parse(self, input, kind) + ) + } + + #[inline] + fn yul_int_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'i', 'n', 't'), + scan_optional!( + input, + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3', '2'), + scan_chars!(input, '2', '2', '4'), + scan_chars!(input, '2', '1', '6'), + scan_chars!(input, '2', '0', '8'), + scan_chars!(input, '2', '0', '0'), + scan_chars!(input, '1', '9', '2'), + scan_chars!(input, '1', '8', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ) + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulIntKeyword) + } else { + KeywordScan::Absent } - NonterminalKind::YulVariableDeclarationStatement => { - Self::yul_variable_declaration_statement.parse(self, input, kind) + ) + } + + #[inline] + fn yul_ufixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if !self.version_is_at_least_0_7_1 && scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) + } else { + KeywordScan::Absent + }, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ), + scan_chars!(input, 'x'), + scan_choice!( + input, + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '1', '6') + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) + } else { + KeywordScan::Absent + }, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '2', '4', '8', 'x', '8'), + scan_chars!(input, '2', '4', '0', 'x', '8'), + scan_chars!(input, '2', '4', '0', 'x', '1', '6'), + scan_chars!(input, '2', '3', '2', 'x', '8'), + scan_chars!(input, '2', '3', '2', 'x', '2', '4'), + scan_chars!(input, '2', '3', '2', 'x', '1', '6'), + scan_chars!(input, '2', '2', '4', 'x', '8'), + scan_chars!(input, '2', '2', '4', 'x', '3', '2'), + scan_chars!(input, '2', '2', '4', 'x', '2', '4'), + scan_chars!(input, '2', '2', '4', 'x', '1', '6'), + scan_chars!(input, '2', '1', '6', 'x', '8'), + scan_chars!(input, '2', '1', '6', 'x', '4', '0'), + scan_chars!(input, '2', '1', '6', 'x', '3', '2'), + scan_chars!(input, '2', '1', '6', 'x', '2', '4'), + scan_chars!(input, '2', '1', '6', 'x', '1', '6'), + scan_chars!(input, '2', '0', '8', 'x', '8'), + scan_chars!(input, '2', '0', '8', 'x', '4', '8'), + scan_chars!(input, '2', '0', '8', 'x', '4', '0'), + scan_chars!(input, '2', '0', '8', 'x', '3', '2'), + scan_chars!(input, '2', '0', '8', 'x', '2', '4'), + scan_chars!(input, '2', '0', '8', 'x', '1', '6'), + scan_chars!(input, '2', '0', '0', 'x', '8'), + scan_chars!(input, '2', '0', '0', 'x', '5', '6'), + scan_chars!(input, '2', '0', '0', 'x', '4', '8'), + scan_chars!(input, '2', '0', '0', 'x', '4', '0'), + scan_chars!(input, '2', '0', '0', 'x', '3', '2'), + scan_chars!(input, '2', '0', '0', 'x', '2', '4'), + scan_chars!(input, '2', '0', '0', 'x', '1', '6'), + scan_chars!(input, '1', '9', '2', 'x', '8'), + scan_chars!(input, '1', '9', '2', 'x', '6', '4'), + scan_chars!(input, '1', '9', '2', 'x', '5', '6'), + scan_chars!(input, '1', '9', '2', 'x', '4', '8'), + scan_chars!(input, '1', '9', '2', 'x', '4', '0'), + scan_chars!(input, '1', '9', '2', 'x', '3', '2'), + scan_chars!(input, '1', '9', '2', 'x', '2', '4'), + scan_chars!(input, '1', '9', '2', 'x', '1', '6'), + scan_chars!(input, '1', '8', '4', 'x', '8'), + scan_chars!(input, '1', '8', '4', 'x', '7', '2'), + scan_chars!(input, '1', '8', '4', 'x', '6', '4'), + scan_chars!(input, '1', '8', '4', 'x', '5', '6'), + scan_chars!(input, '1', '8', '4', 'x', '4', '8'), + scan_chars!(input, '1', '8', '4', 'x', '4', '0'), + scan_chars!(input, '1', '8', '4', 'x', '3', '2'), + scan_chars!(input, '1', '8', '4', 'x', '2', '4'), + scan_chars!(input, '1', '8', '4', 'x', '1', '6') + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) + } else { + KeywordScan::Absent + }, + if self.version_is_at_least_0_4_14 + && !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '2', '5', '6', 'x', '8', '0'), + scan_chars!(input, '2', '5', '6', 'x', '8'), + scan_chars!(input, '2', '5', '6', 'x', '7', '2'), + scan_chars!(input, '2', '5', '6', 'x', '6', '4'), + scan_chars!(input, '2', '5', '6', 'x', '5', '6'), + scan_chars!(input, '2', '5', '6', 'x', '4', '8'), + scan_chars!(input, '2', '5', '6', 'x', '4', '0'), + scan_chars!(input, '2', '5', '6', 'x', '3', '2'), + scan_chars!(input, '2', '5', '6', 'x', '2', '4'), + scan_chars!(input, '2', '5', '6', 'x', '1', '6'), + scan_chars!(input, '2', '4', '8', 'x', '8', '0'), + scan_chars!(input, '2', '4', '8', 'x', '7', '2'), + scan_chars!(input, '2', '4', '8', 'x', '6', '4'), + scan_chars!(input, '2', '4', '8', 'x', '5', '6'), + scan_chars!(input, '2', '4', '8', 'x', '4', '8'), + scan_chars!(input, '2', '4', '8', 'x', '4', '0'), + scan_chars!(input, '2', '4', '8', 'x', '3', '2'), + scan_chars!(input, '2', '4', '8', 'x', '2', '4'), + scan_chars!(input, '2', '4', '8', 'x', '1', '6'), + scan_chars!(input, '2', '4', '0', 'x', '8', '0'), + scan_chars!(input, '2', '4', '0', 'x', '7', '2'), + scan_chars!(input, '2', '4', '0', 'x', '6', '4'), + scan_chars!(input, '2', '4', '0', 'x', '5', '6'), + scan_chars!(input, '2', '4', '0', 'x', '4', '8'), + scan_chars!(input, '2', '4', '0', 'x', '4', '0'), + scan_chars!(input, '2', '4', '0', 'x', '3', '2'), + scan_chars!(input, '2', '4', '0', 'x', '2', '4'), + scan_chars!(input, '2', '3', '2', 'x', '8', '0'), + scan_chars!(input, '2', '3', '2', 'x', '7', '2'), + scan_chars!(input, '2', '3', '2', 'x', '6', '4'), + scan_chars!(input, '2', '3', '2', 'x', '5', '6'), + scan_chars!(input, '2', '3', '2', 'x', '4', '8'), + scan_chars!(input, '2', '3', '2', 'x', '4', '0'), + scan_chars!(input, '2', '3', '2', 'x', '3', '2'), + scan_chars!(input, '2', '2', '4', 'x', '8', '0'), + scan_chars!(input, '2', '2', '4', 'x', '7', '2'), + scan_chars!(input, '2', '2', '4', 'x', '6', '4'), + scan_chars!(input, '2', '2', '4', 'x', '5', '6'), + scan_chars!(input, '2', '2', '4', 'x', '4', '8'), + scan_chars!(input, '2', '2', '4', 'x', '4', '0'), + scan_chars!(input, '2', '1', '6', 'x', '8', '0'), + scan_chars!(input, '2', '1', '6', 'x', '7', '2'), + scan_chars!(input, '2', '1', '6', 'x', '6', '4'), + scan_chars!(input, '2', '1', '6', 'x', '5', '6'), + scan_chars!(input, '2', '1', '6', 'x', '4', '8'), + scan_chars!(input, '2', '0', '8', 'x', '8', '0'), + scan_chars!(input, '2', '0', '8', 'x', '7', '2'), + scan_chars!(input, '2', '0', '8', 'x', '6', '4'), + scan_chars!(input, '2', '0', '8', 'x', '5', '6'), + scan_chars!(input, '2', '0', '0', 'x', '8', '0'), + scan_chars!(input, '2', '0', '0', 'x', '7', '2'), + scan_chars!(input, '2', '0', '0', 'x', '6', '4'), + scan_chars!(input, '1', '9', '2', 'x', '8', '0'), + scan_chars!(input, '1', '9', '2', 'x', '7', '2'), + scan_chars!(input, '1', '8', '4', 'x', '8', '0') + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) + } else { + KeywordScan::Absent + }, + if self.version_is_at_least_0_4_14 + && !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3', '2'), + scan_chars!(input, '2', '2', '4'), + scan_chars!(input, '2', '1', '6'), + scan_chars!(input, '2', '0', '8'), + scan_chars!(input, '2', '0', '0'), + scan_chars!(input, '1', '9', '2'), + scan_chars!(input, '1', '8', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ), + scan_chars!(input, 'x'), + scan_choice!( + input, + scan_chars!(input, '9'), + scan_chars!(input, '7', '9'), + scan_chars!(input, '7', '8'), + scan_chars!(input, '7', '7'), + scan_chars!(input, '7', '6'), + scan_chars!(input, '7', '5'), + scan_chars!(input, '7', '4'), + scan_chars!(input, '7', '3'), + scan_chars!(input, '7', '1'), + scan_chars!(input, '7', '0'), + scan_chars!(input, '7'), + scan_chars!(input, '6', '9'), + scan_chars!(input, '6', '8'), + scan_chars!(input, '6', '7'), + scan_chars!(input, '6', '6'), + scan_chars!(input, '6', '5'), + scan_chars!(input, '6', '3'), + scan_chars!(input, '6', '2'), + scan_chars!(input, '6', '1'), + scan_chars!(input, '6', '0'), + scan_chars!(input, '6'), + scan_chars!(input, '5', '9'), + scan_chars!(input, '5', '8'), + scan_chars!(input, '5', '7'), + scan_chars!(input, '5', '5'), + scan_chars!(input, '5', '4'), + scan_chars!(input, '5', '3'), + scan_chars!(input, '5', '2'), + scan_chars!(input, '5', '1'), + scan_chars!(input, '5', '0'), + scan_chars!(input, '5'), + scan_chars!(input, '4', '9'), + scan_chars!(input, '4', '7'), + scan_chars!(input, '4', '6'), + scan_chars!(input, '4', '5'), + scan_chars!(input, '4', '4'), + scan_chars!(input, '4', '3'), + scan_chars!(input, '4', '2'), + scan_chars!(input, '4', '1'), + scan_chars!(input, '4'), + scan_chars!(input, '3', '9'), + scan_chars!(input, '3', '8'), + scan_chars!(input, '3', '7'), + scan_chars!(input, '3', '6'), + scan_chars!(input, '3', '5'), + scan_chars!(input, '3', '4'), + scan_chars!(input, '3', '3'), + scan_chars!(input, '3', '1'), + scan_chars!(input, '3', '0'), + scan_chars!(input, '3'), + scan_chars!(input, '2', '9'), + scan_chars!(input, '2', '8'), + scan_chars!(input, '2', '7'), + scan_chars!(input, '2', '6'), + scan_chars!(input, '2', '5'), + scan_chars!(input, '2', '3'), + scan_chars!(input, '2', '2'), + scan_chars!(input, '2', '1'), + scan_chars!(input, '2', '0'), + scan_chars!(input, '2'), + scan_chars!(input, '1', '9'), + scan_chars!(input, '1', '8'), + scan_chars!(input, '1', '7'), + scan_chars!(input, '1', '5'), + scan_chars!(input, '1', '4'), + scan_chars!(input, '1', '3'), + scan_chars!(input, '1', '2'), + scan_chars!(input, '1', '1'), + scan_chars!(input, '1', '0'), + scan_chars!(input, '1'), + scan_chars!(input, '0') + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulUfixedKeyword) + } else { + KeywordScan::Absent } - NonterminalKind::YulVariableDeclarationValue => { - Self::yul_variable_declaration_value.parse(self, input, kind) + ) + } + + #[inline] + fn yul_uint_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( + input, + ident, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'u', 'i', 'n', 't'), + scan_optional!( + input, + scan_choice!( + input, + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), + scan_chars!(input, '8'), + scan_chars!(input, '7', '2'), + scan_chars!(input, '6', '4'), + scan_chars!(input, '5', '6'), + scan_chars!(input, '4', '8'), + scan_chars!(input, '4', '0'), + scan_chars!(input, '3', '2'), + scan_chars!(input, '2', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), + scan_chars!(input, '2', '4'), + scan_chars!(input, '2', '3', '2'), + scan_chars!(input, '2', '2', '4'), + scan_chars!(input, '2', '1', '6'), + scan_chars!(input, '2', '0', '8'), + scan_chars!(input, '2', '0', '0'), + scan_chars!(input, '1', '9', '2'), + scan_chars!(input, '1', '8', '4'), + scan_chars!(input, '1', '7', '6'), + scan_chars!(input, '1', '6', '8'), + scan_chars!(input, '1', '6', '0'), + scan_chars!(input, '1', '6'), + scan_chars!(input, '1', '5', '2'), + scan_chars!(input, '1', '4', '4'), + scan_chars!(input, '1', '3', '6'), + scan_chars!(input, '1', '2', '8'), + scan_chars!(input, '1', '2', '0'), + scan_chars!(input, '1', '1', '2'), + scan_chars!(input, '1', '0', '4') + ) + ) + ) + { + KeywordScan::Reserved(TerminalKind::YulUintKeyword) + } else { + KeywordScan::Absent } - NonterminalKind::YulVariableNames => Self::yul_variable_names.parse(self, input, kind), - } + ) } } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_error.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_error.rs index ba4aa54993..fd39e838ac 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_error.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_error.rs @@ -27,7 +27,7 @@ impl ParseError { } impl ParseError { - pub(crate) fn new( + pub(crate) fn create( text_range: TextRange, mut terminals_that_would_have_allowed_more_progress: Vec, ) -> Self { diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_output.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_output.rs index 790329c22b..5861eaefd1 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_output.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parse_output.rs @@ -26,6 +26,6 @@ impl ParseOutput { /// Creates a cursor that starts at the root of the parse tree. pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).create_cursor(TextIndex::ZERO) } } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/choice_helper.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/choice_helper.rs index 2e14c5a35f..cd2189fa53 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/choice_helper.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/choice_helper.rs @@ -140,7 +140,7 @@ pub fn total_not_skipped_span(result: &ParserResult) -> usize { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .filter_map(|edge| match edge.node { diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs index 29d42e609d..6447edfcb9 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs @@ -91,8 +91,8 @@ where let node = Node::terminal(kind, input.to_string()); children.push(Edge::anonymous(node)); ParseOutput { - tree: Rc::new(NonterminalNode::new(topmost_kind, children)), - errors: vec![ParseError::new( + tree: NonterminalNode::create(topmost_kind, children), + errors: vec![ParseError::create( start..start + input.into(), no_match.expected_terminals, )], @@ -149,13 +149,13 @@ where let start_index = stream.text_index_at(start); let mut errors = stream.into_errors(); - errors.push(ParseError::new( + errors.push(ParseError::create( start_index..input.into(), expected_terminals, )); ParseOutput { - tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), + tree: NonterminalNode::create(topmost_node.kind, new_children), errors, } } else { @@ -166,7 +166,7 @@ where debug_assert_eq!( errors.is_empty(), Rc::clone(&tree) - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() .all(|edge| edge .as_terminal() diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_result.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_result.rs index 00666ec339..60a8b1c591 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_result.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/parser_result.rs @@ -134,7 +134,7 @@ impl Match { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .all(|edge| { @@ -215,7 +215,7 @@ impl IncompleteMatch { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .try_fold(0u8, |mut acc, edge| { diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/recovery.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/recovery.rs index f54ae45934..c8fc8f5c45 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/recovery.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/recovery.rs @@ -90,7 +90,10 @@ impl ParserResult { let skipped = input.content(skipped_range.utf8()); - input.emit(ParseError::new(skipped_range, expected_terminals.clone())); + input.emit(ParseError::create( + skipped_range, + expected_terminals.clone(), + )); ParserResult::SkippedUntil(SkippedUntil { nodes, diff --git a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/separated_helper.rs b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/separated_helper.rs index bcc5dc64f0..280e9062c0 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/separated_helper.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/parser/parser_support/separated_helper.rs @@ -62,7 +62,7 @@ impl SeparatedHelper { kind, input.content(skipped_range.utf8()), ))); - input.emit(ParseError::new( + input.emit(ParseError::create( skipped_range, incomplete.expected_terminals, )); diff --git a/crates/solidity/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs b/crates/solidity/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs index e61f6b8089..d8d9cb1c59 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs @@ -5,9 +5,7 @@ use semver::Version; pub struct LanguageFacts; impl LanguageFacts { - pub const NAME: &'static str = "Solidity"; - - pub const SUPPORTED_VERSIONS: &'static [Version] = &[ + pub const ALL_VERSIONS: &'static [Version] = &[ Version::new(0, 4, 11), Version::new(0, 4, 12), Version::new(0, 4, 13), @@ -92,4 +90,8 @@ impl LanguageFacts { Version::new(0, 8, 27), Version::new(0, 8, 28), ]; + + pub const EARLIEST_VERSION: Version = Version::new(0, 4, 11); + + pub const LATEST_VERSION: Version = Version::new(0, 8, 28); } diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs index 92711989d2..1fefc1857e 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/renderer.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use anyhow::Result; use ariadne::{Color, Config, FnCache, Label, Report, ReportBuilder, ReportKind, Source}; use slang_solidity::bindings::{BindingGraph, Definition, Reference}; -use slang_solidity::cst::{NonterminalKind, TerminalKind}; +use slang_solidity::cst::{NodeKind, NonterminalKind, TerminalKindExtensions}; use slang_solidity::diagnostic; use super::runner::ParsedPart; @@ -106,9 +106,11 @@ fn check_bindings_coverage<'a>( let mut cursor = part.parse_output.create_tree_cursor(); - while cursor - .go_to_next_terminal_with_kinds(&[TerminalKind::Identifier, TerminalKind::YulIdentifier]) - { + while cursor.go_to_next_terminal() { + if !matches!(cursor.node().kind(), NodeKind::Terminal(kind) if kind.is_identifier()) { + continue; + } + if matches!( cursor.ancestors().next(), Some(ancestor) diff --git a/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs b/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs index aeee8760b3..4c601ad655 100644 --- a/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs +++ b/crates/solidity/outputs/cargo/tests/src/bindings_output/runner.rs @@ -54,7 +54,7 @@ pub fn run(group_name: &str, test_name: &str) -> Result<()> { contents, } in &multi_part.parts { - let parse_output = parser.parse(Parser::ROOT_KIND, contents); + let parse_output = parser.parse_file_contents(contents); let graph = builder.add_user_file_returning_graph(path, parse_output.create_tree_cursor()); parsed_parts.push(ParsedPart { diff --git a/crates/solidity/outputs/cargo/tests/src/built_ins.rs b/crates/solidity/outputs/cargo/tests/src/built_ins.rs index f73340ea33..e83f8c1c64 100644 --- a/crates/solidity/outputs/cargo/tests/src/built_ins.rs +++ b/crates/solidity/outputs/cargo/tests/src/built_ins.rs @@ -10,7 +10,7 @@ fn test_built_ins_parse_successfully() -> Result<()> { for version in &VERSION_BREAKS { let built_ins = get_built_ins_contents(version); let parser = Parser::create(version.clone())?; - let parse_output = parser.parse(Parser::ROOT_KIND, built_ins); + let parse_output = parser.parse_file_contents(built_ins); let report = parse_output .errors() diff --git a/crates/solidity/outputs/cargo/tests/src/cst_output/runner.rs b/crates/solidity/outputs/cargo/tests/src/cst_output/runner.rs index 9ac49b4e20..5a4945a7b2 100644 --- a/crates/solidity/outputs/cargo/tests/src/cst_output/runner.rs +++ b/crates/solidity/outputs/cargo/tests/src/cst_output/runner.rs @@ -37,7 +37,7 @@ pub fn run(parser_name: &str, test_name: &str) -> Result<()> { let tested_kind = NonterminalKind::from_str(parser_name) .unwrap_or_else(|_| panic!("No such parser: {parser_name}")); - let output = Parser::create(version.clone())?.parse(tested_kind, &source); + let output = Parser::create(version.clone())?.parse_nonterminal(tested_kind, &source); let output = match last_output { // Skip this version if it produces the same output. diff --git a/crates/solidity/outputs/cargo/tests/src/doc_examples/tree_query_language.rs b/crates/solidity/outputs/cargo/tests/src/doc_examples/tree_query_language.rs index 07498aa90e..237ede7f75 100644 --- a/crates/solidity/outputs/cargo/tests/src/doc_examples/tree_query_language.rs +++ b/crates/solidity/outputs/cargo/tests/src/doc_examples/tree_query_language.rs @@ -20,7 +20,7 @@ impl RemoveMkdocSnippetMarkers for &str { fn assert_matches(query: &Query, kind: NonterminalKind, source: &str) -> QueryMatchIterator { let parser = Parser::create(Version::new(0, 8, 12)).unwrap(); - let cursor = parser.parse(kind, source).create_tree_cursor(); + let cursor = parser.parse_nonterminal(kind, source).create_tree_cursor(); let tree = cursor.node(); assert!( @@ -33,7 +33,7 @@ fn assert_matches(query: &Query, kind: NonterminalKind, source: &str) -> QueryMa #[test] fn query_syntax() { - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:query-syntax-1] [MultiplicativeExpression [Expression] [Asterisk] [Expression]] @@ -45,7 +45,7 @@ fn query_syntax() { assert_matches(&query, NonterminalKind::MultiplicativeExpression, "1*2"); - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:query-syntax-2] [MultiplicativeExpression left_operand:[Expression] [Asterisk] right_operand:[Expression]] @@ -57,7 +57,7 @@ fn query_syntax() { assert_matches(&query, NonterminalKind::MultiplicativeExpression, "1*2"); - let query = Query::parse( + let query = Query::create( &r#" // --8<-- [start:query-syntax-3] [MultiplicativeExpression left_operand:[_] operator:["*"] right_operand:[_]] @@ -69,7 +69,7 @@ fn query_syntax() { assert_matches(&query, NonterminalKind::MultiplicativeExpression, "1*2"); - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:query-syntax-4] [MultiplicativeExpression left_operand:[_] [_]] @@ -80,7 +80,7 @@ fn query_syntax() { .unwrap(); assert_matches(&query, NonterminalKind::MultiplicativeExpression, "1*2"); - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:query-syntax-5] [MultiplicativeExpression [Expression [StringExpression]]] @@ -103,7 +103,7 @@ fn query_syntax() { #[test] fn capturing_nodes() { - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:capturing-nodes-1] [StructDefinition @struct_name name:[Identifier]] @@ -115,7 +115,7 @@ fn capturing_nodes() { assert_matches(&query, NonterminalKind::StructDefinition, "struct Abc {}"); - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:capturing-nodes-2] [ContractDefinition @@ -141,7 +141,7 @@ fn capturing_nodes() { #[test] fn quantification() { - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:quantification-1] [SourceUnit members:[_ ([_ @import [ImportDirective]])+]] @@ -157,7 +157,7 @@ fn quantification() { "import 'test.sol';\nimport * as Utils from 'lib/utils.sol'\n\ncontract Test {}", ); - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:quantification-2] [StructDefinition @@ -181,7 +181,7 @@ fn quantification() { ", ); - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:quantification-3] [FunctionCallExpression @@ -214,7 +214,7 @@ fn quantification() { #[test] fn alternations() { - let query = Query::parse( + let query = Query::create( &" // --8<-- [start:alternations-1] [FunctionCallExpression @@ -236,7 +236,7 @@ fn alternations() { assert_matches(&query, NonterminalKind::FunctionCallExpression, "a.call(1)").collect(); matches.first().unwrap().captures.get("method").unwrap(); - let query = Query::parse( + let query = Query::create( &r#" // --8<-- [start:alternations-2] @keyword ( @@ -276,7 +276,7 @@ fn alternations() { #[test] fn adjacency() { - let query = Query::parse( + let query = Query::create( &r#" // --8<-- [start:adjacency-1] [FunctionDefinition @@ -305,7 +305,7 @@ fn adjacency() { "int x" ); - let query = Query::parse( + let query = Query::create( &r#" // --8<-- [start:adjacency-2] [FunctionDefinition @@ -334,7 +334,7 @@ fn adjacency() { " int y" ); - let query = Query::parse( + let query = Query::create( &r#" // --8<-- [start:adjacency-3] [Statements @stmt1 [Statement] . @stmt2 [Statement]] diff --git a/crates/solidity/outputs/cargo/tests/src/doc_examples/using_queries.rs b/crates/solidity/outputs/cargo/tests/src/doc_examples/using_queries.rs index 9273eb664b..5421fe744c 100644 --- a/crates/solidity/outputs/cargo/tests/src/doc_examples/using_queries.rs +++ b/crates/solidity/outputs/cargo/tests/src/doc_examples/using_queries.rs @@ -3,7 +3,7 @@ use std::path::Path; use anyhow::Result; use infra_utils::paths::PathExtensions; use semver::Version; -use slang_solidity::cst::{NonterminalKind, Query, QueryMatchIterator}; +use slang_solidity::cst::{Query, QueryMatchIterator}; use slang_solidity::parser::{ParseOutput, Parser}; fn parse_doc_input_file>(path: T) -> Result { @@ -13,7 +13,7 @@ fn parse_doc_input_file>(path: T) -> Result { let parser = Parser::create(Version::new(0, 8, 0))?; - Ok(parser.parse(NonterminalKind::SourceUnit, source.trim())) + Ok(parser.parse_file_contents(source.trim())) } #[test] @@ -27,7 +27,7 @@ fn using_queries() -> Result<()> { // Any `Cursor` can be used to create a query. let cursor = parse_output.create_tree_cursor(); - let query = Query::parse("[ContractDefinition]").unwrap(); + let query = Query::create("[ContractDefinition]").unwrap(); let result: QueryMatchIterator = cursor.query(vec![query]); // --8<-- [end:creating-a-query] } @@ -38,7 +38,7 @@ fn using_queries() -> Result<()> { // --8<-- [start:visiting-contracts] let mut found = vec![]; - let query = Query::parse("@contract [ContractDefinition]").unwrap(); + let query = Query::create("@contract [ContractDefinition]").unwrap(); for r#match in cursor.query(vec![query]) { let captures = r#match.captures; @@ -62,11 +62,11 @@ fn using_queries() -> Result<()> { // --8<-- [start:multiple-patterns] let mut names = vec![]; - let struct_def = Query::parse("[StructDefinition @name [Identifier]]").unwrap(); - let enum_def = Query::parse("[EnumDefinition @name [Identifier]]").unwrap(); + let struct_def = Query::create("[StructDefinition @name [Identifier]]").unwrap(); + let enum_def = Query::create("[EnumDefinition @name [Identifier]]").unwrap(); for r#match in cursor.query(vec![struct_def, enum_def]) { - let index = r#match.query_number; + let index = r#match.query_index; let captures = r#match.captures; let cursors = captures.get("name").unwrap(); @@ -94,7 +94,7 @@ fn using_queries() -> Result<()> { let mut names = vec![]; - let query = Query::parse("[TypedTupleMember @type type_name:[_]]").unwrap(); + let query = Query::create("[TypedTupleMember @type type_name:[_]]").unwrap(); for r#match in cursor.query(vec![query]) { let captures = r#match.captures; @@ -117,7 +117,7 @@ fn using_queries() -> Result<()> { let mut names = vec![]; - let query = Query::parse(r#"[ElementaryType @uint_keyword variant:["uint"]]"#).unwrap(); + let query = Query::create(r#"[ElementaryType @uint_keyword variant:["uint"]]"#).unwrap(); for r#match in cursor.query(vec![query]) { let captures = r#match.captures; @@ -140,7 +140,7 @@ fn tx_origin_query() -> Result<()> { let parse_output = parse_doc_input_file("tx-origin.sol")?; let cursor = parse_output.create_tree_cursor(); // --8<-- [start:tx-origin] - let query = Query::parse( + let query = Query::create( r#"@txorigin [MemberAccessExpression [Expression @start ["tx"]] ["origin"] diff --git a/crates/solidity/outputs/cargo/tests/src/doc_examples/using_the_cursor.rs b/crates/solidity/outputs/cargo/tests/src/doc_examples/using_the_cursor.rs index 8979470be1..f6910667d8 100644 --- a/crates/solidity/outputs/cargo/tests/src/doc_examples/using_the_cursor.rs +++ b/crates/solidity/outputs/cargo/tests/src/doc_examples/using_the_cursor.rs @@ -21,7 +21,7 @@ fn using_the_cursor() -> Result<()> { // --8<-- [start:parse-input] let parser = Parser::create(Version::parse("0.8.0")?)?; - let parse_output = parser.parse(NonterminalKind::SourceUnit, source); + let parse_output = parser.parse_file_contents(source); // --8<-- [end:parse-input] { diff --git a/crates/solidity/outputs/cargo/tests/src/doc_examples/using_the_parser.rs b/crates/solidity/outputs/cargo/tests/src/doc_examples/using_the_parser.rs index f8ccc8d74a..ee4d4a2930 100644 --- a/crates/solidity/outputs/cargo/tests/src/doc_examples/using_the_parser.rs +++ b/crates/solidity/outputs/cargo/tests/src/doc_examples/using_the_parser.rs @@ -20,7 +20,7 @@ fn using_the_parser() -> Result<()> { // --8<-- [start:parse-input] let parser = Parser::create(Version::parse("0.8.0")?)?; - let parse_output = parser.parse(NonterminalKind::ContractDefinition, source); + let parse_output = parser.parse_nonterminal(NonterminalKind::ContractDefinition, source); // --8<-- [end:parse-input] // --8<-- [start:print-errors] diff --git a/crates/solidity/outputs/cargo/tests/src/trivia.rs b/crates/solidity/outputs/cargo/tests/src/trivia.rs index 8eb2ebc6f7..7d176d8b44 100644 --- a/crates/solidity/outputs/cargo/tests/src/trivia.rs +++ b/crates/solidity/outputs/cargo/tests/src/trivia.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use anyhow::Result; use semver::Version; -use slang_solidity::cst::{NonterminalKind, TerminalKind}; +use slang_solidity::cst::TerminalKind; use slang_solidity::parser::Parser; #[test] @@ -26,7 +26,7 @@ fn compare_end_of_lines(input: &str, expected: &[&str]) -> Result<()> { let version = Version::parse("0.8.0")?; let parser = Parser::create(version)?; - let output = parser.parse(NonterminalKind::SourceUnit, input); + let output = parser.parse_file_contents(input); assert!(output.is_valid()); let actual = Rc::clone(output.tree()) diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/generated/config.json b/crates/solidity/outputs/cargo/wasm/src/generated/generated/config.json index 3444eb9169..15037ce589 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/generated/config.json +++ b/crates/solidity/outputs/cargo/wasm/src/generated/generated/config.json @@ -170,16 +170,6 @@ "as_getter": true } }, - "nomic-foundation:slang:parser:parse-error.text-range()": { - "Function": { - "as_getter": true - } - }, - "nomic-foundation:slang:parser:parse-error.message()": { - "Function": { - "as_getter": true - } - }, "nomic-foundation:slang:parser:parse-output.tree()": { "Function": { "as_getter": true diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit index 1721afc82d..e6fbb0073b 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit @@ -6,12 +6,16 @@ interface bindings { /// A giant graph that contains name binding information for all source files within the compilation unit. /// It stores cursors to all definitions and references, and can resolve the edges between them. resource binding-graph { - /// If the provided cursor points at a definition `Identifier`, it will return the - /// corresponding definition. Otherwise, it will return `undefined`. + /// Tries to resolve the identifier terminal pointed at by the provided cursor to a definition. + /// If successful, returns the definition. Otherwise, returns `undefined`. + /// + /// For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. definition-at: func(cursor: borrow) -> option; - /// If the provided cursor points at a reference `Identifier`, it will return the - /// corresponding reference. Otherwise, it will return `undefined`. + /// Tries to resolve the identifier terminal pointed at by the provided cursor to a reference. + /// If successful, returns the reference. Otherwise, returns `undefined`. + /// + /// For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. reference-at: func(cursor: borrow) -> option; } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit index ea64aab4ac..b3918e9681 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit @@ -3,6 +3,7 @@ interface compilation { use bindings.{binding-graph}; use cst.{nonterminal-node, cursor}; + use parser.{parse-error}; /// A builder for creating compilation units. /// Allows incrementally building a transitive list of all files and their imports. @@ -64,6 +65,9 @@ interface compilation { /// Returns the syntax tree of this file. tree: func() -> nonterminal-node; + /// Returns a list of all errors encountered during parsing this file. + errors: func() -> list; + /// Creates a cursor for traversing the syntax tree of this file. create-tree-cursor: func() -> cursor; } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/cst.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/cst.wit index 8afe6ee8f0..d58a92f3cc 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/cst.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/cst.wit @@ -4621,9 +4621,11 @@ interface cst { //// Useful extension methods for working with terminals and terminal kinds. resource terminal-kind-extensions { - /// Returns true if the terminal is a trivia token. i.e. whitespace, comments, etc... + /// Returns `true` if the terminal is an identifier token. + is-identifier: static func(kind: terminal-kind) -> bool; + /// Returns `true` if the terminal is a trivia token. i.e. whitespace, comments, etc... is-trivia: static func(kind: terminal-kind) -> bool; - /// Returns true if the terminal is a valid token in the language grammar. + /// Returns `true` if the terminal is a valid token in the language grammar. is-valid: static func(kind: terminal-kind) -> bool; } @@ -5014,7 +5016,7 @@ interface cst { /// Moves to the last child of the current node. go-to-last-child: func() -> bool; /// Moves to the nth child of the current node. - go-to-nth-child: func(child-number: u32) -> bool; + go-to-nth-child: func(child-index: u32) -> bool; /// Moves to the next sibling node. go-to-next-sibling: func() -> bool; @@ -5056,23 +5058,21 @@ interface cst { resource query { /// Parses a query string into a query object. /// Throws an error if the query syntax is invalid. - parse: static func(text: string) -> result; + create: static func(text: string) -> result; } /// Represents an error that occurred while parsing a query. record query-error { - /// The error message describing what went wrong. + /// A human-readable message describing what went wrong. message: string, - /// The line number where the error occurred. - line: u32, - /// The column number where the error occurred. - column: u32, + /// The text range where the error occurred in the query code. + text-range: text-range, } - /// Represents a match found by executing a query. + /// Represents a match found by executing queries on a cursor. record query-match { /// The index of the query that produced this match. - query-number: u32, + query-index: u32, /// List of captured nodes and their names from the query. captures: list>>, } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/parser.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/parser.wit index 6eca8e01ae..8834d77de3 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/parser.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/parser.wit @@ -6,27 +6,26 @@ interface parser { /// A parser instance that can parse source code into syntax trees. /// Each parser is configured for a specific language version and grammar. resource parser { - /// Returns the root nonterminal kind for this parser's grammar. - /// This represents the starting point for parsing a complete source file. - root-kind: static func() -> nonterminal-kind; - /// Creates a new parser instance for the specified language version. create: static func(language-version: string) -> result; /// Returns the language version this parser instance is configured for. language-version: func() -> string; - /// Parses the input string starting from the specified nonterminal kind. - parse: func(kind: nonterminal-kind, input: string) -> parse-output; + /// Parses the input string into a complete source file. + parse-file-contents: func(input: string) -> parse-output; + + /// Parses the input string into a nonterminal with the specified kind. + parse-nonterminal: func(kind: nonterminal-kind, input: string) -> parse-output; } - /// Contains information about where the error occurred and what went wrong. - resource parse-error { - /// Returns the text range where the error occurred in the source code. - text-range: func() -> text-range; + /// Represents an error that occurred while parsing source code. + record parse-error { + /// A human-readable message describing what went wrong. + message: string, - /// Returns a human-readable message describing the parsing error. - message: func() -> string; + /// The text range where the error occurred in the source code. + text-range: text-range, } /// The output of a parsing operation. @@ -37,7 +36,7 @@ interface parser { tree: func() -> nonterminal-node; /// Returns a list of all parsing errors encountered. - /// An empty list indicates successful parsing with no errors. + /// An empty list indicates a successful parse with no errors. errors: func() -> list; /// Returns whether the parse was completely successful with no errors. diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/utils.wit b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/utils.wit index 9bb93e160f..86c9d20bd0 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/utils.wit +++ b/crates/solidity/outputs/cargo/wasm/src/generated/interface/generated/utils.wit @@ -4,6 +4,12 @@ interface utils { /// Provides information about the supported language versions and the grammar. resource language-facts { /// Returns a list of language versions supported by Slang, sorted ascendingly. - supported-versions: static func() -> list; + all-versions: static func() -> list; + + /// Returns the earliest language version supported by Slang. + earliest-version: static func() -> string; + + /// Returns the latest language version supported by Slang. + latest-version: static func() -> string; } } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs index c1d50b6098..7ff4c5af2f 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs @@ -16,6 +16,7 @@ mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Cursor, NonterminalNode, }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::ParseError; } mod rust { @@ -118,6 +119,10 @@ define_rc_wrapper! { File { self._borrow_ffi().tree().to_owned()._into_ffi() } + fn errors(&self) -> Vec { + self._borrow_ffi().errors().iter().map(|e| e.clone()._into_ffi()).collect() + } + fn create_tree_cursor(&self) -> ffi::Cursor { self._borrow_ffi().create_tree_cursor()._into_ffi() } diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs index deca6e2bb4..2964feb134 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs @@ -65,12 +65,16 @@ enum_to_enum!(TerminalKind); pub struct TerminalKindExtensionsWrapper; impl ffi::GuestTerminalKindExtensions for TerminalKindExtensionsWrapper { + fn is_identifier(kind: ffi::TerminalKind) -> bool { + crate::rust_crate::cst::TerminalKindExtensions::is_identifier(kind._from_ffi()) + } + fn is_trivia(kind: ffi::TerminalKind) -> bool { - crate::rust_crate::cst::TerminalKindExtensions::is_trivia(&kind._from_ffi()) + crate::rust_crate::cst::TerminalKindExtensions::is_trivia(kind._from_ffi()) } fn is_valid(kind: ffi::TerminalKind) -> bool { - crate::rust_crate::cst::TerminalKindExtensions::is_valid(&kind._from_ffi()) + crate::rust_crate::cst::TerminalKindExtensions::is_valid(kind._from_ffi()) } } @@ -98,6 +102,16 @@ impl IntoFFI for rust::Node { } } +impl FromFFI for ffi::Node { + #[inline] + fn _from_ffi(self) -> rust::Node { + match self { + ffi::Node::Nonterminal(node) => rust::Node::Nonterminal(node._from_ffi()), + ffi::Node::Terminal(node) => rust::Node::Terminal(node._from_ffi()), + } + } +} + //================================================ // // resource nonterminal-node @@ -134,7 +148,7 @@ define_rc_wrapper! { NonterminalNode { } fn create_cursor(&self, text_offset: ffi::TextIndex) -> ffi::Cursor { - std::rc::Rc::clone(self._borrow_ffi()).cursor_with_offset(text_offset._from_ffi())._into_ffi() + std::rc::Rc::clone(self._borrow_ffi()).create_cursor(text_offset._from_ffi())._into_ffi() } } } @@ -190,6 +204,16 @@ impl IntoFFI for rust::Edge { } } +impl FromFFI for ffi::Edge { + #[inline] + fn _from_ffi(self) -> rust::Edge { + rust::Edge { + label: self.label.map(FromFFI::_from_ffi), + node: self.node._from_ffi(), + } + } +} + //================================================ // // resource cursor @@ -277,8 +301,8 @@ define_refcell_wrapper! { Cursor { self._borrow_mut_ffi().go_to_last_child() } - fn go_to_nth_child(&self, child_number: u32) -> bool { - self._borrow_mut_ffi().go_to_nth_child(child_number as usize) + fn go_to_nth_child(&self, child_index: u32) -> bool { + self._borrow_mut_ffi().go_to_nth_child(child_index as usize) } fn go_to_next_sibling(&self) -> bool { @@ -355,8 +379,8 @@ define_refcell_wrapper! { AncestorsIterator { //================================================ define_wrapper! { Query { - fn parse(text: String) -> Result { - rust::Query::parse(&text).map_err(IntoFFI::_into_ffi).map(IntoFFI::_into_ffi) + fn create(text: String) -> Result { + rust::Query::create(&text).map_err(IntoFFI::_into_ffi).map(IntoFFI::_into_ffi) } } } @@ -371,8 +395,7 @@ impl IntoFFI for rust::QueryError { fn _into_ffi(self) -> ffi::QueryError { ffi::QueryError { message: self.message, - line: self.line.try_into().unwrap(), - column: self.column.try_into().unwrap(), + text_range: self.text_range._into_ffi(), } } } @@ -399,7 +422,7 @@ impl IntoFFI for rust::QueryMatch { #[inline] fn _into_ffi(self) -> ffi::QueryMatch { ffi::QueryMatch { - query_number: self.query_number.try_into().unwrap(), + query_index: self.query_index.try_into().unwrap(), captures: self .captures .into_iter() diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs index 01e073bb8d..bceb928319 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs @@ -6,11 +6,11 @@ use crate::wasm_crate::utils::{define_wrapper, FromFFI, IntoFFI}; mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ - Cursor, NonterminalNode, TextRange, + Cursor, NonterminalNode, }; pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::{ - Guest, GuestParseError, GuestParseOutput, GuestParser, NonterminalKind, ParseError, - ParseErrorBorrow, ParseOutput, ParseOutputBorrow, Parser, ParserBorrow, + Guest, GuestParseOutput, GuestParser, NonterminalKind, ParseError, ParseOutput, + ParseOutputBorrow, Parser, ParserBorrow, }; } @@ -20,7 +20,6 @@ mod rust { impl ffi::Guest for crate::wasm_crate::World { type Parser = ParserWrapper; - type ParseError = ParseErrorWrapper; type ParseOutput = ParseOutputWrapper; } @@ -31,10 +30,6 @@ impl ffi::Guest for crate::wasm_crate::World { //================================================ define_wrapper! { Parser { - fn root_kind() -> ffi::NonterminalKind { - rust::Parser::ROOT_KIND._into_ffi() - } - fn create(language_version: String) -> Result { semver::Version::parse(&language_version) .map_err(|_| format!("Invalid semantic version: '{language_version}'")) @@ -46,26 +41,30 @@ define_wrapper! { Parser { self._borrow_ffi().language_version().to_string() } - fn parse(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { - self._borrow_ffi().parse(kind._from_ffi(), &input)._into_ffi() + fn parse_file_contents(&self, input: String) -> ffi::ParseOutput { + self._borrow_ffi().parse_file_contents(&input)._into_ffi() + } + + fn parse_nonterminal(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { + self._borrow_ffi().parse_nonterminal(kind._from_ffi(), &input)._into_ffi() } } } //================================================ // -// resource parse-error +// record parse-error // //================================================ -define_wrapper! { ParseError { - fn text_range(&self) -> ffi::TextRange { - self._borrow_ffi().text_range()._into_ffi() +impl IntoFFI for rust::ParseError { + #[inline] + fn _into_ffi(self) -> ffi::ParseError { + ffi::ParseError { + message: self.message(), + text_range: self.text_range()._into_ffi(), + } } - - fn message(&self) -> String { - self._borrow_ffi().message() - } -} } +} //================================================ // diff --git a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs index b478ca4299..e89308b6de 100644 --- a/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs +++ b/crates/solidity/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs @@ -1,5 +1,7 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use semver::Version; + use crate::wasm_crate::utils::define_wrapper; mod ffi { @@ -23,10 +25,18 @@ impl ffi::Guest for crate::wasm_crate::World { //================================================ define_wrapper! { LanguageFacts { - fn supported_versions() -> Vec { - rust::LanguageFacts::SUPPORTED_VERSIONS + fn all_versions() -> Vec { + rust::LanguageFacts::ALL_VERSIONS .iter() - .map(|v| v.to_string()) + .map(Version::to_string) .collect() } + + fn earliest_version() -> String { + rust::LanguageFacts::EARLIEST_VERSION.to_string() + } + + fn latest_version() -> String { + rust::LanguageFacts::LATEST_VERSION.to_string() + } } } diff --git a/crates/solidity/outputs/npm/package/src/generated/parser/index.mts b/crates/solidity/outputs/npm/package/src/generated/parser/index.mts index 065b3eba7a..d419c657ee 100644 --- a/crates/solidity/outputs/npm/package/src/generated/parser/index.mts +++ b/crates/solidity/outputs/npm/package/src/generated/parser/index.mts @@ -7,8 +7,6 @@ export const Parser = wasm.parser.Parser; /** {@inheritDoc wasm.parser.Parser} */ export type Parser = wasm.parser.Parser; -/** {@inheritDoc wasm.parser.ParseError} */ -export const ParseError = wasm.parser.ParseError; /** {@inheritDoc wasm.parser.ParseError} */ export type ParseError = wasm.parser.ParseError; diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts index 9cfdd7498c..9c05d8998f 100644 --- a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts @@ -38,13 +38,17 @@ export enum BindingLocationType { */ export class BindingGraph { /** - * If the provided cursor points at a definition `Identifier`, it will return the - * corresponding definition. Otherwise, it will return `undefined`. + * Tries to resolve the identifier terminal pointed at by the provided cursor to a definition. + * If successful, returns the definition. Otherwise, returns `undefined`. + * + * For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. */ definitionAt(cursor: Cursor): Definition | undefined; /** - * If the provided cursor points at a reference `Identifier`, it will return the - * corresponding reference. Otherwise, it will return `undefined`. + * Tries to resolve the identifier terminal pointed at by the provided cursor to a reference. + * If successful, returns the reference. Otherwise, returns `undefined`. + * + * For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. */ referenceAt(cursor: Cursor): Reference | undefined; } diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts index c08b1eed29..61ed78a016 100644 --- a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts @@ -11,6 +11,8 @@ import type { NonterminalNode } from "./nomic-foundation-slang-cst.js"; export { NonterminalNode }; import type { Cursor } from "./nomic-foundation-slang-cst.js"; export { Cursor }; +import type { ParseError } from "./nomic-foundation-slang-parser.js"; +export { ParseError }; /** * Contains information about imports found in an added source file. */ @@ -65,6 +67,10 @@ export class File { * Returns the syntax tree of this file. */ get tree(): NonterminalNode; + /** + * Returns a list of all errors encountered during parsing this file. + */ + errors(): ParseError[]; /** * Creates a cursor for traversing the syntax tree of this file. */ diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts index dace5c2c60..5396c7ff46 100644 --- a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts @@ -6389,30 +6389,13 @@ export interface Edge { node: Node; } /** - * Represents an error that occurred while parsing a query. - */ -export interface QueryError { - /** - * The error message describing what went wrong. - */ - message: string; - /** - * The line number where the error occurred. - */ - line: number; - /** - * The column number where the error occurred. - */ - column: number; -} -/** - * Represents a match found by executing a query. + * Represents a match found by executing queries on a cursor. */ export interface QueryMatch { /** * The index of the query that produced this match. */ - queryNumber: number; + queryIndex: number; /** * List of captured nodes and their names from the query. */ @@ -6461,6 +6444,19 @@ export interface TextRange { */ end: TextIndex; } +/** + * Represents an error that occurred while parsing a query. + */ +export interface QueryError { + /** + * A human-readable message describing what went wrong. + */ + message: string; + /** + * The text range where the error occurred in the query code. + */ + textRange: TextRange; +} /** * Iterator over all ancestors of the current node, starting with the immediate parent, and moving upwards, ending with the root node. @@ -6566,7 +6562,7 @@ export class Cursor { /** * Moves to the nth child of the current node. */ - goToNthChild(childNumber: number): boolean; + goToNthChild(childIndex: number): boolean; /** * Moves to the next sibling node. */ @@ -6694,7 +6690,7 @@ export class Query { * Parses a query string into a query object. * Throws an error if the query syntax is invalid. */ - static parse(text: string): Query; + static create(text: string): Query; } /** @@ -6716,11 +6712,15 @@ export class QueryMatchIterator { */ export class TerminalKindExtensions { /** - * Returns true if the terminal is a trivia token. i.e. whitespace, comments, etc... + * Returns `true` if the terminal is an identifier token. + */ + static isIdentifier(kind: TerminalKind): boolean; + /** + * Returns `true` if the terminal is a trivia token. i.e. whitespace, comments, etc... */ static isTrivia(kind: TerminalKind): boolean; /** - * Returns true if the terminal is a valid token in the language grammar. + * Returns `true` if the terminal is a valid token in the language grammar. */ static isValid(kind: TerminalKind): boolean; } diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts index 07fe4156a6..8382b6ed99 100644 --- a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts @@ -2,7 +2,6 @@ export namespace NomicFoundationSlangParser { export { Parser }; - export { ParseError }; export { ParseOutput }; } import type { Cursor } from "./nomic-foundation-slang-cst.js"; @@ -13,19 +12,18 @@ import type { NonterminalKind } from "./nomic-foundation-slang-cst.js"; export { NonterminalKind }; import type { TextRange } from "./nomic-foundation-slang-cst.js"; export { TextRange }; - /** - * Contains information about where the error occurred and what went wrong. + * Represents an error that occurred while parsing source code. */ -export class ParseError { +export interface ParseError { /** - * Returns the text range where the error occurred in the source code. + * A human-readable message describing what went wrong. */ - get textRange(): TextRange; + message: string; /** - * Returns a human-readable message describing the parsing error. + * The text range where the error occurred in the source code. */ - get message(): string; + textRange: TextRange; } /** @@ -40,7 +38,7 @@ export class ParseOutput { get tree(): NonterminalNode; /** * Returns a list of all parsing errors encountered. - * An empty list indicates successful parsing with no errors. + * An empty list indicates a successful parse with no errors. */ errors(): ParseError[]; /** @@ -60,11 +58,6 @@ export class ParseOutput { * Each parser is configured for a specific language version and grammar. */ export class Parser { - /** - * Returns the root nonterminal kind for this parser's grammar. - * This represents the starting point for parsing a complete source file. - */ - static rootKind(): NonterminalKind; /** * Creates a new parser instance for the specified language version. */ @@ -74,7 +67,11 @@ export class Parser { */ get languageVersion(): string; /** - * Parses the input string starting from the specified nonterminal kind. + * Parses the input string into a complete source file. + */ + parseFileContents(input: string): ParseOutput; + /** + * Parses the input string into a nonterminal with the specified kind. */ - parse(kind: NonterminalKind, input: string): ParseOutput; + parseNonterminal(kind: NonterminalKind, input: string): ParseOutput; } diff --git a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts index 0a3e19de1c..9010760119 100644 --- a/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts +++ b/crates/solidity/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts @@ -11,5 +11,13 @@ export class LanguageFacts { /** * Returns a list of language versions supported by Slang, sorted ascendingly. */ - static supportedVersions(): string[]; + static allVersions(): string[]; + /** + * Returns the earliest language version supported by Slang. + */ + static earliestVersion(): string; + /** + * Returns the latest language version supported by Slang. + */ + static latestVersion(): string; } diff --git a/crates/solidity/outputs/npm/package/wasm/generated/solidity_cargo_wasm.component.d.ts b/crates/solidity/outputs/npm/package/wasm/generated/solidity_cargo_wasm.component.d.ts index 959f0ad174..0e3bde1a8b 100644 --- a/crates/solidity/outputs/npm/package/wasm/generated/solidity_cargo_wasm.component.d.ts +++ b/crates/solidity/outputs/npm/package/wasm/generated/solidity_cargo_wasm.component.d.ts @@ -3,12 +3,12 @@ import { NomicFoundationSlangCst } from "./interfaces/nomic-foundation-slang-cst.js"; import { NomicFoundationSlangAst } from "./interfaces/nomic-foundation-slang-ast.js"; import { NomicFoundationSlangBindings } from "./interfaces/nomic-foundation-slang-bindings.js"; -import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangParser } from "./interfaces/nomic-foundation-slang-parser.js"; +import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangUtils } from "./interfaces/nomic-foundation-slang-utils.js"; export * as cst from "./interfaces/nomic-foundation-slang-cst.js"; export * as ast from "./interfaces/nomic-foundation-slang-ast.js"; export * as bindings from "./interfaces/nomic-foundation-slang-bindings.js"; -export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as parser from "./interfaces/nomic-foundation-slang-parser.js"; +export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as utils from "./interfaces/nomic-foundation-slang-utils.js"; diff --git a/crates/solidity/outputs/npm/tests/src/compilation/binding-graph.test.mts b/crates/solidity/outputs/npm/tests/src/compilation/binding-graph.test.mts index 085833e71a..7ab08a9c8b 100644 --- a/crates/solidity/outputs/npm/tests/src/compilation/binding-graph.test.mts +++ b/crates/solidity/outputs/npm/tests/src/compilation/binding-graph.test.mts @@ -1,7 +1,6 @@ import assert from "node:assert"; import { NonterminalKind, TerminalKind } from "@nomicfoundation/slang/cst"; -import { createBuilder } from "./common.mjs"; -import { BindingLocation } from "@nomicfoundation/slang/bindings"; +import { assertUserFileLocation, createBuilder } from "./common.mjs"; test("binding graph", async () => { const builder = await createBuilder(); @@ -108,16 +107,3 @@ test("binding graph", async () => { // Done! No more identifiers in the file. assert(!cursor.goToNextTerminalWithKind(TerminalKind.Identifier)); }); - -function assertUserFileLocation( - location: BindingLocation, - fileId: string, - kind: TerminalKind | NonterminalKind, - line: number, -) { - assert(location.isUserFileLocation()); - - assert.equal(location.fileId, fileId); - assert.equal(location.cursor.node.kind, kind); - assert.equal(location.cursor.textRange.start.line, line); -} diff --git a/crates/solidity/outputs/npm/tests/src/compilation/common.mts b/crates/solidity/outputs/npm/tests/src/compilation/common.mts index ea7805da0b..d34715482d 100644 --- a/crates/solidity/outputs/npm/tests/src/compilation/common.mts +++ b/crates/solidity/outputs/npm/tests/src/compilation/common.mts @@ -2,6 +2,8 @@ import path from "node:path"; import assert from "node:assert"; import { CompilationBuilder } from "@nomicfoundation/slang/compilation"; import { readRepoFile } from "../utils/files.mjs"; +import { BindingLocation } from "@nomicfoundation/slang/bindings"; +import { NonterminalKind, TerminalKind } from "@nomicfoundation/slang/cst"; export async function createBuilder(): Promise { const builder = CompilationBuilder.create({ @@ -23,3 +25,16 @@ export async function createBuilder(): Promise { return builder; } + +export function assertUserFileLocation( + location: BindingLocation, + fileId: string, + kind: TerminalKind | NonterminalKind, + line: number, +) { + assert(location.isUserFileLocation()); + + assert.equal(location.fileId, fileId); + assert.equal(location.cursor.node.kind, kind); + assert.equal(location.cursor.textRange.start.line, line); +} diff --git a/crates/solidity/outputs/npm/tests/src/compilation/inputs/with-errors.sol b/crates/solidity/outputs/npm/tests/src/compilation/inputs/with-errors.sol new file mode 100644 index 0000000000..390fa12863 --- /dev/null +++ b/crates/solidity/outputs/npm/tests/src/compilation/inputs/with-errors.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity x.x.x; + +contract WithErrors { + function noBody() +} diff --git a/crates/solidity/outputs/npm/tests/src/compilation/unit.test.mts b/crates/solidity/outputs/npm/tests/src/compilation/unit.test.mts new file mode 100644 index 0000000000..789eae342d --- /dev/null +++ b/crates/solidity/outputs/npm/tests/src/compilation/unit.test.mts @@ -0,0 +1,32 @@ +import assert from "node:assert"; +import { NonterminalKind, TerminalKind } from "@nomicfoundation/slang/cst"; +import { assertUserFileLocation, createBuilder } from "./common.mjs"; + +test("retains language version", async () => { + const builder = await createBuilder(); + const unit = builder.build(); + + assert.equal(unit.languageVersion, "0.8.0"); +}); + +test("can handle files with errors", async () => { + const builder = await createBuilder(); + await builder.addFile("with-errors.sol"); + + const unit = builder.build(); + const file = unit.file("with-errors.sol")!; + + const errors = file.errors(); + assert.equal(errors.length, 1); + assert.equal(errors[0]!.message, "Expected OpenBrace or ReturnsKeyword or Semicolon."); + + assert.equal(file.tree.kind, NonterminalKind.SourceUnit); + + const cursor = file.createTreeCursor(); + assert(cursor.goToNextTerminalWithKind(TerminalKind.Identifier)); + assert.equal(cursor.node.unparse(), "WithErrors"); + + const definition = unit.bindingGraph.definitionAt(cursor)!; + assertUserFileLocation(definition.nameLocation, "with-errors.sol", TerminalKind.Identifier, 3); + assertUserFileLocation(definition.definiensLocation, "with-errors.sol", NonterminalKind.ContractDefinition, 2); +}); diff --git a/crates/solidity/outputs/npm/tests/src/doc-examples/using-queries.test.mts b/crates/solidity/outputs/npm/tests/src/doc-examples/using-queries.test.mts index 445b678207..e3958ff613 100644 --- a/crates/solidity/outputs/npm/tests/src/doc-examples/using-queries.test.mts +++ b/crates/solidity/outputs/npm/tests/src/doc-examples/using-queries.test.mts @@ -2,12 +2,12 @@ import { readRepoFile } from "../utils/files.mjs"; import assert from "node:assert"; import { Parser } from "@nomicfoundation/slang/parser"; -import { assertIsNonterminalNode, NonterminalKind, Query, QueryMatchIterator } from "@nomicfoundation/slang/cst"; +import { assertIsNonterminalNode, Query, QueryMatchIterator } from "@nomicfoundation/slang/cst"; async function parseDocInputFile(relativePath: string) { const source = await readRepoFile("documentation/public/user-guide/inputs", relativePath); const parser = Parser.create("0.8.0"); - return parser.parse(NonterminalKind.SourceUnit, source); + return parser.parseFileContents(source); } test("using queries", async () => { @@ -17,7 +17,7 @@ test("using queries", async () => { // Any `Cursor` can be used to create a query. const cursor = parseOutput.createTreeCursor(); - const query = Query.parse("[ContractDefinition]"); + const query = Query.create("[ContractDefinition]"); const matches: QueryMatchIterator = cursor.query([query]); // --8<-- [end:creating-a-query] @@ -31,7 +31,7 @@ test("using queries", async () => { // --8<-- [start:visiting-contracts] const found = []; - const query = Query.parse("@contract [ContractDefinition]"); + const query = Query.create("@contract [ContractDefinition]"); const matches = cursor.query([query]); for (const match of matches) { @@ -52,12 +52,12 @@ test("using queries", async () => { // --8<-- [start:multiple-patterns] const names = []; - const structDefinition = Query.parse("[StructDefinition @name [Identifier]]"); - const enumDefinition = Query.parse("[EnumDefinition @name [Identifier]]"); + const structDefinition = Query.create("[StructDefinition @name [Identifier]]"); + const enumDefinition = Query.create("[EnumDefinition @name [Identifier]]"); const matches = cursor.query([structDefinition, enumDefinition]); for (const match of matches) { - const index = match.queryNumber; + const index = match.queryIndex; const cursor = match.captures["name"]![0]!; names.push([index, cursor.node.unparse()]); @@ -79,7 +79,7 @@ test("using queries", async () => { // --8<-- [start:matching-on-label] const names = []; - const query = Query.parse("[TypedTupleMember @type type_name:[_]]"); + const query = Query.create("[TypedTupleMember @type type_name:[_]]"); const matches = cursor.query([query]); for (const match of matches) { @@ -100,7 +100,7 @@ test("using queries", async () => { // --8<-- [start:matching-on-literal-value] const names = []; - const query = Query.parse(`[ElementaryType @uint_keyword variant:["uint"]]`); + const query = Query.create(`[ElementaryType @uint_keyword variant:["uint"]]`); const matches = cursor.query([query]); for (const match of matches) { @@ -118,7 +118,7 @@ test("using queries", async () => { const cursor = parseOutput.createTreeCursor(); // --8<-- [start:tx-origin] - const query = Query.parse(` + const query = Query.create(` @txorigin [MemberAccessExpression [Expression @start ["tx"]] ["origin"] diff --git a/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-ast.test.mts b/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-ast.test.mts index 7cf8e91008..b2685c7432 100644 --- a/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-ast.test.mts +++ b/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-ast.test.mts @@ -13,7 +13,7 @@ test("using the ast", async () => { // --8<-- [start:parse-input] const parser = Parser.create("0.8.0"); - const parseOutput = parser.parse(NonterminalKind.FunctionDefinition, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.FunctionDefinition, source); // --8<-- [end:parse-input] // --8<-- [start:create-node] diff --git a/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-cursor.test.mts b/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-cursor.test.mts index ea98c8233b..4bb9b74637 100644 --- a/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-cursor.test.mts +++ b/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-cursor.test.mts @@ -12,7 +12,7 @@ test("using the cursor", async () => { // --8<-- [start:parse-input] const parser = Parser.create("0.8.0"); - const parseOutput = parser.parse(NonterminalKind.SourceUnit, source); + const parseOutput = parser.parseFileContents(source); // --8<-- [end:parse-input] { diff --git a/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-parser.test.mts b/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-parser.test.mts index 7f07b11cf6..2fccd9c0c7 100644 --- a/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-parser.test.mts +++ b/crates/solidity/outputs/npm/tests/src/doc-examples/using-the-parser.test.mts @@ -17,7 +17,7 @@ test("using the parser", async () => { // --8<-- [start:parse-input] const parser = Parser.create("0.8.0"); - const parseOutput = parser.parse(NonterminalKind.ContractDefinition, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.ContractDefinition, source); // --8<-- [end:parse-input] // --8<-- [start:print-errors] diff --git a/crates/solidity/testing/perf/src/tests/bindings_resolve.rs b/crates/solidity/testing/perf/src/tests/bindings_resolve.rs index ec84c6c1dd..669d9c54c6 100644 --- a/crates/solidity/testing/perf/src/tests/bindings_resolve.rs +++ b/crates/solidity/testing/perf/src/tests/bindings_resolve.rs @@ -2,7 +2,7 @@ use std::rc::Rc; use infra_utils::paths::PathExtensions; use slang_solidity::bindings::BindingGraph; -use slang_solidity::cst::{NonterminalKind, TerminalKind}; +use slang_solidity::cst::{NodeKind, NonterminalKind, TerminalKindExtensions}; use crate::tests::parser::ParsedFile; @@ -30,10 +30,11 @@ pub fn run(dependencies: BuiltBindingGraph) { for file in files { let mut cursor = file.parse_output.create_tree_cursor(); - while cursor.go_to_next_terminal_with_kinds(&[ - TerminalKind::Identifier, - TerminalKind::YulIdentifier, - ]) { + while cursor.go_to_next_terminal() { + if !matches!(cursor.node().kind(), NodeKind::Terminal(kind) if kind.is_identifier()) { + continue; + } + if matches!( cursor.ancestors().next(), Some(ancestor) diff --git a/crates/solidity/testing/perf/src/tests/parser.rs b/crates/solidity/testing/perf/src/tests/parser.rs index 1eecbec387..057f3e2a05 100644 --- a/crates/solidity/testing/perf/src/tests/parser.rs +++ b/crates/solidity/testing/perf/src/tests/parser.rs @@ -24,7 +24,7 @@ pub fn run(files: Vec) -> Vec { let mut results = vec![]; for SourceFile { path, contents } in files { - let parse_output = parser.parse(Parser::ROOT_KIND, &contents); + let parse_output = parser.parse_file_contents(&contents); assert!( parse_output.is_valid(), diff --git a/crates/solidity/testing/perf/src/tests/query.rs b/crates/solidity/testing/perf/src/tests/query.rs index 6e4da38a5e..9181485b2f 100644 --- a/crates/solidity/testing/perf/src/tests/query.rs +++ b/crates/solidity/testing/perf/src/tests/query.rs @@ -11,7 +11,7 @@ pub fn setup() -> Vec { pub fn run(files: Vec) { let mut functions_count = 0; - let queries = vec![Query::parse( + let queries = vec![Query::create( "[FunctionDefinition @name name: [_] ]", diff --git a/crates/solidity/testing/sanctuary/src/tests.rs b/crates/solidity/testing/sanctuary/src/tests.rs index 87a59f020f..97599228bb 100644 --- a/crates/solidity/testing/sanctuary/src/tests.rs +++ b/crates/solidity/testing/sanctuary/src/tests.rs @@ -8,7 +8,9 @@ use itertools::Itertools; use metaslang_bindings::PathResolver; use semver::Version; use slang_solidity::bindings::{self, BindingGraph}; -use slang_solidity::cst::{Cursor, KindTypes, NonterminalKind, TerminalKind, TextRange}; +use slang_solidity::cst::{ + Cursor, KindTypes, NodeKind, NonterminalKind, TerminalKindExtensions, TextRange, +}; use slang_solidity::diagnostic::{Diagnostic, Severity}; use slang_solidity::parser::{ParseOutput, Parser}; use slang_solidity::utils::LanguageFacts; @@ -104,7 +106,7 @@ pub fn run_test(file: &SourceFile, events: &Events, check_bindings: bool) -> Res .replace("'", "\""); let parser = Parser::create(version.clone())?; - let output = parser.parse(NonterminalKind::SourceUnit, &source); + let output = parser.parse_file_contents(&source); let source_id = file.path.strip_repo_root()?.unwrap_str(); let with_color = true; @@ -152,7 +154,7 @@ fn extract_compiler_version(compiler: &str) -> Option { panic!("Unrecognized compiler/version: '{compiler}'"); }; - if &version < LanguageFacts::SUPPORTED_VERSIONS.first().unwrap() { + if version < LanguageFacts::EARLIEST_VERSION { // Version is too early: return None; } @@ -201,13 +203,15 @@ fn run_bindings_check( } } - // Check that all `Identifier` and `YulIdentifier` nodes are bound to either a definition or a reference: + // Check that all identifier nodes are bound to either a definition or a reference: let mut cursor = output.create_tree_cursor(); - while cursor - .go_to_next_terminal_with_kinds(&[TerminalKind::Identifier, TerminalKind::YulIdentifier]) - { + while cursor.go_to_next_terminal() { + if !matches!(cursor.node().kind(), NodeKind::Terminal(kind) if kind.is_identifier()) { + continue; + } + if matches!( cursor.ancestors().next(), Some(ancestor) diff --git a/crates/testlang/outputs/cargo/crate/src/generated/compilation/file.rs b/crates/testlang/outputs/cargo/crate/src/generated/compilation/file.rs index 2f5fd5bcc3..7a5bf8ed41 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/compilation/file.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/compilation/file.rs @@ -6,20 +6,25 @@ use std::rc::Rc; use metaslang_cst::text_index::TextIndex; use crate::cst::{Cursor, NonterminalNode}; +use crate::parser::{ParseError, ParseOutput}; #[derive(Clone)] pub struct File { id: String, tree: Rc, + errors: Vec, resolved_imports: BTreeMap, } impl File { - pub(super) fn new(id: String, tree: Rc) -> Self { + pub(super) fn create(id: String, parse_output: ParseOutput) -> Self { + let ParseOutput { tree, errors } = parse_output; + Self { id, tree, + errors, resolved_imports: BTreeMap::new(), } @@ -33,8 +38,12 @@ impl File { &self.tree } + pub fn errors(&self) -> &Vec { + &self.errors + } + pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).create_cursor(TextIndex::ZERO) } pub(super) fn resolve_import(&mut self, import_path: &Cursor, destination_file_id: String) { diff --git a/crates/testlang/outputs/cargo/crate/src/generated/compilation/internal_builder.rs b/crates/testlang/outputs/cargo/crate/src/generated/compilation/internal_builder.rs index a0c2ec5e73..c10f90ceae 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/compilation/internal_builder.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/compilation/internal_builder.rs @@ -41,11 +41,11 @@ impl InternalCompilationBuilder { }; } - let parse_output = self.parser.parse(Parser::ROOT_KIND, contents); + let parse_output = self.parser.parse_file_contents(contents); let import_paths = self.imports.extract(parse_output.create_tree_cursor()); - let file = File::new(id.clone(), Rc::clone(parse_output.tree())); + let file = File::create(id.clone(), parse_output); self.files.insert(id, file); AddFileResponse { import_paths } @@ -74,7 +74,7 @@ impl InternalCompilationBuilder { .map(|(id, file)| (id.to_owned(), Rc::new(file.to_owned()))) .collect(); - CompilationUnit::new(language_version, files) + CompilationUnit::create(language_version, files) } } diff --git a/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs b/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs index 4e92751737..312aef257a 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/compilation/unit.rs @@ -19,7 +19,7 @@ pub struct CompilationUnit { } impl CompilationUnit { - pub(super) fn new(language_version: Version, files: BTreeMap>) -> Self { + pub(super) fn create(language_version: Version, files: BTreeMap>) -> Self { Self { language_version, files, diff --git a/crates/testlang/outputs/cargo/crate/src/generated/cst/generated/terminal_kind.rs b/crates/testlang/outputs/cargo/crate/src/generated/cst/generated/terminal_kind.rs index 33b232d19d..aebb91f001 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/cst/generated/terminal_kind.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/cst/generated/terminal_kind.rs @@ -110,13 +110,18 @@ pub enum TerminalKind { } impl crate::cst::TerminalKindExtensions for TerminalKind { - fn is_trivia(&self) -> bool { + fn is_identifier(self) -> bool { + matches!( + self,| Self::Identifier) + } + + fn is_trivia(self) -> bool { matches!(self, |Self::EndOfLine| Self::MultiLineComment | Self::SingleLineComment | Self::Whitespace) } - fn is_valid(&self) -> bool { + fn is_valid(self) -> bool { !matches!(self, Self::UNRECOGNIZED | Self::MISSING) } } diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/generated/parser.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/generated/parser.rs index a7fcd186f0..44b7927742 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/generated/parser.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/generated/parser.rs @@ -43,12 +43,10 @@ pub enum ParserInitializationError { } impl Parser { - pub const ROOT_KIND: NonterminalKind = NonterminalKind::SourceUnit; - pub fn create( language_version: Version, ) -> std::result::Result { - if LanguageFacts::SUPPORTED_VERSIONS + if LanguageFacts::ALL_VERSIONS .binary_search(&language_version) .is_ok() { @@ -65,9 +63,42 @@ impl Parser { pub fn language_version(&self) -> &Version { &self.language_version - } /******************************************** - * Parser Functions - ********************************************/ + } + + pub fn parse_file_contents(&self, input: &str) -> ParseOutput { + self.parse_nonterminal(NonterminalKind::SourceUnit, input) + } + pub fn parse_nonterminal(&self, kind: NonterminalKind, input: &str) -> ParseOutput { + match kind { + NonterminalKind::AdditionExpression => { + Self::addition_expression.parse(self, input, kind) + } + NonterminalKind::Expression => Self::expression.parse(self, input, kind), + NonterminalKind::Literal => Self::literal.parse(self, input, kind), + NonterminalKind::MemberAccessExpression => { + Self::member_access_expression.parse(self, input, kind) + } + NonterminalKind::NegationExpression => { + Self::negation_expression.parse(self, input, kind) + } + NonterminalKind::SeparatedIdentifiers => { + Self::separated_identifiers.parse(self, input, kind) + } + NonterminalKind::SourceUnit => Self::source_unit.parse(self, input, kind), + NonterminalKind::SourceUnitMember => Self::source_unit_member.parse(self, input, kind), + NonterminalKind::SourceUnitMembers => { + Self::source_unit_members.parse(self, input, kind) + } + NonterminalKind::Tree => Self::tree.parse(self, input, kind), + NonterminalKind::TreeNode => Self::tree_node.parse(self, input, kind), + NonterminalKind::TreeNodeChild => Self::tree_node_child.parse(self, input, kind), + NonterminalKind::TreeNodeChildren => Self::tree_node_children.parse(self, input, kind), + } + } + + /******************************************** + * Parser Functions + ********************************************/ #[allow(unused_assignments, unused_parens)] fn addition_expression(&self, input: &mut ParserContext<'_>) -> ParserResult { @@ -646,34 +677,6 @@ impl Parser { scan_choice!(input, scan_chars!(input, ' '), scan_chars!(input, '\t')) ) } - - pub fn parse(&self, kind: NonterminalKind, input: &str) -> ParseOutput { - match kind { - NonterminalKind::AdditionExpression => { - Self::addition_expression.parse(self, input, kind) - } - NonterminalKind::Expression => Self::expression.parse(self, input, kind), - NonterminalKind::Literal => Self::literal.parse(self, input, kind), - NonterminalKind::MemberAccessExpression => { - Self::member_access_expression.parse(self, input, kind) - } - NonterminalKind::NegationExpression => { - Self::negation_expression.parse(self, input, kind) - } - NonterminalKind::SeparatedIdentifiers => { - Self::separated_identifiers.parse(self, input, kind) - } - NonterminalKind::SourceUnit => Self::source_unit.parse(self, input, kind), - NonterminalKind::SourceUnitMember => Self::source_unit_member.parse(self, input, kind), - NonterminalKind::SourceUnitMembers => { - Self::source_unit_members.parse(self, input, kind) - } - NonterminalKind::Tree => Self::tree.parse(self, input, kind), - NonterminalKind::TreeNode => Self::tree_node.parse(self, input, kind), - NonterminalKind::TreeNodeChild => Self::tree_node_child.parse(self, input, kind), - NonterminalKind::TreeNodeChildren => Self::tree_node_children.parse(self, input, kind), - } - } } impl Lexer for Parser { diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_error.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_error.rs index ba4aa54993..fd39e838ac 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_error.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_error.rs @@ -27,7 +27,7 @@ impl ParseError { } impl ParseError { - pub(crate) fn new( + pub(crate) fn create( text_range: TextRange, mut terminals_that_would_have_allowed_more_progress: Vec, ) -> Self { diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_output.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_output.rs index 790329c22b..5861eaefd1 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_output.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parse_output.rs @@ -26,6 +26,6 @@ impl ParseOutput { /// Creates a cursor that starts at the root of the parse tree. pub fn create_tree_cursor(&self) -> Cursor { - Rc::clone(&self.tree).cursor_with_offset(TextIndex::ZERO) + Rc::clone(&self.tree).create_cursor(TextIndex::ZERO) } } diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/choice_helper.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/choice_helper.rs index 2e14c5a35f..cd2189fa53 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/choice_helper.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/choice_helper.rs @@ -140,7 +140,7 @@ pub fn total_not_skipped_span(result: &ParserResult) -> usize { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .filter_map(|edge| match edge.node { diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs index 29d42e609d..6447edfcb9 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_function.rs @@ -91,8 +91,8 @@ where let node = Node::terminal(kind, input.to_string()); children.push(Edge::anonymous(node)); ParseOutput { - tree: Rc::new(NonterminalNode::new(topmost_kind, children)), - errors: vec![ParseError::new( + tree: NonterminalNode::create(topmost_kind, children), + errors: vec![ParseError::create( start..start + input.into(), no_match.expected_terminals, )], @@ -149,13 +149,13 @@ where let start_index = stream.text_index_at(start); let mut errors = stream.into_errors(); - errors.push(ParseError::new( + errors.push(ParseError::create( start_index..input.into(), expected_terminals, )); ParseOutput { - tree: Rc::new(NonterminalNode::new(topmost_node.kind, new_children)), + tree: NonterminalNode::create(topmost_node.kind, new_children), errors, } } else { @@ -166,7 +166,7 @@ where debug_assert_eq!( errors.is_empty(), Rc::clone(&tree) - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() .all(|edge| edge .as_terminal() diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_result.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_result.rs index 00666ec339..60a8b1c591 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_result.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/parser_result.rs @@ -134,7 +134,7 @@ impl Match { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .all(|edge| { @@ -215,7 +215,7 @@ impl IncompleteMatch { .flat_map(|edge| { edge.node .clone() - .cursor_with_offset(TextIndex::ZERO) + .create_cursor(TextIndex::ZERO) .remaining_nodes() }) .try_fold(0u8, |mut acc, edge| { diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/recovery.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/recovery.rs index f54ae45934..c8fc8f5c45 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/recovery.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/recovery.rs @@ -90,7 +90,10 @@ impl ParserResult { let skipped = input.content(skipped_range.utf8()); - input.emit(ParseError::new(skipped_range, expected_terminals.clone())); + input.emit(ParseError::create( + skipped_range, + expected_terminals.clone(), + )); ParserResult::SkippedUntil(SkippedUntil { nodes, diff --git a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/separated_helper.rs b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/separated_helper.rs index bcc5dc64f0..280e9062c0 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/separated_helper.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/parser/parser_support/separated_helper.rs @@ -62,7 +62,7 @@ impl SeparatedHelper { kind, input.content(skipped_range.utf8()), ))); - input.emit(ParseError::new( + input.emit(ParseError::create( skipped_range, incomplete.expected_terminals, )); diff --git a/crates/testlang/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs b/crates/testlang/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs index 9dea6c75c1..ba8029ca53 100644 --- a/crates/testlang/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs +++ b/crates/testlang/outputs/cargo/crate/src/generated/utils/generated/language_facts.rs @@ -5,12 +5,14 @@ use semver::Version; pub struct LanguageFacts; impl LanguageFacts { - pub const NAME: &'static str = "Testlang"; - - pub const SUPPORTED_VERSIONS: &'static [Version] = &[ + pub const ALL_VERSIONS: &'static [Version] = &[ Version::new(1, 0, 0), Version::new(1, 0, 1), Version::new(1, 1, 0), Version::new(1, 1, 1), ]; + + pub const EARLIEST_VERSION: Version = Version::new(1, 0, 0); + + pub const LATEST_VERSION: Version = Version::new(1, 1, 1); } diff --git a/crates/testlang/outputs/cargo/tests/src/graph/mod.rs b/crates/testlang/outputs/cargo/tests/src/bindings/mod.rs similarity index 92% rename from crates/testlang/outputs/cargo/tests/src/graph/mod.rs rename to crates/testlang/outputs/cargo/tests/src/bindings/mod.rs index da187539c8..305e4e3ae1 100644 --- a/crates/testlang/outputs/cargo/tests/src/graph/mod.rs +++ b/crates/testlang/outputs/cargo/tests/src/bindings/mod.rs @@ -2,7 +2,6 @@ use metaslang_graph_builder::ast::File; use metaslang_graph_builder::functions::Functions; use metaslang_graph_builder::{ExecutionConfig, NoCancellation, Variables}; use semver::Version; -use slang_testlang::cst::NonterminalKind; use slang_testlang::parser::Parser; #[test] @@ -36,7 +35,7 @@ fn builds_a_graph() { assert!(msgb.check().is_ok()); let source = "tree $t1 [A [B C]];"; - let parse_output = parser.parse(NonterminalKind::SourceUnit, source); + let parse_output = parser.parse_file_contents(source); assert!(parse_output.is_valid()); let tree = parse_output.create_tree_cursor(); diff --git a/crates/testlang/outputs/cargo/tests/src/cst/mod.rs b/crates/testlang/outputs/cargo/tests/src/cst/mod.rs new file mode 100644 index 0000000000..6a1604d3df --- /dev/null +++ b/crates/testlang/outputs/cargo/tests/src/cst/mod.rs @@ -0,0 +1 @@ +mod queries; diff --git a/crates/testlang/outputs/cargo/tests/src/query/engine_tests.rs b/crates/testlang/outputs/cargo/tests/src/cst/queries/engine_tests.rs similarity index 99% rename from crates/testlang/outputs/cargo/tests/src/query/engine_tests.rs rename to crates/testlang/outputs/cargo/tests/src/cst/queries/engine_tests.rs index 4b59d755ed..5a4ec6047b 100644 --- a/crates/testlang/outputs/cargo/tests/src/query/engine_tests.rs +++ b/crates/testlang/outputs/cargo/tests/src/cst/queries/engine_tests.rs @@ -83,8 +83,8 @@ macro_rules! query_matches { } fn run_query_test(tree: Edge, query: &str, matches: Vec>>) { - let cursor = tree.node.cursor_with_offset(TextIndex::ZERO); - let query = vec![Query::parse(query).unwrap()]; + let cursor = tree.node.create_cursor(TextIndex::ZERO); + let query = vec![Query::create(query).unwrap()]; let mut matches = matches.into_iter(); for QueryMatch { captures, .. } in cursor.query(query) { let captures = capture_cursors_to_strings(captures); diff --git a/crates/testlang/outputs/cargo/tests/src/query/mod.rs b/crates/testlang/outputs/cargo/tests/src/cst/queries/mod.rs similarity index 100% rename from crates/testlang/outputs/cargo/tests/src/query/mod.rs rename to crates/testlang/outputs/cargo/tests/src/cst/queries/mod.rs diff --git a/crates/testlang/outputs/cargo/tests/src/query/parser_tests.rs b/crates/testlang/outputs/cargo/tests/src/cst/queries/parser_tests.rs similarity index 72% rename from crates/testlang/outputs/cargo/tests/src/query/parser_tests.rs rename to crates/testlang/outputs/cargo/tests/src/cst/queries/parser_tests.rs index 4ea49c31b4..ab6828bed7 100644 --- a/crates/testlang/outputs/cargo/tests/src/query/parser_tests.rs +++ b/crates/testlang/outputs/cargo/tests/src/cst/queries/parser_tests.rs @@ -3,7 +3,7 @@ use slang_testlang::cst::Query; fn run_parser_test(input: &str, result: &str) { - assert_eq!(Query::parse(input).unwrap().to_string(), result); + assert_eq!(Query::create(input).unwrap().to_string(), result); } #[test] @@ -52,12 +52,15 @@ fn test_zero_or_more_canonicalisation() { // Test the error message on parse failure #[test] fn test_parsing_error() { - let result = Query::parse(r#"@root [_"#); + let result = Query::create(r#"@root [_"#); match result { Ok(_) => panic!("Expected error"), Err(e) => { assert_eq!(e.message, "Parse error:\nexpected ']' at: \nAlt at: [_\n"); - assert_eq!((e.line, e.column), (0, 8)); + assert_eq!( + format!("{:?}", e.text_range), + "TextIndex { utf8: 8, utf16: 8, line: 0, column: 8 }..TextIndex { utf8: 8, utf16: 8, line: 0, column: 8 }", + ); } } } @@ -65,7 +68,7 @@ fn test_parsing_error() { // See https://github.com/NomicFoundation/slang/issues/1042 #[test] fn test_parsing_error_with_invalid_edge_label() { - let result = Query::parse(r#"[Tree @name Name: [_]]"#); + let result = Query::create(r#"[Tree @name Name: [_]]"#); match result { Ok(_) => panic!("Expected error"), Err(e) => { @@ -73,14 +76,17 @@ fn test_parsing_error_with_invalid_edge_label() { e.message, "Parse error:\n'Name' is not a valid edge label at: Name: [_]]\n", ); - assert_eq!((e.line, e.column), (0, 12)); + assert_eq!( + format!("{:?}", e.text_range), + "TextIndex { utf8: 12, utf16: 12, line: 0, column: 12 }..TextIndex { utf8: 22, utf16: 22, line: 0, column: 22 }", + ); } } } #[test] fn test_parsing_error_with_invalid_node_kind() { - let result = Query::parse(r#"[Tree [tree_node]]"#); + let result = Query::create(r#"[Tree [tree_node]]"#); match result { Ok(_) => panic!("Expected error"), Err(e) => { @@ -88,14 +94,17 @@ fn test_parsing_error_with_invalid_node_kind() { e.message, "Parse error:\n'tree_node' is not a valid node kind at: tree_node]]\n", ); - assert_eq!((e.line, e.column), (0, 7)); + assert_eq!( + format!("{:?}", e.text_range), + "TextIndex { utf8: 7, utf16: 7, line: 0, column: 7 }..TextIndex { utf8: 18, utf16: 18, line: 0, column: 18 }", + ); } } } #[test] fn test_parsing_error_with_kind_beginning_with_underscore() { - let result = Query::parse(r#"[Tree [_tree_node]]"#); + let result = Query::create(r#"[Tree [_tree_node]]"#); match result { Ok(_) => panic!("Expected error"), Err(e) => { @@ -103,14 +112,17 @@ fn test_parsing_error_with_kind_beginning_with_underscore() { e.message, "Parse error:\n'_tree_node' is not a valid node kind at: _tree_node]]\n", ); - assert_eq!((e.line, e.column), (0, 7)); + assert_eq!( + format!("{:?}", e.text_range), + "TextIndex { utf8: 7, utf16: 7, line: 0, column: 7 }..TextIndex { utf8: 19, utf16: 19, line: 0, column: 19 }", + ); } } } #[test] fn test_fails_parsing_ellipsis() { - let result = Query::parse(r#"[_ ...]"#); + let result = Query::create(r#"[_ ...]"#); match result { Ok(_) => panic!("Expected parse failure"), Err(e) => assert_eq!( @@ -122,7 +134,7 @@ fn test_fails_parsing_ellipsis() { #[test] fn test_fails_consecutive_adjacency_operators() { - let result = Query::parse(r#"[_ [DelimitedIdentifier] . .]"#); + let result = Query::create(r#"[_ [DelimitedIdentifier] . .]"#); match result { Ok(_) => panic!("Expected parse failure"), Err(e) => assert_eq!(e.message, "Parse error:\nNoneOf at: .]\n"), @@ -131,7 +143,7 @@ fn test_fails_consecutive_adjacency_operators() { #[test] fn test_fails_sole_adjacency() { - let result = Query::parse(r#"[_ .]"#); + let result = Query::create(r#"[_ .]"#); match result { Ok(_) => panic!("Expected parse failure"), Err(e) => assert_eq!( @@ -143,13 +155,13 @@ fn test_fails_sole_adjacency() { #[test] fn test_fails_adjacency_at_edge_of_alt_option() { - let result = Query::parse(r#"([TreeNode] | . [DelimitedIdentifier])+"#); + let result = Query::create(r#"([TreeNode] | . [DelimitedIdentifier])+"#); assert!(result.is_err(), "Expected parse failure"); } #[test] fn test_fails_parsing_trivia_node_selector() { - let result = Query::parse(r#"[EndOfLine]"#); + let result = Query::create(r#"[EndOfLine]"#); match result { Ok(_) => panic!("Expected parse failure"), Err(e) => assert_eq!( diff --git a/crates/testlang/outputs/cargo/tests/src/lib.rs b/crates/testlang/outputs/cargo/tests/src/lib.rs index 81e01938e3..578cff61a1 100644 --- a/crates/testlang/outputs/cargo/tests/src/lib.rs +++ b/crates/testlang/outputs/cargo/tests/src/lib.rs @@ -1,6 +1,6 @@ #![cfg(test)] -mod errors; -mod graph; -mod query; -mod versions; +mod bindings; +mod cst; +mod parser; +mod utils; diff --git a/crates/testlang/outputs/cargo/tests/src/errors/mod.rs b/crates/testlang/outputs/cargo/tests/src/parser/mod.rs similarity index 100% rename from crates/testlang/outputs/cargo/tests/src/errors/mod.rs rename to crates/testlang/outputs/cargo/tests/src/parser/mod.rs diff --git a/crates/testlang/outputs/cargo/tests/src/utils/language_facts.rs b/crates/testlang/outputs/cargo/tests/src/utils/language_facts.rs new file mode 100644 index 0000000000..5106ea9b85 --- /dev/null +++ b/crates/testlang/outputs/cargo/tests/src/utils/language_facts.rs @@ -0,0 +1,25 @@ +use semver::Version; +use slang_testlang::utils::LanguageFacts; + +#[test] +fn list_all_versions() { + assert_eq!( + LanguageFacts::ALL_VERSIONS, + vec![ + Version::new(1, 0, 0), + Version::new(1, 0, 1), + Version::new(1, 1, 0), + Version::new(1, 1, 1), + ], + ); +} + +#[test] +fn list_earliest_version() { + assert_eq!(LanguageFacts::EARLIEST_VERSION, Version::new(1, 0, 0)); +} + +#[test] +fn list_latest_version() { + assert_eq!(LanguageFacts::LATEST_VERSION, Version::new(1, 1, 1)); +} diff --git a/crates/testlang/outputs/cargo/tests/src/utils/mod.rs b/crates/testlang/outputs/cargo/tests/src/utils/mod.rs new file mode 100644 index 0000000000..c95399d364 --- /dev/null +++ b/crates/testlang/outputs/cargo/tests/src/utils/mod.rs @@ -0,0 +1 @@ +mod language_facts; diff --git a/crates/testlang/outputs/cargo/tests/src/versions/mod.rs b/crates/testlang/outputs/cargo/tests/src/versions/mod.rs deleted file mode 100644 index b5eb2c1ec8..0000000000 --- a/crates/testlang/outputs/cargo/tests/src/versions/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -use semver::Version; -use slang_testlang::utils::LanguageFacts; - -#[test] -fn list_supported_versions() { - let versions = LanguageFacts::SUPPORTED_VERSIONS; - - assert!(!versions.is_empty()); - assert!(!versions.contains(&Version::new(0, 0, 0))); - assert!(versions.contains(&Version::new(1, 0, 0))); -} diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/generated/config.json b/crates/testlang/outputs/cargo/wasm/src/generated/generated/config.json index 3444eb9169..15037ce589 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/generated/config.json +++ b/crates/testlang/outputs/cargo/wasm/src/generated/generated/config.json @@ -170,16 +170,6 @@ "as_getter": true } }, - "nomic-foundation:slang:parser:parse-error.text-range()": { - "Function": { - "as_getter": true - } - }, - "nomic-foundation:slang:parser:parse-error.message()": { - "Function": { - "as_getter": true - } - }, "nomic-foundation:slang:parser:parse-output.tree()": { "Function": { "as_getter": true diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit index 1721afc82d..e6fbb0073b 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/bindings.wit @@ -6,12 +6,16 @@ interface bindings { /// A giant graph that contains name binding information for all source files within the compilation unit. /// It stores cursors to all definitions and references, and can resolve the edges between them. resource binding-graph { - /// If the provided cursor points at a definition `Identifier`, it will return the - /// corresponding definition. Otherwise, it will return `undefined`. + /// Tries to resolve the identifier terminal pointed at by the provided cursor to a definition. + /// If successful, returns the definition. Otherwise, returns `undefined`. + /// + /// For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. definition-at: func(cursor: borrow) -> option; - /// If the provided cursor points at a reference `Identifier`, it will return the - /// corresponding reference. Otherwise, it will return `undefined`. + /// Tries to resolve the identifier terminal pointed at by the provided cursor to a reference. + /// If successful, returns the reference. Otherwise, returns `undefined`. + /// + /// For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. reference-at: func(cursor: borrow) -> option; } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit index ea64aab4ac..b3918e9681 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/compilation.wit @@ -3,6 +3,7 @@ interface compilation { use bindings.{binding-graph}; use cst.{nonterminal-node, cursor}; + use parser.{parse-error}; /// A builder for creating compilation units. /// Allows incrementally building a transitive list of all files and their imports. @@ -64,6 +65,9 @@ interface compilation { /// Returns the syntax tree of this file. tree: func() -> nonterminal-node; + /// Returns a list of all errors encountered during parsing this file. + errors: func() -> list; + /// Creates a cursor for traversing the syntax tree of this file. create-tree-cursor: func() -> cursor; } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/cst.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/cst.wit index 0b2027c8c4..42e9856c28 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/cst.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/cst.wit @@ -203,9 +203,11 @@ interface cst { //// Useful extension methods for working with terminals and terminal kinds. resource terminal-kind-extensions { - /// Returns true if the terminal is a trivia token. i.e. whitespace, comments, etc... + /// Returns `true` if the terminal is an identifier token. + is-identifier: static func(kind: terminal-kind) -> bool; + /// Returns `true` if the terminal is a trivia token. i.e. whitespace, comments, etc... is-trivia: static func(kind: terminal-kind) -> bool; - /// Returns true if the terminal is a valid token in the language grammar. + /// Returns `true` if the terminal is a valid token in the language grammar. is-valid: static func(kind: terminal-kind) -> bool; } @@ -368,7 +370,7 @@ interface cst { /// Moves to the last child of the current node. go-to-last-child: func() -> bool; /// Moves to the nth child of the current node. - go-to-nth-child: func(child-number: u32) -> bool; + go-to-nth-child: func(child-index: u32) -> bool; /// Moves to the next sibling node. go-to-next-sibling: func() -> bool; @@ -410,23 +412,21 @@ interface cst { resource query { /// Parses a query string into a query object. /// Throws an error if the query syntax is invalid. - parse: static func(text: string) -> result; + create: static func(text: string) -> result; } /// Represents an error that occurred while parsing a query. record query-error { - /// The error message describing what went wrong. + /// A human-readable message describing what went wrong. message: string, - /// The line number where the error occurred. - line: u32, - /// The column number where the error occurred. - column: u32, + /// The text range where the error occurred in the query code. + text-range: text-range, } - /// Represents a match found by executing a query. + /// Represents a match found by executing queries on a cursor. record query-match { /// The index of the query that produced this match. - query-number: u32, + query-index: u32, /// List of captured nodes and their names from the query. captures: list>>, } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/parser.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/parser.wit index 6eca8e01ae..8834d77de3 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/parser.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/parser.wit @@ -6,27 +6,26 @@ interface parser { /// A parser instance that can parse source code into syntax trees. /// Each parser is configured for a specific language version and grammar. resource parser { - /// Returns the root nonterminal kind for this parser's grammar. - /// This represents the starting point for parsing a complete source file. - root-kind: static func() -> nonterminal-kind; - /// Creates a new parser instance for the specified language version. create: static func(language-version: string) -> result; /// Returns the language version this parser instance is configured for. language-version: func() -> string; - /// Parses the input string starting from the specified nonterminal kind. - parse: func(kind: nonterminal-kind, input: string) -> parse-output; + /// Parses the input string into a complete source file. + parse-file-contents: func(input: string) -> parse-output; + + /// Parses the input string into a nonterminal with the specified kind. + parse-nonterminal: func(kind: nonterminal-kind, input: string) -> parse-output; } - /// Contains information about where the error occurred and what went wrong. - resource parse-error { - /// Returns the text range where the error occurred in the source code. - text-range: func() -> text-range; + /// Represents an error that occurred while parsing source code. + record parse-error { + /// A human-readable message describing what went wrong. + message: string, - /// Returns a human-readable message describing the parsing error. - message: func() -> string; + /// The text range where the error occurred in the source code. + text-range: text-range, } /// The output of a parsing operation. @@ -37,7 +36,7 @@ interface parser { tree: func() -> nonterminal-node; /// Returns a list of all parsing errors encountered. - /// An empty list indicates successful parsing with no errors. + /// An empty list indicates a successful parse with no errors. errors: func() -> list; /// Returns whether the parse was completely successful with no errors. diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/utils.wit b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/utils.wit index 9bb93e160f..86c9d20bd0 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/utils.wit +++ b/crates/testlang/outputs/cargo/wasm/src/generated/interface/generated/utils.wit @@ -4,6 +4,12 @@ interface utils { /// Provides information about the supported language versions and the grammar. resource language-facts { /// Returns a list of language versions supported by Slang, sorted ascendingly. - supported-versions: static func() -> list; + all-versions: static func() -> list; + + /// Returns the earliest language version supported by Slang. + earliest-version: static func() -> string; + + /// Returns the latest language version supported by Slang. + latest-version: static func() -> string; } } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs index c1d50b6098..7ff4c5af2f 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/compilation/mod.rs @@ -16,6 +16,7 @@ mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ Cursor, NonterminalNode, }; + pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::ParseError; } mod rust { @@ -118,6 +119,10 @@ define_rc_wrapper! { File { self._borrow_ffi().tree().to_owned()._into_ffi() } + fn errors(&self) -> Vec { + self._borrow_ffi().errors().iter().map(|e| e.clone()._into_ffi()).collect() + } + fn create_tree_cursor(&self) -> ffi::Cursor { self._borrow_ffi().create_tree_cursor()._into_ffi() } diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs index deca6e2bb4..2964feb134 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/cst/mod.rs @@ -65,12 +65,16 @@ enum_to_enum!(TerminalKind); pub struct TerminalKindExtensionsWrapper; impl ffi::GuestTerminalKindExtensions for TerminalKindExtensionsWrapper { + fn is_identifier(kind: ffi::TerminalKind) -> bool { + crate::rust_crate::cst::TerminalKindExtensions::is_identifier(kind._from_ffi()) + } + fn is_trivia(kind: ffi::TerminalKind) -> bool { - crate::rust_crate::cst::TerminalKindExtensions::is_trivia(&kind._from_ffi()) + crate::rust_crate::cst::TerminalKindExtensions::is_trivia(kind._from_ffi()) } fn is_valid(kind: ffi::TerminalKind) -> bool { - crate::rust_crate::cst::TerminalKindExtensions::is_valid(&kind._from_ffi()) + crate::rust_crate::cst::TerminalKindExtensions::is_valid(kind._from_ffi()) } } @@ -98,6 +102,16 @@ impl IntoFFI for rust::Node { } } +impl FromFFI for ffi::Node { + #[inline] + fn _from_ffi(self) -> rust::Node { + match self { + ffi::Node::Nonterminal(node) => rust::Node::Nonterminal(node._from_ffi()), + ffi::Node::Terminal(node) => rust::Node::Terminal(node._from_ffi()), + } + } +} + //================================================ // // resource nonterminal-node @@ -134,7 +148,7 @@ define_rc_wrapper! { NonterminalNode { } fn create_cursor(&self, text_offset: ffi::TextIndex) -> ffi::Cursor { - std::rc::Rc::clone(self._borrow_ffi()).cursor_with_offset(text_offset._from_ffi())._into_ffi() + std::rc::Rc::clone(self._borrow_ffi()).create_cursor(text_offset._from_ffi())._into_ffi() } } } @@ -190,6 +204,16 @@ impl IntoFFI for rust::Edge { } } +impl FromFFI for ffi::Edge { + #[inline] + fn _from_ffi(self) -> rust::Edge { + rust::Edge { + label: self.label.map(FromFFI::_from_ffi), + node: self.node._from_ffi(), + } + } +} + //================================================ // // resource cursor @@ -277,8 +301,8 @@ define_refcell_wrapper! { Cursor { self._borrow_mut_ffi().go_to_last_child() } - fn go_to_nth_child(&self, child_number: u32) -> bool { - self._borrow_mut_ffi().go_to_nth_child(child_number as usize) + fn go_to_nth_child(&self, child_index: u32) -> bool { + self._borrow_mut_ffi().go_to_nth_child(child_index as usize) } fn go_to_next_sibling(&self) -> bool { @@ -355,8 +379,8 @@ define_refcell_wrapper! { AncestorsIterator { //================================================ define_wrapper! { Query { - fn parse(text: String) -> Result { - rust::Query::parse(&text).map_err(IntoFFI::_into_ffi).map(IntoFFI::_into_ffi) + fn create(text: String) -> Result { + rust::Query::create(&text).map_err(IntoFFI::_into_ffi).map(IntoFFI::_into_ffi) } } } @@ -371,8 +395,7 @@ impl IntoFFI for rust::QueryError { fn _into_ffi(self) -> ffi::QueryError { ffi::QueryError { message: self.message, - line: self.line.try_into().unwrap(), - column: self.column.try_into().unwrap(), + text_range: self.text_range._into_ffi(), } } } @@ -399,7 +422,7 @@ impl IntoFFI for rust::QueryMatch { #[inline] fn _into_ffi(self) -> ffi::QueryMatch { ffi::QueryMatch { - query_number: self.query_number.try_into().unwrap(), + query_index: self.query_index.try_into().unwrap(), captures: self .captures .into_iter() diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs index 01e073bb8d..bceb928319 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/parser/mod.rs @@ -6,11 +6,11 @@ use crate::wasm_crate::utils::{define_wrapper, FromFFI, IntoFFI}; mod ffi { pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::cst::{ - Cursor, NonterminalNode, TextRange, + Cursor, NonterminalNode, }; pub use crate::wasm_crate::bindgen::exports::nomic_foundation::slang::parser::{ - Guest, GuestParseError, GuestParseOutput, GuestParser, NonterminalKind, ParseError, - ParseErrorBorrow, ParseOutput, ParseOutputBorrow, Parser, ParserBorrow, + Guest, GuestParseOutput, GuestParser, NonterminalKind, ParseError, ParseOutput, + ParseOutputBorrow, Parser, ParserBorrow, }; } @@ -20,7 +20,6 @@ mod rust { impl ffi::Guest for crate::wasm_crate::World { type Parser = ParserWrapper; - type ParseError = ParseErrorWrapper; type ParseOutput = ParseOutputWrapper; } @@ -31,10 +30,6 @@ impl ffi::Guest for crate::wasm_crate::World { //================================================ define_wrapper! { Parser { - fn root_kind() -> ffi::NonterminalKind { - rust::Parser::ROOT_KIND._into_ffi() - } - fn create(language_version: String) -> Result { semver::Version::parse(&language_version) .map_err(|_| format!("Invalid semantic version: '{language_version}'")) @@ -46,26 +41,30 @@ define_wrapper! { Parser { self._borrow_ffi().language_version().to_string() } - fn parse(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { - self._borrow_ffi().parse(kind._from_ffi(), &input)._into_ffi() + fn parse_file_contents(&self, input: String) -> ffi::ParseOutput { + self._borrow_ffi().parse_file_contents(&input)._into_ffi() + } + + fn parse_nonterminal(&self, kind: ffi::NonterminalKind, input: String) -> ffi::ParseOutput { + self._borrow_ffi().parse_nonterminal(kind._from_ffi(), &input)._into_ffi() } } } //================================================ // -// resource parse-error +// record parse-error // //================================================ -define_wrapper! { ParseError { - fn text_range(&self) -> ffi::TextRange { - self._borrow_ffi().text_range()._into_ffi() +impl IntoFFI for rust::ParseError { + #[inline] + fn _into_ffi(self) -> ffi::ParseError { + ffi::ParseError { + message: self.message(), + text_range: self.text_range()._into_ffi(), + } } - - fn message(&self) -> String { - self._borrow_ffi().message() - } -} } +} //================================================ // diff --git a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs index b478ca4299..e89308b6de 100644 --- a/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs +++ b/crates/testlang/outputs/cargo/wasm/src/generated/wrappers/utils/mod.rs @@ -1,5 +1,7 @@ // This file is generated automatically by infrastructure scripts. Please don't edit by hand. +use semver::Version; + use crate::wasm_crate::utils::define_wrapper; mod ffi { @@ -23,10 +25,18 @@ impl ffi::Guest for crate::wasm_crate::World { //================================================ define_wrapper! { LanguageFacts { - fn supported_versions() -> Vec { - rust::LanguageFacts::SUPPORTED_VERSIONS + fn all_versions() -> Vec { + rust::LanguageFacts::ALL_VERSIONS .iter() - .map(|v| v.to_string()) + .map(Version::to_string) .collect() } + + fn earliest_version() -> String { + rust::LanguageFacts::EARLIEST_VERSION.to_string() + } + + fn latest_version() -> String { + rust::LanguageFacts::LATEST_VERSION.to_string() + } } } diff --git a/crates/testlang/outputs/npm/package/src/generated/parser/index.mts b/crates/testlang/outputs/npm/package/src/generated/parser/index.mts index 065b3eba7a..d419c657ee 100644 --- a/crates/testlang/outputs/npm/package/src/generated/parser/index.mts +++ b/crates/testlang/outputs/npm/package/src/generated/parser/index.mts @@ -7,8 +7,6 @@ export const Parser = wasm.parser.Parser; /** {@inheritDoc wasm.parser.Parser} */ export type Parser = wasm.parser.Parser; -/** {@inheritDoc wasm.parser.ParseError} */ -export const ParseError = wasm.parser.ParseError; /** {@inheritDoc wasm.parser.ParseError} */ export type ParseError = wasm.parser.ParseError; diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts index 9cfdd7498c..9c05d8998f 100644 --- a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-bindings.d.ts @@ -38,13 +38,17 @@ export enum BindingLocationType { */ export class BindingGraph { /** - * If the provided cursor points at a definition `Identifier`, it will return the - * corresponding definition. Otherwise, it will return `undefined`. + * Tries to resolve the identifier terminal pointed at by the provided cursor to a definition. + * If successful, returns the definition. Otherwise, returns `undefined`. + * + * For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. */ definitionAt(cursor: Cursor): Definition | undefined; /** - * If the provided cursor points at a reference `Identifier`, it will return the - * corresponding reference. Otherwise, it will return `undefined`. + * Tries to resolve the identifier terminal pointed at by the provided cursor to a reference. + * If successful, returns the reference. Otherwise, returns `undefined`. + * + * For more information on identifier terminals, see the `TerminalKindExtensions.isIdentifier()` API. */ referenceAt(cursor: Cursor): Reference | undefined; } diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts index c08b1eed29..61ed78a016 100644 --- a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-compilation.d.ts @@ -11,6 +11,8 @@ import type { NonterminalNode } from "./nomic-foundation-slang-cst.js"; export { NonterminalNode }; import type { Cursor } from "./nomic-foundation-slang-cst.js"; export { Cursor }; +import type { ParseError } from "./nomic-foundation-slang-parser.js"; +export { ParseError }; /** * Contains information about imports found in an added source file. */ @@ -65,6 +67,10 @@ export class File { * Returns the syntax tree of this file. */ get tree(): NonterminalNode; + /** + * Returns a list of all errors encountered during parsing this file. + */ + errors(): ParseError[]; /** * Creates a cursor for traversing the syntax tree of this file. */ diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts index 47dbeac4e6..1e96d4002a 100644 --- a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-cst.d.ts @@ -385,30 +385,13 @@ export interface Edge { node: Node; } /** - * Represents an error that occurred while parsing a query. - */ -export interface QueryError { - /** - * The error message describing what went wrong. - */ - message: string; - /** - * The line number where the error occurred. - */ - line: number; - /** - * The column number where the error occurred. - */ - column: number; -} -/** - * Represents a match found by executing a query. + * Represents a match found by executing queries on a cursor. */ export interface QueryMatch { /** * The index of the query that produced this match. */ - queryNumber: number; + queryIndex: number; /** * List of captured nodes and their names from the query. */ @@ -457,6 +440,19 @@ export interface TextRange { */ end: TextIndex; } +/** + * Represents an error that occurred while parsing a query. + */ +export interface QueryError { + /** + * A human-readable message describing what went wrong. + */ + message: string; + /** + * The text range where the error occurred in the query code. + */ + textRange: TextRange; +} /** * Iterator over all ancestors of the current node, starting with the immediate parent, and moving upwards, ending with the root node. @@ -562,7 +558,7 @@ export class Cursor { /** * Moves to the nth child of the current node. */ - goToNthChild(childNumber: number): boolean; + goToNthChild(childIndex: number): boolean; /** * Moves to the next sibling node. */ @@ -690,7 +686,7 @@ export class Query { * Parses a query string into a query object. * Throws an error if the query syntax is invalid. */ - static parse(text: string): Query; + static create(text: string): Query; } /** @@ -712,11 +708,15 @@ export class QueryMatchIterator { */ export class TerminalKindExtensions { /** - * Returns true if the terminal is a trivia token. i.e. whitespace, comments, etc... + * Returns `true` if the terminal is an identifier token. + */ + static isIdentifier(kind: TerminalKind): boolean; + /** + * Returns `true` if the terminal is a trivia token. i.e. whitespace, comments, etc... */ static isTrivia(kind: TerminalKind): boolean; /** - * Returns true if the terminal is a valid token in the language grammar. + * Returns `true` if the terminal is a valid token in the language grammar. */ static isValid(kind: TerminalKind): boolean; } diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts index 07fe4156a6..8382b6ed99 100644 --- a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-parser.d.ts @@ -2,7 +2,6 @@ export namespace NomicFoundationSlangParser { export { Parser }; - export { ParseError }; export { ParseOutput }; } import type { Cursor } from "./nomic-foundation-slang-cst.js"; @@ -13,19 +12,18 @@ import type { NonterminalKind } from "./nomic-foundation-slang-cst.js"; export { NonterminalKind }; import type { TextRange } from "./nomic-foundation-slang-cst.js"; export { TextRange }; - /** - * Contains information about where the error occurred and what went wrong. + * Represents an error that occurred while parsing source code. */ -export class ParseError { +export interface ParseError { /** - * Returns the text range where the error occurred in the source code. + * A human-readable message describing what went wrong. */ - get textRange(): TextRange; + message: string; /** - * Returns a human-readable message describing the parsing error. + * The text range where the error occurred in the source code. */ - get message(): string; + textRange: TextRange; } /** @@ -40,7 +38,7 @@ export class ParseOutput { get tree(): NonterminalNode; /** * Returns a list of all parsing errors encountered. - * An empty list indicates successful parsing with no errors. + * An empty list indicates a successful parse with no errors. */ errors(): ParseError[]; /** @@ -60,11 +58,6 @@ export class ParseOutput { * Each parser is configured for a specific language version and grammar. */ export class Parser { - /** - * Returns the root nonterminal kind for this parser's grammar. - * This represents the starting point for parsing a complete source file. - */ - static rootKind(): NonterminalKind; /** * Creates a new parser instance for the specified language version. */ @@ -74,7 +67,11 @@ export class Parser { */ get languageVersion(): string; /** - * Parses the input string starting from the specified nonterminal kind. + * Parses the input string into a complete source file. + */ + parseFileContents(input: string): ParseOutput; + /** + * Parses the input string into a nonterminal with the specified kind. */ - parse(kind: NonterminalKind, input: string): ParseOutput; + parseNonterminal(kind: NonterminalKind, input: string): ParseOutput; } diff --git a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts index 0a3e19de1c..9010760119 100644 --- a/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts +++ b/crates/testlang/outputs/npm/package/wasm/generated/interfaces/nomic-foundation-slang-utils.d.ts @@ -11,5 +11,13 @@ export class LanguageFacts { /** * Returns a list of language versions supported by Slang, sorted ascendingly. */ - static supportedVersions(): string[]; + static allVersions(): string[]; + /** + * Returns the earliest language version supported by Slang. + */ + static earliestVersion(): string; + /** + * Returns the latest language version supported by Slang. + */ + static latestVersion(): string; } diff --git a/crates/testlang/outputs/npm/package/wasm/generated/testlang_cargo_wasm.component.d.ts b/crates/testlang/outputs/npm/package/wasm/generated/testlang_cargo_wasm.component.d.ts index 959f0ad174..0e3bde1a8b 100644 --- a/crates/testlang/outputs/npm/package/wasm/generated/testlang_cargo_wasm.component.d.ts +++ b/crates/testlang/outputs/npm/package/wasm/generated/testlang_cargo_wasm.component.d.ts @@ -3,12 +3,12 @@ import { NomicFoundationSlangCst } from "./interfaces/nomic-foundation-slang-cst.js"; import { NomicFoundationSlangAst } from "./interfaces/nomic-foundation-slang-ast.js"; import { NomicFoundationSlangBindings } from "./interfaces/nomic-foundation-slang-bindings.js"; -import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangParser } from "./interfaces/nomic-foundation-slang-parser.js"; +import { NomicFoundationSlangCompilation } from "./interfaces/nomic-foundation-slang-compilation.js"; import { NomicFoundationSlangUtils } from "./interfaces/nomic-foundation-slang-utils.js"; export * as cst from "./interfaces/nomic-foundation-slang-cst.js"; export * as ast from "./interfaces/nomic-foundation-slang-ast.js"; export * as bindings from "./interfaces/nomic-foundation-slang-bindings.js"; -export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as parser from "./interfaces/nomic-foundation-slang-parser.js"; +export * as compilation from "./interfaces/nomic-foundation-slang-compilation.js"; export * as utils from "./interfaces/nomic-foundation-slang-utils.js"; diff --git a/crates/testlang/outputs/npm/tests/src/ast/ast.test.mts b/crates/testlang/outputs/npm/tests/src/ast/ast.test.mts index 70a75ee3c3..a4dc2b864f 100644 --- a/crates/testlang/outputs/npm/tests/src/ast/ast.test.mts +++ b/crates/testlang/outputs/npm/tests/src/ast/ast.test.mts @@ -23,7 +23,7 @@ test("create and use sequence types", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.Tree, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.Tree, source); expect(parseOutput.isValid()).toBeTruthy(); const cst = parseOutput.tree; @@ -41,7 +41,7 @@ test("create and use choice types", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.TreeNodeChild, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.TreeNodeChild, source); expect(parseOutput.isValid()).toBeTruthy(); const cst = parseOutput.tree; @@ -63,7 +63,7 @@ test("create and use repeated types", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.Tree, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.Tree, source); expect(parseOutput.isValid()).toBeTruthy(); const cst = parseOutput.tree; @@ -85,7 +85,7 @@ test("create and use separated types", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.SeparatedIdentifiers, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.SeparatedIdentifiers, source); expect(parseOutput.isValid()).toBeTruthy(); const cst = parseOutput.tree; @@ -106,7 +106,7 @@ test("throws an exception on initializing the wrong type", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.Tree, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.Tree, source); expect(parseOutput.isValid()).toBeTruthy(); const cst = parseOutput.tree; @@ -122,7 +122,7 @@ test("throws an exception on using an incorrect/incomplete CST node", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.Tree, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.Tree, source); expect(parseOutput.isValid()).toBeFalsy(); const cst = parseOutput.tree; @@ -149,7 +149,7 @@ test("create and use prefix expressions", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.Expression, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.Expression, source); expect(parseOutput.isValid()).toBeTruthy(); const cst = parseOutput.tree; @@ -168,7 +168,7 @@ test("create and use postfix expressions", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.Expression, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.Expression, source); expect(parseOutput.isValid()).toBeTruthy(); const cst = parseOutput.tree; @@ -188,7 +188,7 @@ test("create and use binary expressions", () => { const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.Expression, source); + const parseOutput = parser.parseNonterminal(NonterminalKind.Expression, source); expect(parseOutput.isValid()).toBeTruthy(); const cst = parseOutput.tree; @@ -209,7 +209,7 @@ it("can reuse the same CST nodes after selectors", () => { const source = `foo + bar`; const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.SourceUnit, source); + const parseOutput = parser.parseFileContents(source); parseOutput.isValid(); // true const cst = parseOutput.tree.asNonterminalNode()!; diff --git a/crates/testlang/outputs/npm/tests/src/cst/cursor.test.mts b/crates/testlang/outputs/npm/tests/src/cst/cursor.test.mts index 1a66818131..927ae25b57 100644 --- a/crates/testlang/outputs/npm/tests/src/cst/cursor.test.mts +++ b/crates/testlang/outputs/npm/tests/src/cst/cursor.test.mts @@ -13,7 +13,7 @@ test("use cursor goToNext()", () => { const source = "tree [A [B C] D];"; const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.SourceUnit, source); + const parseOutput = parser.parseFileContents(source); const cursor: Cursor = parseOutput.createTreeCursor(); assertIsNonterminalNode(cursor.node, NonterminalKind.SourceUnit); @@ -101,7 +101,7 @@ test("use cursor goToNext()", () => { test("access the node using its name", () => { const source = "tree [A [B C] D];"; const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.SourceUnit, source); + const parseOutput = parser.parseFileContents(source); const cursor = parseOutput.createTreeCursor(); let names: string[] = []; diff --git a/crates/testlang/outputs/npm/tests/src/cst/iterators.test.mts b/crates/testlang/outputs/npm/tests/src/cst/iterators.test.mts index 348abc56ec..c3ff494849 100644 --- a/crates/testlang/outputs/npm/tests/src/cst/iterators.test.mts +++ b/crates/testlang/outputs/npm/tests/src/cst/iterators.test.mts @@ -12,7 +12,7 @@ describe("iterators", () => { const source = "tree [A [B C] D];"; const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.SourceUnit, source); + const parseOutput = parser.parseFileContents(source); const cursor: Cursor = parseOutput.createTreeCursor(); assertIsNonterminalNode(cursor.node, NonterminalKind.SourceUnit); diff --git a/crates/testlang/outputs/npm/tests/src/cst/nodes.test.mts b/crates/testlang/outputs/npm/tests/src/cst/nodes.test.mts index f5979885f4..d3fbd899f5 100644 --- a/crates/testlang/outputs/npm/tests/src/cst/nodes.test.mts +++ b/crates/testlang/outputs/npm/tests/src/cst/nodes.test.mts @@ -9,7 +9,7 @@ import { describe("nodes", () => { const source = `"foo"`; - const parseOutput = Parser.create("1.0.0").parse(NonterminalKind.Literal, source); + const parseOutput = Parser.create("1.0.0").parseNonterminal(NonterminalKind.Literal, source); const nonTerminal = parseOutput.tree; assertIsNonterminalNode(nonTerminal, NonterminalKind.Literal); diff --git a/crates/testlang/outputs/npm/tests/src/cst/query.test.mts b/crates/testlang/outputs/npm/tests/src/cst/query.test.mts index 4aee305a0e..4ed9cc4366 100644 --- a/crates/testlang/outputs/npm/tests/src/cst/query.test.mts +++ b/crates/testlang/outputs/npm/tests/src/cst/query.test.mts @@ -10,10 +10,10 @@ import { Parser } from "@slang-private/testlang-npm-package/parser"; test("simple query", () => { const parser = Parser.create("1.0.0"); const treeSource = `tree [A [B C] D];`; - const parseOutput = parser.parse(NonterminalKind.Tree, treeSource); + const parseOutput = parser.parseNonterminal(NonterminalKind.Tree, treeSource); const querySource = `[TreeNodeChild @id [DelimitedIdentifier]]`; - const query = Query.parse(querySource); + const query = Query.create(querySource); const matches = parseOutput.createTreeCursor().query([query]); @@ -41,16 +41,28 @@ test("query syntax error", () => { const source = `[TreeNode @b [DelimitedIdentifier]`; try { - Query.parse(source); - throw new Error("Query.parse() should have thrown"); + Query.create(source); + throw new Error("Query.create() should have thrown"); } catch (error) { expect(error).toEqual({ message: `Parse error: expected ']' at: Alt at: [TreeNode @b [DelimitedIdentifier] `, - line: 0, - column: 34, + textRange: { + start: { + utf8: 34, + utf16: 34, + line: 0, + column: 34, + }, + end: { + utf8: 34, + utf16: 34, + line: 0, + column: 34, + }, + }, } satisfies QueryError); } }); diff --git a/crates/testlang/outputs/npm/tests/src/cst/terminal-kind-extensions.test.mts b/crates/testlang/outputs/npm/tests/src/cst/terminal-kind-extensions.test.mts index fe5b9cb9a9..ad040fb7ab 100644 --- a/crates/testlang/outputs/npm/tests/src/cst/terminal-kind-extensions.test.mts +++ b/crates/testlang/outputs/npm/tests/src/cst/terminal-kind-extensions.test.mts @@ -1,5 +1,39 @@ import { TerminalKindExtensions, TerminalKind } from "@slang-private/testlang-npm-package/cst"; +describe("is_identifier()", () => { + for (const kind in TerminalKind) { + it(`TerminalKind.${kind}`, () => { + switch (kind) { + case TerminalKind.Identifier: { + expect(TerminalKindExtensions.isIdentifier(kind)).toBeTruthy(); + break; + } + case TerminalKind.Bang: + case TerminalKind.CloseBracket: + case TerminalKind.DelimitedIdentifier: + case TerminalKind.EndOfLine: + case TerminalKind.Missing: + case TerminalKind.MultiLineComment: + case TerminalKind.OpenBracket: + case TerminalKind.Period: + case TerminalKind.Plus: + case TerminalKind.Semicolon: + case TerminalKind.SingleLineComment: + case TerminalKind.StringLiteral: + case TerminalKind.TreeKeyword: + case TerminalKind.Unrecognized: + case TerminalKind.Whitespace: { + expect(TerminalKindExtensions.isIdentifier(kind)).toBeFalsy(); + break; + } + default: { + throw new Error(`Unexpected terminal kind: ${kind}`); + } + } + }); + } +}); + describe("is_trivia()", () => { for (const kind in TerminalKind) { it(`TerminalKind.${kind}`, () => { diff --git a/crates/testlang/outputs/npm/tests/src/language/language-facts.test.mts b/crates/testlang/outputs/npm/tests/src/language/language-facts.test.mts deleted file mode 100644 index 0708b4deae..0000000000 --- a/crates/testlang/outputs/npm/tests/src/language/language-facts.test.mts +++ /dev/null @@ -1,10 +0,0 @@ -import { LanguageFacts } from "@slang-private/testlang-npm-package/utils"; - -test("list supported versions", () => { - const versions = LanguageFacts.supportedVersions(); - - expect(versions.length).toBeGreaterThan(0); - - expect(versions.includes("1.0.0")).toBeTruthy(); - expect(versions.includes("0.0.0")).toBeFalsy(); -}); diff --git a/crates/testlang/outputs/npm/tests/src/parser/parse-error.test.mts b/crates/testlang/outputs/npm/tests/src/parser/parse-error.test.mts index 037db2f061..d07162b443 100644 --- a/crates/testlang/outputs/npm/tests/src/parser/parse-error.test.mts +++ b/crates/testlang/outputs/npm/tests/src/parser/parse-error.test.mts @@ -1,11 +1,10 @@ import { Parser } from "@slang-private/testlang-npm-package/parser"; -import { NonterminalKind } from "@slang-private/testlang-npm-package/cst"; test("render error reports", () => { const source = "tree [AB;"; const parser = Parser.create("1.0.0"); - const parseOutput = parser.parse(NonterminalKind.SourceUnit, source); + const parseOutput = parser.parseFileContents(source); expect(parseOutput.isValid()).toBeFalsy(); const errors = parseOutput.errors(); diff --git a/crates/testlang/outputs/npm/tests/src/parser/parse.test.mts b/crates/testlang/outputs/npm/tests/src/parser/parse.test.mts index 4453018134..a073dc053d 100644 --- a/crates/testlang/outputs/npm/tests/src/parser/parse.test.mts +++ b/crates/testlang/outputs/npm/tests/src/parser/parse.test.mts @@ -10,7 +10,7 @@ test("parse terminal", () => { const source = "About_time"; const parser = Parser.create("1.0.0"); - const tree = parser.parse(NonterminalKind.TreeNodeChild, source).tree; + const tree = parser.parseNonterminal(NonterminalKind.TreeNodeChild, source).tree; assertIsNonterminalNode(tree, NonterminalKind.TreeNodeChild); const children = tree.children(); @@ -23,7 +23,7 @@ test("parse nonterminal", () => { const source = `tree [A [B C] D];`; const parser = Parser.create("1.0.0"); - const tree = parser.parse(NonterminalKind.SourceUnit, source).tree; + const tree = parser.parseFileContents(source).tree; assertIsNonterminalNode(tree, NonterminalKind.SourceUnit); const children = tree.children(); @@ -36,7 +36,7 @@ test("parse unicode characters", () => { const source = `"some 😁 emoji"`; const parser = Parser.create("1.0.0"); - const nonTerminal = parser.parse(NonterminalKind.Literal, source).tree; + const nonTerminal = parser.parseNonterminal(NonterminalKind.Literal, source).tree; assertIsNonterminalNode(nonTerminal, NonterminalKind.Literal); expect(nonTerminal.textLength).toEqual({ diff --git a/crates/testlang/outputs/npm/tests/src/parser/root-kind.test.mts b/crates/testlang/outputs/npm/tests/src/parser/root-kind.test.mts deleted file mode 100644 index c94db77514..0000000000 --- a/crates/testlang/outputs/npm/tests/src/parser/root-kind.test.mts +++ /dev/null @@ -1,6 +0,0 @@ -import { NonterminalKind } from "@slang-private/testlang-npm-package/cst"; -import { Parser } from "@slang-private/testlang-npm-package/parser"; - -test("Parser exposes a root kind", () => { - expect(Parser.rootKind()).toEqual(NonterminalKind.SourceUnit); -}); diff --git a/crates/testlang/outputs/npm/tests/src/public-api.test.mts b/crates/testlang/outputs/npm/tests/src/public-api.test.mts index f9448d7f7b..c969812c06 100644 --- a/crates/testlang/outputs/npm/tests/src/public-api.test.mts +++ b/crates/testlang/outputs/npm/tests/src/public-api.test.mts @@ -1,6 +1,5 @@ import * as slang from "@slang-private/testlang-npm-package"; import { NonterminalKind, TerminalKind } from "@slang-private/testlang-npm-package/cst"; -import { Parser } from "@slang-private/testlang-npm-package/parser"; test("use namespace imports of the API", () => { expect(slang.cst.NonterminalKind.SourceUnit).toEqual("SourceUnit"); @@ -13,7 +12,3 @@ test("use nested imports of the API", () => { expect(NonterminalKind.TreeNode).toEqual("TreeNode"); expect(TerminalKind.Identifier).toEqual("Identifier"); }); - -test("language exposes a root kind", () => { - expect(Parser.rootKind()).toEqual(NonterminalKind.SourceUnit); -}); diff --git a/crates/testlang/outputs/npm/tests/src/utils/language-facts.test.mts b/crates/testlang/outputs/npm/tests/src/utils/language-facts.test.mts index 0708b4deae..5b45b2caad 100644 --- a/crates/testlang/outputs/npm/tests/src/utils/language-facts.test.mts +++ b/crates/testlang/outputs/npm/tests/src/utils/language-facts.test.mts @@ -1,10 +1,13 @@ import { LanguageFacts } from "@slang-private/testlang-npm-package/utils"; -test("list supported versions", () => { - const versions = LanguageFacts.supportedVersions(); +test("allVersions()", () => { + expect(LanguageFacts.allVersions()).toStrictEqual(["1.0.0", "1.0.1", "1.1.0", "1.1.1"]); +}); - expect(versions.length).toBeGreaterThan(0); +test("earliestVersion()", () => { + expect(LanguageFacts.earliestVersion()).toStrictEqual("1.0.0"); +}); - expect(versions.includes("1.0.0")).toBeTruthy(); - expect(versions.includes("0.0.0")).toBeFalsy(); +test("latestVersion()", () => { + expect(LanguageFacts.latestVersion()).toStrictEqual("1.1.1"); }); diff --git a/documentation/public/user-guide/concepts.md b/documentation/public/user-guide/concepts.md index 41124c852a..024bfe2afb 100644 --- a/documentation/public/user-guide/concepts.md +++ b/documentation/public/user-guide/concepts.md @@ -10,12 +10,11 @@ The earliest Solidity version we support is `0.4.11`, and we plan on supporting From a `Parser` object, you can analyze any source text according to the nonterminals of that specific version. Providing an accurate language version is important, as it affects the shape of the syntax tree, and possible errors produced. -You can use the `LanguageFacts::supportedVersions()` API to get a list of all supported versions for the current Slang release. +You can use the `LanguageFacts::allVersions()` API to get a list of all supported versions for the current Slang release. -The `Parser::parse()` API is the main entry point for the parser, and to generate concrete syntax trees (CSTs) that can be used for further analysis. -Each `parse()` operation accepts the input source code, and a `NonterminalKind` variant. -This allows callers to parse entire source files (`NonterminalKind::SourceUnit`), individual contracts (`NonterminalKind::ContractDefinition`), -methods (`NonterminalKind::FunctionDefinition`), or any other syntax nodes. +The `Parser::parse_file_contents(source)` API is the main entry point for the parser, and to generate concrete syntax trees (CSTs) that can be used for further analysis. +Additionally, there is `Parser::parse_nonterminal(kind, source)` API that allows callers to parse specific nonterminal nodes, like individual contracts (`NonterminalKind::ContractDefinition`), +methods (`NonterminalKind::FunctionDefinition`), or expressions (`NonterminalKind::Expression`). The resulting `ParseOutput` object will contain syntax errors (if any), and the syntax tree corresponding to the input source code. diff --git a/documentation/public/user-guide/npm-package/using-queries.md b/documentation/public/user-guide/npm-package/using-queries.md index 194770d35e..d4333f79b1 100644 --- a/documentation/public/user-guide/npm-package/using-queries.md +++ b/documentation/public/user-guide/npm-package/using-queries.md @@ -8,7 +8,7 @@ If not specified otherwise, let's assume we already parsed a Solidity source and ## Creating and executing queries -You can create a `Query` object using `Query.parse`, which accepts a string value. These can be then used by `Cursor.query` to execute it. +You can create a `Query` object using `Query.create()`, which accepts a string value. These can be then used by `Cursor.query()` to execute it. You can pass multiple queries to a cursor to and efficiently traverse the tree looking for matches. They will be executed concurrently, returning matches in the order they appear in input. diff --git a/documentation/public/user-guide/rust-crate/using-queries.md b/documentation/public/user-guide/rust-crate/using-queries.md index 2c6e2639f1..9d64135edd 100644 --- a/documentation/public/user-guide/rust-crate/using-queries.md +++ b/documentation/public/user-guide/rust-crate/using-queries.md @@ -8,7 +8,7 @@ If not specified otherwise, let's assume we already parsed a Solidity source and ## Creating and executing queries -You can create a `Query` struct using `Query::parse`, which accepts a `&str`. These can be then used by `Cursor::query` to execute it. +You can create a `Query` struct using `Query::create()`, which accepts a `&str`. These can be then used by `Cursor::query()` to execute it. You can pass multiple queries to a cursor to and efficiently traverse the tree looking for matches. They will be executed concurrently, returning matches in the order they appear in input.