diff --git a/.changeset/dry-turtles-rhyme.md b/.changeset/dry-turtles-rhyme.md new file mode 100644 index 0000000000..ed40132859 --- /dev/null +++ b/.changeset/dry-turtles-rhyme.md @@ -0,0 +1,5 @@ +--- +"@nomicfoundation/slang": minor +--- + +Properly parse unreserved keywords in an identifier position, i.e. `from`, `emit`, `global` etc. diff --git a/crates/codegen/grammar/src/grammar.rs b/crates/codegen/grammar/src/grammar.rs index a3859f7506..da3021ee85 100644 --- a/crates/codegen/grammar/src/grammar.rs +++ b/crates/codegen/grammar/src/grammar.rs @@ -4,7 +4,7 @@ use semver::Version; use crate::parser_definition::{ParserDefinitionRef, TriviaParserDefinitionRef}; use crate::visitor::{GrammarVisitor, Visitable}; -use crate::{PrecedenceParserDefinitionRef, ScannerDefinitionRef}; +use crate::{KeywordScannerDefinitionRef, PrecedenceParserDefinitionRef, ScannerDefinitionRef}; pub struct Grammar { pub name: String, @@ -36,6 +36,7 @@ impl Grammar { #[derive(Clone)] pub enum GrammarElement { ScannerDefinition(ScannerDefinitionRef), + KeywordScannerDefinition(KeywordScannerDefinitionRef), TriviaParserDefinition(TriviaParserDefinitionRef), ParserDefinition(ParserDefinitionRef), PrecedenceParserDefinition(PrecedenceParserDefinitionRef), @@ -45,6 +46,7 @@ impl GrammarElement { pub fn name(&self) -> &'static str { match self { Self::ScannerDefinition(scanner) => scanner.name(), + Self::KeywordScannerDefinition(scanner) => scanner.name(), Self::TriviaParserDefinition(trivia_parser) => trivia_parser.name(), Self::ParserDefinition(parser) => parser.name(), Self::PrecedenceParserDefinition(precedence_parser) => precedence_parser.name(), @@ -80,6 +82,7 @@ impl Visitable for GrammarElement { fn accept_visitor(&self, visitor: &mut V) { match self { Self::ScannerDefinition(scanner) => scanner.accept_visitor(visitor), + Self::KeywordScannerDefinition(scanner) => scanner.accept_visitor(visitor), Self::TriviaParserDefinition(trivia_parser) => trivia_parser.accept_visitor(visitor), Self::ParserDefinition(parser) => parser.accept_visitor(visitor), Self::PrecedenceParserDefinition(precedence_parser) => { diff --git a/crates/codegen/grammar/src/parser_definition.rs b/crates/codegen/grammar/src/parser_definition.rs index 75c4915692..bcb123f921 100644 --- a/crates/codegen/grammar/src/parser_definition.rs +++ b/crates/codegen/grammar/src/parser_definition.rs @@ -2,7 +2,10 @@ use std::fmt::Debug; use std::rc::Rc; use crate::visitor::{GrammarVisitor, Visitable}; -use crate::{PrecedenceParserDefinitionRef, ScannerDefinitionRef, VersionQualityRange}; +use crate::{ + KeywordScannerDefinitionRef, PrecedenceParserDefinitionRef, ScannerDefinitionRef, + VersionQualityRange, +}; /// A named wrapper, used to give a name to a [`ParserDefinitionNode`]. #[derive(Clone, Debug)] @@ -59,6 +62,7 @@ pub enum ParserDefinitionNode { Sequence(Vec>), Choice(Named>), ScannerDefinition(ScannerDefinitionRef), + KeywordScannerDefinition(KeywordScannerDefinitionRef), TriviaParserDefinition(TriviaParserDefinitionRef), ParserDefinition(ParserDefinitionRef), PrecedenceParserDefinition(PrecedenceParserDefinitionRef), @@ -128,6 +132,7 @@ impl Visitable for ParserDefinitionNode { } Self::ScannerDefinition(_) + | Self::KeywordScannerDefinition(_) | Self::TriviaParserDefinition(_) | Self::ParserDefinition(_) | Self::PrecedenceParserDefinition(_) => {} diff --git a/crates/codegen/grammar/src/scanner_definition.rs b/crates/codegen/grammar/src/scanner_definition.rs index 19a0cc1e65..15e5ec8291 100644 --- a/crates/codegen/grammar/src/scanner_definition.rs +++ b/crates/codegen/grammar/src/scanner_definition.rs @@ -65,3 +65,98 @@ impl Visitable for ScannerDefinitionNode { } } } + +pub trait KeywordScannerDefinition: Debug { + fn name(&self) -> &'static str; + fn identifier_scanner(&self) -> &'static str; + fn definitions(&self) -> &[KeywordScannerDefinitionVersionedNode]; +} + +pub type KeywordScannerDefinitionRef = Rc; + +impl Visitable for KeywordScannerDefinitionRef { + fn accept_visitor(&self, visitor: &mut V) { + visitor.keyword_scanner_definition_enter(self); + } +} + +#[derive(Debug)] +pub struct KeywordScannerDefinitionVersionedNode { + // Underlying keyword scanner (i.e. identifier scanner) + pub value: KeywordScannerDefinitionNode, + /// When the keyword scanner is enabled + pub enabled: Vec, + /// When the keyword is reserved, i.e. can't be used in other position (e.g. as a name) + pub reserved: Vec, +} + +#[derive(Clone, Debug)] +pub enum KeywordScannerDefinitionNode { + Optional(Box), + Sequence(Vec), + Choice(Vec), + Atom(String), + // No repeatable combinators, because keywords are assumed to be finite +} + +impl From for ScannerDefinitionNode { + fn from(val: KeywordScannerDefinitionNode) -> Self { + match val { + KeywordScannerDefinitionNode::Optional(node) => { + ScannerDefinitionNode::Optional(Box::new((*node).into())) + } + KeywordScannerDefinitionNode::Sequence(nodes) => { + ScannerDefinitionNode::Sequence(nodes.into_iter().map(Into::into).collect()) + } + KeywordScannerDefinitionNode::Atom(string) => ScannerDefinitionNode::Literal(string), + KeywordScannerDefinitionNode::Choice(nodes) => { + ScannerDefinitionNode::Choice(nodes.into_iter().map(Into::into).collect()) + } + } + } +} + +/// A [`KeywordScannerDefinitionRef`] that only has a single atom value. +/// +/// The main usage for this type is to construct a keyword trie in parser generator, as trie will +/// only work with single atom values and keyword promotion needs to additionally account for +/// keyword reservation, rather than just literal presence. +#[derive(Clone)] +pub struct KeywordScannerAtomic(KeywordScannerDefinitionRef); + +impl KeywordScannerAtomic { + /// Wraps the keyword scanner definition if it is a single atom value. + pub fn try_from_def(def: &KeywordScannerDefinitionRef) -> Option { + match def.definitions() { + [KeywordScannerDefinitionVersionedNode { + value: KeywordScannerDefinitionNode::Atom(_), + .. + }] => Some(Self(def.clone())), + _ => None, + } + } +} + +impl std::ops::Deref for KeywordScannerAtomic { + type Target = KeywordScannerDefinitionRef; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl KeywordScannerAtomic { + pub fn definition(&self) -> &KeywordScannerDefinitionVersionedNode { + let def = &self.0.definitions().get(0); + def.expect("KeywordScannerAtomic should have exactly one definition") + } + pub fn value(&self) -> &str { + match self.definition() { + KeywordScannerDefinitionVersionedNode { + value: KeywordScannerDefinitionNode::Atom(atom), + .. + } => atom, + _ => unreachable!("KeywordScannerAtomic should have a single atom value"), + } + } +} diff --git a/crates/codegen/grammar/src/visitor.rs b/crates/codegen/grammar/src/visitor.rs index d6ce34521d..874092fb5e 100644 --- a/crates/codegen/grammar/src/visitor.rs +++ b/crates/codegen/grammar/src/visitor.rs @@ -1,7 +1,7 @@ use crate::{ - Grammar, ParserDefinitionNode, ParserDefinitionRef, PrecedenceParserDefinitionNode, - PrecedenceParserDefinitionRef, ScannerDefinitionNode, ScannerDefinitionRef, - TriviaParserDefinitionRef, + Grammar, KeywordScannerDefinitionRef, ParserDefinitionNode, ParserDefinitionRef, + PrecedenceParserDefinitionNode, PrecedenceParserDefinitionRef, ScannerDefinitionNode, + ScannerDefinitionRef, TriviaParserDefinitionRef, }; pub trait GrammarVisitor { @@ -9,6 +9,7 @@ pub trait GrammarVisitor { fn grammar_leave(&mut self, _grammar: &Grammar) {} fn scanner_definition_enter(&mut self, _scanner: &ScannerDefinitionRef) {} + fn keyword_scanner_definition_enter(&mut self, _scanner: &KeywordScannerDefinitionRef) {} fn trivia_parser_definition_enter(&mut self, _trivia_parser: &TriviaParserDefinitionRef) {} fn parser_definition_enter(&mut self, _parser: &ParserDefinitionRef) {} fn precedence_parser_definition_enter(&mut self, _parser: &PrecedenceParserDefinitionRef) {} diff --git a/crates/codegen/parser/generator/src/keyword_scanner_definition.rs b/crates/codegen/parser/generator/src/keyword_scanner_definition.rs new file mode 100644 index 0000000000..2a7af0e1a7 --- /dev/null +++ b/crates/codegen/parser/generator/src/keyword_scanner_definition.rs @@ -0,0 +1,88 @@ +use codegen_grammar::{ + KeywordScannerDefinitionNode, KeywordScannerDefinitionRef, ScannerDefinitionNode, +}; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; + +use crate::parser_definition::VersionQualityRangeVecExtensions; +use crate::scanner_definition::ScannerDefinitionNodeExtensions; + +pub trait KeywordScannerDefinitionExtensions { + fn to_scanner_code(&self) -> TokenStream; +} + +impl KeywordScannerDefinitionExtensions for KeywordScannerDefinitionRef { + fn to_scanner_code(&self) -> TokenStream { + let name_ident = format_ident!("{}", self.name()); + let token_kind = quote! { TokenKind::#name_ident }; + + let kw_scanners: Vec<_> = self + .definitions() + .iter() + .map(|versioned_kw| { + let scanner = versioned_kw.value.to_scanner_code(); + let enabled_cond = versioned_kw.enabled.as_bool_expr(); + let reserved_cond = versioned_kw.reserved.as_bool_expr(); + + // Simplify the emitted code if we trivially know that reserved or enabled is true + match (&*reserved_cond.to_string(), &*enabled_cond.to_string()) { + ("true", _) => quote! { + if #scanner { + KeywordScan::Reserved(#token_kind) + } else { + KeywordScan::Absent + } + }, + ("false", _) => quote! { + if #enabled_cond && #scanner { + KeywordScan::Present(#token_kind) + } else { + KeywordScan::Absent + } + }, + (_, "true") => quote! { + if #scanner { + if #reserved_cond { + KeywordScan::Reserved(#token_kind) + } else { + KeywordScan::Present(#token_kind) + } + } else { + KeywordScan::Absent + } + }, + (_, "false") => quote! { + if #reserved_cond && #scanner { + KeywordScan::Reserved(#token_kind) + } else { + KeywordScan::Absent + } + }, + _ => quote! { + if (#reserved_cond || #enabled_cond) && #scanner { + if #reserved_cond { + KeywordScan::Reserved(#token_kind) + } else { + KeywordScan::Present(#token_kind) + } + } else { + KeywordScan::Absent + } + }, + } + }) + .collect(); + + match &kw_scanners[..] { + [] => quote! { KeywordScan::Absent }, + multiple => quote! { scan_keyword_choice!(input, ident, #(#multiple),*) }, + } + } +} + +impl KeywordScannerDefinitionExtensions for KeywordScannerDefinitionNode { + fn to_scanner_code(&self) -> TokenStream { + // This is a subset; let's reuse that + ScannerDefinitionNode::from(self.clone()).to_scanner_code() + } +} diff --git a/crates/codegen/parser/generator/src/lib.rs b/crates/codegen/parser/generator/src/lib.rs index 44c7c9f8b1..12829266bb 100644 --- a/crates/codegen/parser/generator/src/lib.rs +++ b/crates/codegen/parser/generator/src/lib.rs @@ -1,4 +1,5 @@ mod ast_model; +mod keyword_scanner_definition; mod parser_definition; mod precedence_parser_definition; mod rust_generator; diff --git a/crates/codegen/parser/generator/src/parser_definition.rs b/crates/codegen/parser/generator/src/parser_definition.rs index 3c03e519cb..536f1abe6e 100644 --- a/crates/codegen/parser/generator/src/parser_definition.rs +++ b/crates/codegen/parser/generator/src/parser_definition.rs @@ -5,6 +5,7 @@ use codegen_grammar::{ use inflector::Inflector; use proc_macro2::TokenStream; use quote::{format_ident, quote}; +use semver::Version; pub trait ParserDefinitionExtensions { fn to_parser_code(&self) -> TokenStream; @@ -138,6 +139,21 @@ impl ParserDefinitionNodeExtensions for ParserDefinitionNode { } } + // Keyword scanner uses the promotion inside the parse_token + Self::KeywordScannerDefinition(scanner_definition) => { + let kind = format_ident!("{name}", name = scanner_definition.name()); + + let parse_token = if is_trivia { + format_ident!("parse_token") + } else { + format_ident!("parse_token_with_trivia") + }; + + quote! { + self.#parse_token::<#lex_ctx>(input, TokenKind::#kind) + } + } + Self::TriviaParserDefinition(trivia_parser_definition) => { let function_name = format_ident!("{}", trivia_parser_definition.name().to_snake_case()); @@ -299,13 +315,24 @@ impl ParserDefinitionNodeExtensions for ParserDefinitionNode { pub trait VersionQualityRangeVecExtensions { fn wrap_code(&self, if_true: TokenStream, if_false: Option) -> TokenStream; + // Quotes a boolean expression that is satisfied for the given version quality ranges + fn as_bool_expr(&self) -> TokenStream; } impl VersionQualityRangeVecExtensions for Vec { - fn wrap_code(&self, if_true: TokenStream, if_false: Option) -> TokenStream { + fn as_bool_expr(&self) -> TokenStream { if self.is_empty() { - if_true + quote!(true) } else { + // Optimize for legibility; return `false` for "never enabled" + match self.as_slice() { + [VersionQualityRange { + from, + quality: VersionQuality::Removed, + }] if from == &Version::new(0, 0, 0) => return quote!(false), + _ => {} + } + let flags = self.iter().map(|vqr| { let flag = format_ident!( "version_is_at_least_{v}", @@ -317,8 +344,18 @@ impl VersionQualityRangeVecExtensions for Vec { quote! { !self.#flag } } }); + quote! { #(#flags)&&* } + } + } + + fn wrap_code(&self, if_true: TokenStream, if_false: Option) -> TokenStream { + if self.is_empty() { + if_true + } else { + let condition = self.as_bool_expr(); + let else_part = if_false.map(|if_false| quote! { else { #if_false } }); - quote! { if #(#flags)&&* { #if_true } #else_part } + quote! { if #condition { #if_true } #else_part } } } } diff --git a/crates/codegen/parser/generator/src/rust_generator.rs b/crates/codegen/parser/generator/src/rust_generator.rs index e000d7737d..d6f8b5f5ad 100644 --- a/crates/codegen/parser/generator/src/rust_generator.rs +++ b/crates/codegen/parser/generator/src/rust_generator.rs @@ -1,12 +1,11 @@ use std::collections::{BTreeMap, BTreeSet}; -use std::mem; use std::path::Path; use anyhow::Result; use codegen_grammar::{ - Grammar, GrammarVisitor, ParserDefinitionNode, ParserDefinitionRef, - PrecedenceParserDefinitionRef, ScannerDefinitionNode, ScannerDefinitionRef, - TriviaParserDefinitionRef, + Grammar, GrammarVisitor, KeywordScannerAtomic, KeywordScannerDefinitionRef, + ParserDefinitionNode, ParserDefinitionRef, PrecedenceParserDefinitionRef, + ScannerDefinitionNode, ScannerDefinitionRef, TriviaParserDefinitionRef, }; use infra_utils::cargo::CargoWorkspace; use infra_utils::codegen::Codegen; @@ -15,6 +14,7 @@ use semver::Version; use serde::Serialize; use crate::ast_model::AstModel; +use crate::keyword_scanner_definition::KeywordScannerDefinitionExtensions; use crate::parser_definition::ParserDefinitionExtensions; use crate::precedence_parser_definition::PrecedenceParserDefinitionExtensions; use crate::scanner_definition::ScannerDefinitionExtensions; @@ -29,27 +29,30 @@ pub struct RustGenerator { trivia_kinds: BTreeSet<&'static str>, field_names: BTreeSet, - top_level_scanner_names: BTreeSet<&'static str>, - scanner_functions: Vec<(&'static str, String)>, // (name of scanner, code) - scanner_contexts: Vec, + scanner_functions: BTreeMap<&'static str, String>, // (name of scanner, code) + scanner_contexts: BTreeMap<&'static str, ScannerContext>, + keyword_compound_scanners: BTreeMap<&'static str, String>, // (name of the KW scanner, code) - parser_functions: Vec<(&'static str, String)>, // (name of parser, code) + parser_functions: BTreeMap<&'static str, String>, // (name of parser, code) #[serde(skip)] - scanner_contexts_map: BTreeMap<&'static str, ScannerContext>, + top_level_scanner_names: BTreeSet<&'static str>, #[serde(skip)] all_scanners: BTreeMap<&'static str, ScannerDefinitionRef>, #[serde(skip)] current_context_name: &'static str, } -#[derive(Serialize)] +#[derive(Default, Serialize)] struct ScannerContext { - name: &'static str, #[serde(skip)] scanner_definitions: BTreeSet<&'static str>, - alpha_literal_scanner: String, - non_alpha_literal_scanner: String, + literal_scanner: String, + keyword_compound_scanners: BTreeMap<&'static str, String>, + keyword_trie_scanner: String, + #[serde(skip)] + keyword_scanner_defs: BTreeMap<&'static str, KeywordScannerDefinitionRef>, + promotable_identifier_scanners: BTreeSet<&'static str>, compound_scanner_names: Vec<&'static str>, delimiters: BTreeMap<&'static str, &'static str>, } @@ -150,70 +153,80 @@ impl RustGenerator { fn set_current_context(&mut self, name: &'static str) { self.current_context_name = name; - self.scanner_contexts_map - .entry(name) - .or_insert_with(|| ScannerContext { - name, - scanner_definitions: BTreeSet::default(), - alpha_literal_scanner: String::new(), - non_alpha_literal_scanner: String::new(), - compound_scanner_names: vec![], - delimiters: BTreeMap::default(), - }); + self.scanner_contexts.entry(name).or_default(); + } + + fn current_context(&mut self) -> &mut ScannerContext { + self.scanner_contexts + .get_mut(&self.current_context_name) + .expect("context must be set with `set_current_context`") } } impl GrammarVisitor for RustGenerator { fn grammar_leave(&mut self, _grammar: &Grammar) { + // Expose the scanner functions that... self.scanner_functions = self .all_scanners .iter() .filter(|(name, scanner)| { - !self.top_level_scanner_names.contains(*name) || scanner.literals().is_empty() + // are compound (do not consist of only literals) + scanner.literals().is_empty() || + // but make sure to also include a scanner that is referenced by other scanners, even if not compound + !self.top_level_scanner_names.contains(*name) }) .map(|(name, scanner)| (*name, scanner.to_scanner_code().to_string())) .collect(); - self.parser_functions.sort_by(|a, b| a.0.cmp(b.0)); - self.scanner_functions.sort_by(|a, b| a.0.cmp(b.0)); + for context in self.scanner_contexts.values_mut() { + let mut literal_trie = Trie::new(); - for context in self.scanner_contexts_map.values_mut() { - let mut alpha_literal_trie = Trie::new(); - let mut non_alpha_literal_trie = Trie::new(); - let mut have_identifier_scanner = false; for scanner_name in &context.scanner_definitions { let scanner = &self.all_scanners[*scanner_name]; + let literals = scanner.literals(); if literals.is_empty() { - // Dr Hackity McHackerson - // Identifier at the end so it doesn't grab other things. - // Not a problem when we switch to a DFA. - if scanner_name == &"Identifier" { - have_identifier_scanner = true; - } else { - context.compound_scanner_names.push(scanner_name); - } + context.compound_scanner_names.push(scanner_name); } else { for literal in literals { - // This is good enough until we switch to a DFA - if literal.chars().next().unwrap().is_alphabetic() { - alpha_literal_trie.insert(literal.as_str(), scanner.clone()); - } else { - non_alpha_literal_trie.insert(literal.as_str(), scanner.clone()); - } + literal_trie.insert(&literal, scanner.clone()); } } } - context.alpha_literal_scanner = alpha_literal_trie.to_scanner_code().to_string(); - context.non_alpha_literal_scanner = - non_alpha_literal_trie.to_scanner_code().to_string(); - if have_identifier_scanner { - context.compound_scanner_names.push("Identifier"); + + context.literal_scanner = literal_trie.to_scanner_code().to_string(); + + context.promotable_identifier_scanners = context + .keyword_scanner_defs + .values() + .map(|def| def.identifier_scanner()) + .collect(); + + let mut keyword_trie = Trie::new(); + for (name, def) in &context.keyword_scanner_defs { + match KeywordScannerAtomic::try_from_def(def) { + Some(atomic) => keyword_trie.insert(atomic.value(), atomic.clone()), + None => { + context + .keyword_compound_scanners + .insert(name, def.to_scanner_code().to_string()); + } + } } + + context.keyword_trie_scanner = keyword_trie.to_scanner_code().to_string(); } - self.scanner_contexts = mem::take(&mut self.scanner_contexts_map) - .into_values() + // Collect all of the keyword scanners into a single list to be defined at top-level + self.keyword_compound_scanners = self + .scanner_contexts + .values() + .flat_map(|context| { + context + .keyword_compound_scanners + .iter() + .map(|(name, code)| (*name, code.clone())) + }) .collect(); // Make sure empty strings are not there @@ -236,11 +249,25 @@ impl GrammarVisitor for RustGenerator { self.all_scanners.insert(scanner.name(), scanner.clone()); } + fn keyword_scanner_definition_enter(&mut self, scanner: &KeywordScannerDefinitionRef) { + for def in scanner.definitions() { + let versions = def.enabled.iter().chain(def.reserved.iter()); + + self.referenced_versions.extend( + versions + .map(|vqr| &vqr.from) + // "Removed from 0.0.0" is an alias for "never"; it's never directly checked + .filter(|v| *v != &Version::new(0, 0, 0)) + .cloned(), + ); + } + } + fn trivia_parser_definition_enter(&mut self, parser: &TriviaParserDefinitionRef) { self.set_current_context(parser.context()); self.rule_kinds.insert(parser.name()); self.trivia_kinds.insert(parser.name()); - self.parser_functions.push(( + self.parser_functions.insert( parser.name(), { let code = parser.to_parser_code(); @@ -248,7 +275,7 @@ impl GrammarVisitor for RustGenerator { quote! { #code.with_kind(RuleKind::#rule_kind) } } .to_string(), - )); + ); } fn parser_definition_enter(&mut self, parser: &ParserDefinitionRef) { @@ -257,14 +284,14 @@ impl GrammarVisitor for RustGenerator { if !parser.is_inline() { self.rule_kinds.insert(parser.name()); let code = parser.to_parser_code(); - self.parser_functions.push(( + self.parser_functions.insert( parser.name(), { let rule_kind = format_ident!("{}", parser.name()); quote! { #code.with_kind(RuleKind::#rule_kind) } } .to_string(), - )); + ); } } @@ -278,10 +305,10 @@ impl GrammarVisitor for RustGenerator { // While it's not common to parse a precedence expression as a standalone rule, // we generate a function for completeness. for (name, code) in parser.to_precedence_expression_parser_code() { - self.parser_functions.push((name, code.to_string())); + self.parser_functions.insert(name, code.to_string()); } - self.parser_functions.push(( + self.parser_functions.insert( parser.name(), { let code = parser.to_parser_code(); @@ -289,7 +316,7 @@ impl GrammarVisitor for RustGenerator { quote! { #code.with_kind(RuleKind::#rule_kind) } } .to_string(), - )); + ); } fn scanner_definition_node_enter(&mut self, node: &ScannerDefinitionNode) { @@ -310,12 +337,18 @@ impl GrammarVisitor for RustGenerator { ParserDefinitionNode::ScannerDefinition(scanner) => { self.top_level_scanner_names.insert(scanner.name()); self.token_kinds.insert(scanner.name()); - self.scanner_contexts_map - .get_mut(&self.current_context_name) - .unwrap() + + self.current_context() .scanner_definitions .insert(scanner.name()); } + ParserDefinitionNode::KeywordScannerDefinition(scanner) => { + self.token_kinds.insert(scanner.name()); + + self.current_context() + .keyword_scanner_defs + .insert(scanner.name(), scanner.clone()); + } // Collect field names ParserDefinitionNode::Choice(choice) => { @@ -347,11 +380,7 @@ impl GrammarVisitor for RustGenerator { _ => panic!("DelimitedBy must be delimited by scanners"), }; - let delimiters = &mut self - .scanner_contexts_map - .get_mut(&self.current_context_name) - .unwrap() - .delimiters; + let delimiters = &mut self.current_context().delimiters; assert!( delimiters.get(close).is_none(), diff --git a/crates/codegen/parser/generator/src/trie.rs b/crates/codegen/parser/generator/src/trie.rs index 5d8f1f5d8c..b07f69b3cf 100644 --- a/crates/codegen/parser/generator/src/trie.rs +++ b/crates/codegen/parser/generator/src/trie.rs @@ -1,20 +1,23 @@ use std::collections::BTreeMap; use std::fmt::Debug; -use codegen_grammar::{ScannerDefinitionNode, ScannerDefinitionRef}; +use codegen_grammar::{ + KeywordScannerAtomic, KeywordScannerDefinitionVersionedNode, ScannerDefinitionNode, + ScannerDefinitionRef, VersionQualityRange, +}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; use crate::parser_definition::VersionQualityRangeVecExtensions; #[derive(Clone, Debug, Default)] -pub struct Trie { +pub struct Trie { pub subtries: BTreeMap, pub key: Option, - pub payload: Option, + pub payload: Option, } -impl Trie { +impl Trie { pub fn new() -> Self { Self { subtries: BTreeMap::new(), @@ -23,7 +26,7 @@ impl Trie { } } - pub fn insert(&mut self, key: &str, payload: ScannerDefinitionRef) { + pub fn insert(&mut self, key: &str, payload: T) { let mut node = self; for char in key.chars() { node = node.subtries.entry(char).or_insert_with(Self::new); @@ -34,7 +37,7 @@ impl Trie { // Finds the next node that has either a payload or more than one subtrie // It returns the path to that node and the node itself - pub fn next_interesting_node(&self, prefix: Option) -> (Vec, &Trie) { + pub fn next_interesting_node(&self, prefix: Option) -> (Vec, &Self) { let mut path = prefix.map(|c| vec![c]).unwrap_or_default(); let mut node = self; while node.payload.is_none() && node.subtries.len() == 1 { @@ -57,32 +60,10 @@ impl Trie { }) .collect::>(); - let leaf = if let Some(scanner_definition_ref) = &trie.payload { - let kind = format_ident!("{}", scanner_definition_ref.name()); - - if branches.is_empty() && !path.is_empty() { - // This is an optimisation for a common case - let leaf = quote! { scan_chars!(input, #(#path),*).then_some(TokenKind::#kind) }; - return if let ScannerDefinitionNode::Versioned(_, version_quality_ranges) = - scanner_definition_ref.node() - { - version_quality_ranges.wrap_code(leaf, Some(quote! { None })) - } else { - leaf - }; - } - - if let ScannerDefinitionNode::Versioned(_, version_quality_ranges) = - scanner_definition_ref.node() - { - version_quality_ranges - .wrap_code(quote! { Some(TokenKind::#kind) }, Some(quote! { None })) - } else { - quote! { Some(TokenKind::#kind) } - } - } else { - quote! { None } - }; + let leaf = trie + .payload + .as_ref() + .map_or_else(T::default_case, T::to_leaf_code); let trie_code = if branches.is_empty() { leaf @@ -96,6 +77,7 @@ impl Trie { } }; + let default_case = T::default_case(); if path.is_empty() { trie_code } else { @@ -103,9 +85,113 @@ impl Trie { if scan_chars!(input, #(#path),*) { #trie_code } else { - None + #default_case } } } } } + +trait VersionWrapped { + fn applicable_version_quality_ranges(&self) -> Vec; +} + +impl VersionWrapped for ScannerDefinitionNode { + fn applicable_version_quality_ranges(&self) -> Vec { + match self { + ScannerDefinitionNode::Versioned(_, version_quality_ranges) => { + version_quality_ranges.clone() + } + + ScannerDefinitionNode::Optional(node) + | ScannerDefinitionNode::ZeroOrMore(node) + | ScannerDefinitionNode::OneOrMore(node) => node.applicable_version_quality_ranges(), + + _ => vec![], + } + } +} + +/// Used together with [`Trie`]. Represents the payload of a trie node and can be used to customize +/// the emitted code. +/// +/// Implemented for [`ScannerDefinitionRef`] and [`KeywordScannerAtomic`], allows to create +/// tries for both literal scanner definitions and keyword scanners. +pub trait Payload { + fn to_leaf_code(&self) -> TokenStream; + fn default_case() -> TokenStream; +} + +impl Payload for ScannerDefinitionRef { + fn to_leaf_code(&self) -> TokenStream { + let kind = format_ident!("{}", self.name()); + + self.node().applicable_version_quality_ranges().wrap_code( + quote! { Some(TokenKind::#kind) }, + Some(Self::default_case()), + ) + } + + fn default_case() -> TokenStream { + quote! { None } + } +} + +impl Payload for KeywordScannerAtomic { + fn to_leaf_code(&self) -> TokenStream { + let kind = format_ident!("{}", self.name()); + + let KeywordScannerDefinitionVersionedNode { + enabled, reserved, .. + } = self.definition(); + + let enabled_cond = enabled.as_bool_expr(); + let reserved_cond = reserved.as_bool_expr(); + + // Simplify the emitted code if we trivially know that reserved or enabled is true + match (&*reserved_cond.to_string(), &*enabled_cond.to_string()) { + ("true", _) => quote!(KeywordScan::Reserved(TokenKind::#kind)), + ("false", _) => quote! { + if #enabled_cond { + KeywordScan::Present(TokenKind::#kind) + } else { + KeywordScan::Absent + } + }, + (_, "false") => quote! { + if #reserved_cond { + KeywordScan::Reserved(TokenKind::#kind) + } else { + KeywordScan::Absent + } + }, + (_, "true") => quote! { + if #reserved_cond { + KeywordScan::Reserved(TokenKind::#kind) + } else { + KeywordScan::Present(TokenKind::#kind) + } + }, + (reserved, enabled) if reserved == enabled => quote! { + if #reserved_cond { + KeywordScan::Reserved(TokenKind::#kind) + } else { + KeywordScan::Absent + } + }, + _ => quote! { + if #reserved_cond { + KeywordScan::Reserved(TokenKind::#kind) + } else if #enabled_cond { + KeywordScan::Present(TokenKind::#kind) + } else { + KeywordScan::Absent + } + }, + } + } + + fn default_case() -> TokenStream { + quote! { KeywordScan::Absent } + } +} diff --git a/crates/codegen/parser/runtime/src/lexer.rs b/crates/codegen/parser/runtime/src/lexer.rs index fdda0371e9..5923dfdf7b 100644 --- a/crates/codegen/parser/runtime/src/lexer.rs +++ b/crates/codegen/parser/runtime/src/lexer.rs @@ -2,13 +2,63 @@ use crate::cst::{self, NamedNode}; use crate::kinds::{IsLexicalContext, TokenKind}; use crate::support::{ParserContext, ParserResult}; +/// Whether a keyword has been scanned and if so, whether it is reserved (unusable as an identifier) +/// or not. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KeywordScan { + /// The keyword is not present. + Absent, + /// The keyword is present, but is not reserved. + Present(TokenKind), + /// The keyword is present and is reserved. + Reserved(TokenKind), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ScannedToken { + Single(TokenKind), + IdentifierOrKeyword { + identifier: TokenKind, + kw: KeywordScan, + }, +} + +impl ScannedToken { + pub fn accepted_as(self, expected: TokenKind) -> bool { + match self { + Self::Single(kind) => kind == expected, + Self::IdentifierOrKeyword { identifier, kw } => match kw { + KeywordScan::Reserved(kind) => kind == expected, + KeywordScan::Present(kind) => kind == expected || identifier == expected, + KeywordScan::Absent => identifier == expected, + }, + } + } + + /// Returns the most general token kind that can be accepted for the scanned token. + /// + /// If the scanned token is an identifier, returns the specific keyword kind if the keyword is reserved, + /// otherwise returns the general identifier kind. For other tokens, returns the token kind itself. + pub fn unambiguous(self) -> TokenKind { + match self { + Self::Single(kind) => kind, + Self::IdentifierOrKeyword { identifier, kw } => match kw { + KeywordScan::Reserved(kind) => kind, + // Ambiguous; prefer using the more general identifier + KeywordScan::Present(..) => identifier, + KeywordScan::Absent => identifier, + }, + } + } +} + pub(crate) trait Lexer { // Generated by the templating engine #[doc(hidden)] fn next_token( &self, input: &mut ParserContext<'_>, - ) -> Option; + ) -> Option; // NOTE: These are context-insensitive #[doc(hidden)] fn leading_trivia(&self, input: &mut ParserContext<'_>) -> ParserResult; @@ -22,7 +72,7 @@ pub(crate) trait Lexer { fn peek_token( &self, input: &mut ParserContext<'_>, - ) -> Option { + ) -> Option { let start = input.position(); let token = self.next_token::(input); input.set_position(start); @@ -33,7 +83,7 @@ pub(crate) trait Lexer { fn peek_token_with_trivia( &self, input: &mut ParserContext<'_>, - ) -> Option { + ) -> Option { let start = input.position(); let _ = self.leading_trivia(input); @@ -50,7 +100,10 @@ pub(crate) trait Lexer { kind: TokenKind, ) -> ParserResult { let start = input.position(); - if self.next_token::(input) != Some(kind) { + if !self + .next_token::(input) + .is_some_and(|t| t.accepted_as(kind)) + { input.set_position(start); return ParserResult::no_match(vec![kind]); } @@ -82,7 +135,10 @@ pub(crate) trait Lexer { } let start = input.position(); - if self.next_token::(input) != Some(kind) { + if !self + .next_token::(input) + .is_some_and(|t| t.accepted_as(kind)) + { input.set_position(restore); return ParserResult::no_match(vec![kind]); } diff --git a/crates/codegen/parser/runtime/src/support/recovery.rs b/crates/codegen/parser/runtime/src/support/recovery.rs index f878372569..0df7a28b87 100644 --- a/crates/codegen/parser/runtime/src/support/recovery.rs +++ b/crates/codegen/parser/runtime/src/support/recovery.rs @@ -1,6 +1,6 @@ use crate::cst; use crate::kinds::{IsLexicalContext, TokenKind}; -use crate::lexer::Lexer; +use crate::lexer::{Lexer, ScannedToken}; use crate::parse_error::ParseError; use crate::support::context::ParserContext; use crate::support::parser_result::SkippedUntil; @@ -63,7 +63,10 @@ impl ParserResult { ParseResultKind::Incomplete, ), ParserResult::Match(result) - if lexer.peek_token_with_trivia::(input) != Some(expected) => + if lexer + .peek_token_with_trivia::(input) + .map(ScannedToken::unambiguous) + != Some(expected) => { (result.nodes, result.expected_tokens, ParseResultKind::Match) } @@ -129,7 +132,10 @@ pub(crate) fn skip_until_with_nested_delims( let mut local_delims = vec![]; loop { let save = input.position(); - match lexer.next_token::(input) { + match lexer + .next_token::(input) + .map(ScannedToken::unambiguous) + { // If we're not skipping past a local delimited group (delimiter stack is empty), // we can unwind on a token that's expected by us or by our ancestor. Some(token) diff --git a/crates/codegen/parser/runtime/src/support/scanner_macros.rs b/crates/codegen/parser/runtime/src/support/scanner_macros.rs index 32cefbf03f..ad9e5f25e3 100644 --- a/crates/codegen/parser/runtime/src/support/scanner_macros.rs +++ b/crates/codegen/parser/runtime/src/support/scanner_macros.rs @@ -66,6 +66,26 @@ macro_rules! scan_choice { }; } +#[allow(unused_macros)] +macro_rules! scan_keyword_choice { + ($stream:ident, $ident:ident, $($scanner:expr),*) => { + loop { + let save = $stream.position(); + $( + { + if let result @ (KeywordScan::Present(..) | KeywordScan::Reserved(..)) = ($scanner) { + if $ident.len() == $stream.position().utf8 - save.utf8 { + break result; + } + } + } + $stream.set_position(save); + )* + break KeywordScan::Absent; + } + }; +} + #[allow(unused_macros)] macro_rules! scan_zero_or_more { ($stream:ident, $scanner:expr) => { diff --git a/crates/codegen/parser/runtime/src/support/separated_helper.rs b/crates/codegen/parser/runtime/src/support/separated_helper.rs index c79b5cc796..ec586ffdd4 100644 --- a/crates/codegen/parser/runtime/src/support/separated_helper.rs +++ b/crates/codegen/parser/runtime/src/support/separated_helper.rs @@ -24,7 +24,7 @@ impl SeparatedHelper { accum.extend(r#match.nodes); match lexer.peek_token_with_trivia::(input) { - Some(token) if token == separator => { + Some(scanned) if scanned.accepted_as(separator) => { match lexer .parse_token_with_trivia::(input, separator) .with_name(separator_field_name) diff --git a/crates/codegen/parser/runtime/src/templates/kinds.rs.jinja2 b/crates/codegen/parser/runtime/src/templates/kinds.rs.jinja2 index 6659de214d..d03ef26d6b 100644 --- a/crates/codegen/parser/runtime/src/templates/kinds.rs.jinja2 +++ b/crates/codegen/parser/runtime/src/templates/kinds.rs.jinja2 @@ -86,8 +86,8 @@ pub enum TokenKind { /// The lexical context of the scanner. #[derive(strum_macros::FromRepr, Clone, Copy)] pub(crate) enum LexicalContext { - {%- for context in code.scanner_contexts %} - {{ context.name }}, + {%- for context_name, _context in code.scanner_contexts %} + {{ context_name }}, {%- endfor %} } @@ -101,11 +101,11 @@ pub(crate) trait IsLexicalContext { pub(crate) mod LexicalContextType { use super::{IsLexicalContext, LexicalContext}; - {%- for context in code.scanner_contexts %} - pub struct {{ context.name }} {} - impl IsLexicalContext for {{ context.name }} { + {%- for context_name, _ in code.scanner_contexts %} + pub struct {{ context_name }} {} + impl IsLexicalContext for {{ context_name }} { fn value() -> LexicalContext { - LexicalContext::{{ context.name }} + LexicalContext::{{ context_name }} } } {%- endfor %} diff --git a/crates/codegen/parser/runtime/src/templates/language.rs.jinja2 b/crates/codegen/parser/runtime/src/templates/language.rs.jinja2 index 3a39c6234e..877f71f29c 100644 --- a/crates/codegen/parser/runtime/src/templates/language.rs.jinja2 +++ b/crates/codegen/parser/runtime/src/templates/language.rs.jinja2 @@ -15,7 +15,7 @@ use crate::cst; use crate::kinds::{ FieldName, IsLexicalContext, LexicalContext, LexicalContextType, RuleKind, TokenKind, }; -use crate::lexer::Lexer; +use crate::lexer::{KeywordScan, Lexer, ScannedToken}; #[cfg(feature = "slang_napi_interfaces")] use crate::napi::napi_parse_output::ParseOutput as NAPIParseOutput; use crate::parse_output::ParseOutput; @@ -78,24 +78,30 @@ impl Language { * Parser Functions ********************************************/ - {% for function in code.parser_functions %} + {% for parser_name, parser_code in code.parser_functions %} #[allow(unused_assignments, unused_parens)] - fn {{ function.0 | snake_case }}(&self, input: &mut ParserContext<'_>) -> ParserResult { {{ function.1 }} } + fn {{ parser_name | snake_case }}(&self, input: &mut ParserContext<'_>) -> ParserResult { {{ parser_code }} } {% endfor %} /******************************************** * Scanner Functions ********************************************/ - {% for function in code.scanner_functions %} + {% for scanner_name, scanner_code in code.scanner_functions %} #[allow(unused_assignments, unused_parens)] - fn {{ function.0 | snake_case }}(&self, input: &mut ParserContext<'_>) -> bool { {{ function.1 }} } + fn {{ scanner_name | snake_case }}(&self, input: &mut ParserContext<'_>) -> bool { {{ scanner_code }} } + {% endfor %} + + // Keyword scanners + {%- for keyword_name, code in code.keyword_compound_scanners %} + #[inline] + fn {{ keyword_name | snake_case }}(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { {{ code }} } {% endfor %} pub fn parse(&self, kind: RuleKind, input: &str) -> ParseOutput { match kind { - {%- for function in code.parser_functions -%} - RuleKind::{{ function.0 }} => Self::{{ function.0 | snake_case }}.parse(self, input), + {%- for parser_name, _code in code.parser_functions -%} + RuleKind::{{ parser_name }} => Self::{{ parser_name | snake_case }}.parse(self, input), {%- endfor -%} } } @@ -112,8 +118,8 @@ impl Lexer for Language { fn delimiters() -> &'static [(TokenKind, TokenKind)] { match LexCtx::value() { - {%- for context in code.scanner_contexts %} - LexicalContext::{{ context.name }} => &[ + {%- for context_name, context in code.scanner_contexts %} + LexicalContext::{{ context_name }} => &[ {%- for open, close in context.delimiters %} (TokenKind::{{ open }}, TokenKind::{{ close }}), {%- endfor %} @@ -122,62 +128,104 @@ impl Lexer for Language { } } - fn next_token(&self, input: &mut ParserContext<'_>) -> Option { + fn next_token(&self, input: &mut ParserContext<'_>) -> Option { let save = input.position(); let mut furthest_position = input.position(); let mut longest_token = None; - match LexCtx::value() { - {%- for context in code.scanner_contexts %} - LexicalContext::{{ context.name }} => { - macro_rules! longest_match { - ($( { $kind:ident = $function:ident } )*) => { - $( - if self.$function(input) && input.position() > furthest_position { - furthest_position = input.position(); - longest_token = Some(TokenKind::$kind); - } - input.set_position(save); - )* - }; - } + macro_rules! longest_match { + ($( { $kind:ident = $function:ident } )*) => { + $( + if self.$function(input) && input.position() > furthest_position { + furthest_position = input.position(); - if let Some(kind) = {{ context.alpha_literal_scanner }} { - // Make sure that this is not the start of an identifier - if !self.identifier_part(input) { - furthest_position = input.position(); - longest_token = Some(kind); - } + longest_token = Some(TokenKind::$kind); } input.set_position(save); + )* + }; + } - if let Some(kind) = {{ context.non_alpha_literal_scanner }} { + match LexCtx::value() { + {%- for context_name, context in code.scanner_contexts %} + LexicalContext::{{ context_name }} => { + if let Some(kind) = {{ context.literal_scanner }} { furthest_position = input.position(); longest_token = Some(kind); } input.set_position(save); - longest_match! { {%- for name in context.compound_scanner_names %} - { {{ name }} = {{ name | snake_case }} } + {%- if name not in context.promotable_identifier_scanners %} + { {{name }} = {{ name | snake_case }} } + {%- endif -%} {%- endfor %} } + // Make sure promotable identifiers are last so they don't grab other things + longest_match! { + {%- for name in context.promotable_identifier_scanners %} + { {{ name }} = {{ name | snake_case }} } + {%- endfor %} + } + + // We have an identifier; we need to check if it's a keyword + if let Some(identifier) = longest_token.filter(|tok| + [ + {% for name in context.promotable_identifier_scanners %} + TokenKind::{{ name }}, + {% endfor %} + ] + .contains(tok) + ) { + let kw_scan = {{ context.keyword_trie_scanner }}; + let kw_scan = match kw_scan { + // Strict prefix; we need to match the whole identifier to promote + _ if input.position() < furthest_position => KeywordScan::Absent, + value => value, + }; + + {% if context.keyword_compound_scanners | length > 0 %} + // Perf: only scan for a compound keyword if we didn't already find one + let mut kw_scan = kw_scan; + if kw_scan == KeywordScan::Absent { + input.set_position(save); + + // TODO: Don't allocate a string here + let ident_value = input.content(save.utf8..furthest_position.utf8); + + for keyword_compound_scanner in [ + {%- for keyword_name, _ in context.keyword_compound_scanners %} + Self::{{ keyword_name | snake_case }}, + {%- endfor %} + ] { + match keyword_compound_scanner(self, input, &ident_value) { + _ if input.position() < furthest_position => {/* Strict prefix */}, + KeywordScan::Absent => {}, + value => kw_scan = value, + } + input.set_position(save); + } + } + {% endif %} + + input.set_position(furthest_position); + return Some(ScannedToken::IdentifierOrKeyword { identifier, kw: kw_scan }); + } }, {%- endfor %} } match longest_token { - Some(..) => { + Some(token) => { input.set_position(furthest_position); - longest_token + Some(ScannedToken::Single(token)) }, // Skip a character if possible and if we didn't recognize a token None if input.peek().is_some() => { let _ = input.next(); - Some(TokenKind::SKIPPED) + Some(ScannedToken::Single(TokenKind::SKIPPED)) }, - // EOF None => None, } } diff --git a/crates/solidity/inputs/language/src/grammar.rs b/crates/solidity/inputs/language/src/grammar.rs index 902f62b105..caf39b4022 100644 --- a/crates/solidity/inputs/language/src/grammar.rs +++ b/crates/solidity/inputs/language/src/grammar.rs @@ -7,13 +7,13 @@ use std::ops::Deref; use std::rc::Rc; use codegen_grammar::{ - Grammar, GrammarElement, Named, ParserDefinition, ParserDefinitionNode, + Grammar, GrammarElement, KeywordScannerDefinition, KeywordScannerDefinitionNode, + KeywordScannerDefinitionVersionedNode, Named, ParserDefinition, ParserDefinitionNode, PrecedenceOperatorModel, PrecedenceParserDefinition, PrecedenceParserDefinitionNode, ScannerDefinition, ScannerDefinitionNode, TriviaParserDefinition, VersionQuality, VersionQualityRange, }; -use codegen_language_definition::model; -use codegen_language_definition::model::{FieldsErrorRecovery, Identifier, Item}; +use codegen_language_definition::model::{self, FieldsErrorRecovery, Identifier, Item}; use indexmap::IndexMap; /// Materializes the DSL v2 model ([`model::Language`]) into [`Grammar`]. @@ -175,6 +175,27 @@ impl ScannerDefinition for NamedScanner { } } +#[derive(Debug)] +struct NamedKeywordScanner { + name: &'static str, + identifier_scanner_name: &'static str, + defs: Vec, +} + +impl KeywordScannerDefinition for NamedKeywordScanner { + fn name(&self) -> &'static str { + self.name + } + + fn definitions(&self) -> &[codegen_grammar::KeywordScannerDefinitionVersionedNode] { + &self.defs + } + + fn identifier_scanner(&self) -> &'static str { + self.identifier_scanner_name + } +} + #[derive(Debug)] struct NamedTriviaParser { name: &'static str, @@ -262,7 +283,11 @@ impl ParserThunk { } } -fn enabled_to_range(spec: model::VersionSpecifier) -> Vec { +fn enabled_to_range(spec: impl Into>) -> Vec { + let Some(spec) = spec.into() else { + return vec![]; + }; + match spec { model::VersionSpecifier::Never => vec![VersionQualityRange { from: semver::Version::new(0, 0, 0), @@ -409,10 +434,32 @@ fn resolve_grammar_element(ident: &Identifier, ctx: &mut ResolveCtx<'_>) -> Gram name: ident.to_string().leak(), def: resolve_token(item.deref().clone(), ctx), }, - Item::Keyword { item } => NamedScanner { - name: ident.to_string().leak(), - def: resolve_keyword(item.deref().clone()), - }, + Item::Keyword { item } => { + let defs: Vec<_> = item + .definitions + .iter() + .cloned() + .map(|def| { + let value = resolve_keyword_value(def.value); + KeywordScannerDefinitionVersionedNode { + value, + enabled: enabled_to_range(def.enabled), + reserved: enabled_to_range(def.reserved), + } + }) + .collect(); + + let kw_scanner = NamedKeywordScanner { + name: ident.to_string().leak(), + identifier_scanner_name: item.identifier.to_string().leak(), + defs, + }; + + // Keywords are special scanners and are handled separately + let resolved = GrammarElement::KeywordScannerDefinition(Rc::new(kw_scanner)); + ctx.resolved.insert(ident.clone(), resolved.clone()); + return resolved; + } _ => unreachable!("Only terminals can be resolved here"), }; @@ -490,59 +537,18 @@ fn resolve_token(token: model::TokenItem, ctx: &mut ResolveCtx<'_>) -> ScannerDe } } -fn resolve_keyword(keyword: model::KeywordItem) -> ScannerDefinitionNode { - // TODO(#568): Handle reserved keywords using the given "Identifier" parser - let _ = keyword.identifier; - - let defs: Vec<_> = keyword - .definitions - .into_iter() - .map(|def| { - let value = resolve_keyword_value(def.value); - // If missing, the default is "Always" - match (def.enabled, def.reserved) { - // Contextual keywords (never reserved) - // TODO(#568): Properly support contextual keywords. - // Currently, to minimize the diff and ease the transition to the DSL v2, we treat them as normal keywords. - // Moreover, since the DSL v1 only treats "enablement" as being reserved, we try to preserve that for now. - (enabled, Some(model::VersionSpecifier::Never)) => value.versioned(enabled), - // TODO(#568): If a contextual keyword was enabled at some point and then reserved, for now we treat it - // as a reserved keyword starting from when it was being used, to preserve the DSL v1 behaviour. - ( - Some(model::VersionSpecifier::From { from: enabled }), - Some(model::VersionSpecifier::From { from: reserved }), - ) if enabled < reserved => ScannerDefinitionNode::Versioned( - Box::new(value), - enabled_to_range(model::VersionSpecifier::From { from: enabled }), - ), - (_, Some(reserved)) => { - ScannerDefinitionNode::Versioned(Box::new(value), enabled_to_range(reserved)) - } - // The keyword is always reserved - (_, None) => value, - } - }) - .collect(); - - match defs.len() { - 0 => panic!("Keyword {} has no definitions", keyword.name), - 1 => defs.into_iter().next().unwrap(), - _ => ScannerDefinitionNode::Choice(defs), - } -} - -fn resolve_keyword_value(value: model::KeywordValue) -> ScannerDefinitionNode { +fn resolve_keyword_value(value: model::KeywordValue) -> KeywordScannerDefinitionNode { match value { - model::KeywordValue::Sequence { values } => { - ScannerDefinitionNode::Sequence(values.into_iter().map(resolve_keyword_value).collect()) - } - model::KeywordValue::Choice { values } => { - ScannerDefinitionNode::Choice(values.into_iter().map(resolve_keyword_value).collect()) - } + model::KeywordValue::Sequence { values } => KeywordScannerDefinitionNode::Sequence( + values.into_iter().map(resolve_keyword_value).collect(), + ), + model::KeywordValue::Choice { values } => KeywordScannerDefinitionNode::Choice( + values.into_iter().map(resolve_keyword_value).collect(), + ), model::KeywordValue::Optional { value } => { - ScannerDefinitionNode::Optional(Box::new(resolve_keyword_value(*value))) + KeywordScannerDefinitionNode::Optional(Box::new(resolve_keyword_value(*value))) } - model::KeywordValue::Atom { atom } => ScannerDefinitionNode::Literal(atom), + model::KeywordValue::Atom { atom } => KeywordScannerDefinitionNode::Atom(atom), } } @@ -837,6 +843,9 @@ impl IntoParserDefNode for GrammarElement { GrammarElement::ScannerDefinition(parser) => { ParserDefinitionNode::ScannerDefinition(parser) } + GrammarElement::KeywordScannerDefinition(scanner) => { + ParserDefinitionNode::KeywordScannerDefinition(scanner) + } GrammarElement::TriviaParserDefinition(parser) => { ParserDefinitionNode::TriviaParserDefinition(parser) } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/language.rs b/crates/solidity/outputs/cargo/crate/src/generated/language.rs index 27de6b3b64..4f0078d1bb 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/language.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/language.rs @@ -17,7 +17,7 @@ use crate::cst; use crate::kinds::{ FieldName, IsLexicalContext, LexicalContext, LexicalContextType, RuleKind, TokenKind, }; -use crate::lexer::Lexer; +use crate::lexer::{KeywordScan, Lexer, ScannedToken}; #[cfg(feature = "slang_napi_interfaces")] use crate::napi::napi_parse_output::ParseOutput as NAPIParseOutput; use crate::parse_output::ParseOutput; @@ -6340,51 +6340,6 @@ impl Language { ) } - #[allow(unused_assignments, unused_parens)] - fn bytes_keyword(&self, input: &mut ParserContext<'_>) -> bool { - 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') - ) - ) - ) - } - #[allow(unused_assignments, unused_parens)] fn decimal_digits(&self, input: &mut ParserContext<'_>) -> bool { scan_sequence!( @@ -6531,66 +6486,403 @@ impl Language { } #[allow(unused_assignments, unused_parens)] - fn fixed_keyword(&self, input: &mut ParserContext<'_>) -> bool { + 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_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + 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 + } + ) + } + + #[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 hex_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + self.single_quoted_hex_string_literal(input), + self.double_quoted_hex_string_literal(input) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn identifier(&self, input: &mut ParserContext<'_>) -> bool { + self.raw_identifier(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 multiline_comment(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, '/'), + scan_chars!(input, '*'), + scan_zero_or_more!( + 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', '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_none_of!(input, '*'), + scan_not_followed_by!(input, scan_chars!(input, '*'), scan_chars!(input, '/')) + ) + ), + scan_chars!(input, '*'), + scan_chars!(input, '/') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn raw_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 single_line_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_ascii_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, '\''), + scan_zero_or_more!( + input, 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') + 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_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_unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + if self.version_is_at_least_0_7_0 { scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + scan_chars!(input, 'u', 'n', 'i', 'c', 'o', 'd', 'e', '\''), + scan_zero_or_more!( 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_choice!( + input, + self.escape_sequence(input), + scan_none_of!(input, '\'', '\\', '\r', '\n') + ) + ), + scan_chars!(input, '\'') + ) + } else { + false + } + } + + #[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 unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + if self.version_is_at_least_0_7_0 { + self.single_quoted_unicode_string_literal(input) + } else { + false + }, + if self.version_is_at_least_0_7_0 { + self.double_quoted_unicode_string_literal(input) + } else { + false + } + ) + } + + #[allow(unused_assignments, unused_parens)] + fn version_pragma_value(&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 { + self.raw_identifier(input) + } + + // Keyword scanners + #[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(TokenKind::BytesKeyword) + } else { + KeywordScan::Absent + } + ) + } + + #[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(TokenKind::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(TokenKind::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'), @@ -6627,75 +6919,213 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '2', '4'), scan_chars!(input, '1', '8', '4', 'x', '1', '6') ) - ), - if self.version_is_at_least_0_4_14 { - 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(TokenKind::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(TokenKind::FixedKeyword) + } else { + KeywordScan::Present(TokenKind::FixedKeyword) + } } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 { - scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + 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(TokenKind::FixedKeyword) + } else { + KeywordScan::Present(TokenKind::FixedKeyword) + } + } else { + KeywordScan::Absent + } + ) + } + + #[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'), @@ -6730,373 +7160,73 @@ impl Language { 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(TokenKind::IntKeyword) } else { - false + KeywordScan::Absent } ) } - #[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!( + #[inline] + fn ufixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_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)) - ) - ) + ident, + if scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TokenKind::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') ), - self.identifier_start(input) - ), - if !self.version_is_at_least_0_5_0 { - scan_not_followed_by!( + scan_chars!(input, 'x'), + scan_choice!( 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) + 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(TokenKind::UfixedKeyword) } else { - false - } - ) - } - - #[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 hex_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - self.single_quoted_hex_string_literal(input), - self.double_quoted_hex_string_literal(input) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn identifier(&self, input: &mut ParserContext<'_>) -> bool { - self.raw_identifier(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 int_keyword(&self, input: &mut ParserContext<'_>) -> bool { - 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') - ) - ) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn multiline_comment(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - 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, '*'), - scan_chars!(input, '/') - ) - } - - #[allow(unused_assignments, unused_parens)] - fn raw_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 single_line_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_ascii_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - 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_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_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 ufixed_keyword(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - 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') - ) - ), - scan_sequence!( + KeywordScan::Absent + }, + if scan_sequence!( scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7146,198 +7276,82 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '2', '4'), scan_chars!(input, '1', '8', '4', 'x', '1', '6') ) - ), - if self.version_is_at_least_0_4_14 { - 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(TokenKind::UfixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 { - 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 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(TokenKind::UfixedKeyword) + } else { + KeywordScan::Present(TokenKind::UfixedKeyword) + } } else { - false - } - ) - } - - #[allow(unused_assignments, unused_parens)] - fn uint_keyword(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, 'u', 'i', 'n', 't'), - scan_optional!( - input, + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, scan_chars!(input, '9', '6'), @@ -7372,137 +7386,214 @@ impl Language { 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') ) - ) - ) - } - - #[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 unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - if self.version_is_at_least_0_7_0 { - self.single_quoted_unicode_string_literal(input) - } else { - false - }, - if self.version_is_at_least_0_7_0 { - self.double_quoted_unicode_string_literal(input) + ) { + if self.version_is_at_least_0_4_14 { + KeywordScan::Reserved(TokenKind::UfixedKeyword) + } else { + KeywordScan::Present(TokenKind::UfixedKeyword) + } } else { - false + KeywordScan::Absent } ) } - #[allow(unused_assignments, unused_parens)] - fn version_pragma_value(&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!( + #[inline] + fn uint_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( input, - scan_choice!(input, scan_chars!(input, ' '), scan_chars!(input, '\t')) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_bytes_keyword(&self, input: &mut ParserContext<'_>) -> bool { - if !self.version_is_at_least_0_7_1 { - scan_sequence!( - scan_chars!(input, 'b', 'y', 't', 'e', 's'), + ident, + if scan_sequence!( + scan_chars!(input, 'u', 'i', 'n', 't'), scan_optional!( input, scan_choice!( input, - scan_chars!(input, '9'), + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), scan_chars!(input, '8'), - scan_chars!(input, '7'), - scan_chars!(input, '6'), - scan_chars!(input, '5'), - scan_chars!(input, '4'), + 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, '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', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), 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, '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'), - 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, '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') ) ) - ) - } else { - false - } + ) { + KeywordScan::Reserved(TokenKind::UintKeyword) + } else { + KeywordScan::Absent + } + ) } - #[allow(unused_assignments, unused_parens)] - fn yul_decimal_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_not_followed_by!( + #[inline] + fn yul_bytes_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( 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')) + 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') + ) + ) ) - ), - self.identifier_start(input) + { + KeywordScan::Reserved(TokenKind::YulBytesKeyword) + } else { + KeywordScan::Absent + } ) } - #[allow(unused_assignments, unused_parens)] - fn yul_fixed_keyword(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( + #[inline] + fn yul_fixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( input, - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'f', 'i', 'x', 'e', 'd') + ident, + if !self.version_is_at_least_0_7_1 && scan_chars!(input, 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent }, - if !self.version_is_at_least_0_7_1 { - scan_sequence!( + if !self.version_is_at_least_0_7_1 + && scan_sequence!( scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7544,11 +7635,13 @@ impl Language { scan_chars!(input, '1', '6') ) ) + { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent }, - if !self.version_is_at_least_0_7_1 { - scan_sequence!( + if !self.version_is_at_least_0_7_1 + && scan_sequence!( scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7599,11 +7692,14 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '1', '6') ) ) + { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 && !self.version_is_at_least_0_7_1 { - scan_sequence!( + 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, @@ -7664,11 +7760,14 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '8', '0') ) ) + { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 && !self.version_is_at_least_0_7_1 { - scan_sequence!( + 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, @@ -7781,89 +7880,81 @@ impl Language { scan_chars!(input, '0') ) ) + { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent } ) } - #[allow(unused_assignments, unused_parens)] - fn yul_hex_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_not_followed_by!( + #[inline] + fn yul_int_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( 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 { - self.raw_identifier(input) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_int_keyword(&self, input: &mut ParserContext<'_>) -> bool { - if !self.version_is_at_least_0_7_1 { - scan_sequence!( - scan_chars!(input, 'i', 'n', 't'), - scan_optional!( - input, - scan_choice!( + ident, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'i', 'n', 't'), + scan_optional!( 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_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') + ) ) ) - ) - } else { - false - } + { + KeywordScan::Reserved(TokenKind::YulIntKeyword) + } else { + KeywordScan::Absent + } + ) } - #[allow(unused_assignments, unused_parens)] - fn yul_ufixed_keyword(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( + #[inline] + fn yul_ufixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( input, - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') + ident, + if !self.version_is_at_least_0_7_1 && scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent }, - if !self.version_is_at_least_0_7_1 { - scan_sequence!( + if !self.version_is_at_least_0_7_1 + && scan_sequence!( scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7905,11 +7996,13 @@ impl Language { scan_chars!(input, '1', '6') ) ) + { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent }, - if !self.version_is_at_least_0_7_1 { - scan_sequence!( + if !self.version_is_at_least_0_7_1 + && scan_sequence!( scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7960,11 +8053,14 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '1', '6') ) ) + { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 && !self.version_is_at_least_0_7_1 { - scan_sequence!( + 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, @@ -8025,11 +8121,14 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '8', '0') ) ) + { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 && !self.version_is_at_least_0_7_1 { - scan_sequence!( + 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, @@ -8142,59 +8241,67 @@ impl Language { scan_chars!(input, '0') ) ) + { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent } ) } - #[allow(unused_assignments, unused_parens)] - fn yul_uint_keyword(&self, input: &mut ParserContext<'_>) -> bool { - if !self.version_is_at_least_0_7_1 { - scan_sequence!( - scan_chars!(input, 'u', 'i', 'n', 't'), - scan_optional!( - input, - scan_choice!( + #[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_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_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') + ) ) ) - ) - } else { - false - } + { + KeywordScan::Reserved(TokenKind::YulUintKeyword) + } else { + KeywordScan::Absent + } + ) } pub fn parse(&self, kind: RuleKind, input: &str) -> ParseOutput { @@ -8514,849 +8621,1422 @@ impl Lexer for Language { fn next_token( &self, input: &mut ParserContext<'_>, - ) -> Option { + ) -> Option { let save = input.position(); let mut furthest_position = input.position(); let mut longest_token = None; - match LexCtx::value() { - LexicalContext::Default => { - macro_rules! longest_match { - ($( { $kind:ident = $function:ident } )*) => { - $( - if self.$function(input) && input.position() > furthest_position { - furthest_position = input.position(); - longest_token = Some(TokenKind::$kind); - } - input.set_position(save); - )* - }; + macro_rules! longest_match { + ($( { $kind:ident = $function:ident } )*) => { + $( + if self.$function(input) && input.position() > furthest_position { + furthest_position = input.position(); + + longest_token = Some(TokenKind::$kind); } + input.set_position(save); + )* + }; + } + match LexCtx::value() { + LexicalContext::Default => { if let Some(kind) = match input.next() { - Some('a') => match input.next() { - Some('b') => scan_chars!(input, 's', 't', 'r', 'a', 'c', 't') - .then_some(TokenKind::AbstractKeyword), - Some('d') => scan_chars!(input, 'd', 'r', 'e', 's', 's') - .then_some(TokenKind::AddressKeyword), - Some('f') => { - scan_chars!(input, 't', 'e', 'r').then_some(TokenKind::AfterKeyword) + Some('!') => match input.next() { + Some('=') => Some(TokenKind::BangEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Bang) } - Some('l') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'i', 'a', 's').then_some(TokenKind::AliasKeyword) - } else { - None + None => Some(TokenKind::Bang), + }, + Some('%') => match input.next() { + Some('=') => Some(TokenKind::PercentEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Percent) + } + None => Some(TokenKind::Percent), + }, + Some('&') => match input.next() { + Some('&') => Some(TokenKind::AmpersandAmpersand), + Some('=') => Some(TokenKind::AmpersandEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Ampersand) + } + None => Some(TokenKind::Ampersand), + }, + Some('(') => Some(TokenKind::OpenParen), + Some(')') => Some(TokenKind::CloseParen), + Some('*') => match input.next() { + Some('*') => Some(TokenKind::AsteriskAsterisk), + Some('=') => Some(TokenKind::AsteriskEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Asterisk) + } + None => Some(TokenKind::Asterisk), + }, + Some('+') => match input.next() { + Some('+') => Some(TokenKind::PlusPlus), + Some('=') => Some(TokenKind::PlusEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Plus) + } + None => Some(TokenKind::Plus), + }, + Some(',') => Some(TokenKind::Comma), + Some('-') => match input.next() { + Some('-') => Some(TokenKind::MinusMinus), + Some('=') => Some(TokenKind::MinusEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Minus) + } + None => Some(TokenKind::Minus), + }, + Some('.') => Some(TokenKind::Period), + Some('/') => match input.next() { + Some('=') => Some(TokenKind::SlashEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Slash) + } + None => Some(TokenKind::Slash), + }, + Some(':') => Some(TokenKind::Colon), + Some(';') => Some(TokenKind::Semicolon), + Some('<') => match input.next() { + Some('<') => match input.next() { + Some('=') => Some(TokenKind::LessThanLessThanEqual), + Some(_) => { + input.undo(); + Some(TokenKind::LessThanLessThan) + } + None => Some(TokenKind::LessThanLessThan), + }, + Some('=') => Some(TokenKind::LessThanEqual), + Some(_) => { + input.undo(); + Some(TokenKind::LessThan) + } + None => Some(TokenKind::LessThan), + }, + Some('=') => match input.next() { + Some('=') => Some(TokenKind::EqualEqual), + Some('>') => Some(TokenKind::EqualGreaterThan), + Some(_) => { + input.undo(); + Some(TokenKind::Equal) + } + None => Some(TokenKind::Equal), + }, + Some('>') => match input.next() { + Some('=') => Some(TokenKind::GreaterThanEqual), + Some('>') => match input.next() { + Some('=') => Some(TokenKind::GreaterThanGreaterThanEqual), + Some('>') => match input.next() { + Some('=') => { + Some(TokenKind::GreaterThanGreaterThanGreaterThanEqual) + } + Some(_) => { + input.undo(); + Some(TokenKind::GreaterThanGreaterThanGreaterThan) + } + None => Some(TokenKind::GreaterThanGreaterThanGreaterThan), + }, + Some(_) => { + input.undo(); + Some(TokenKind::GreaterThanGreaterThan) + } + None => Some(TokenKind::GreaterThanGreaterThan), + }, + Some(_) => { + input.undo(); + Some(TokenKind::GreaterThan) + } + None => Some(TokenKind::GreaterThan), + }, + Some('?') => Some(TokenKind::QuestionMark), + Some('[') => Some(TokenKind::OpenBracket), + Some(']') => Some(TokenKind::CloseBracket), + Some('^') => match input.next() { + Some('=') => Some(TokenKind::CaretEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Caret) + } + None => Some(TokenKind::Caret), + }, + Some('{') => Some(TokenKind::OpenBrace), + Some('|') => match input.next() { + Some('=') => Some(TokenKind::BarEqual), + Some('|') => Some(TokenKind::BarBar), + Some(_) => { + input.undo(); + Some(TokenKind::Bar) + } + None => Some(TokenKind::Bar), + }, + Some('}') => Some(TokenKind::CloseBrace), + Some('~') => Some(TokenKind::Tilde), + Some(_) => { + input.undo(); + None + } + None => None, + } { + furthest_position = input.position(); + longest_token = Some(kind); + } + input.set_position(save); + + longest_match! { + { AsciiStringLiteral = ascii_string_literal } + { DecimalLiteral = decimal_literal } + { EndOfLine = end_of_line } + { HexLiteral = hex_literal } + { HexStringLiteral = hex_string_literal } + { MultilineComment = multiline_comment } + { SingleLineComment = single_line_comment } + { UnicodeStringLiteral = unicode_string_literal } + { Whitespace = whitespace } + } + // Make sure promotable identifiers are last so they don't grab other things + longest_match! { + { Identifier = identifier } + } + + // We have an identifier; we need to check if it's a keyword + if let Some(identifier) = + longest_token.filter(|tok| [TokenKind::Identifier].contains(tok)) + { + let kw_scan = match input.next() { + Some('a') => match input.next() { + Some('b') => { + if scan_chars!(input, 's', 't', 'r', 'a', 'c', 't') { + KeywordScan::Reserved(TokenKind::AbstractKeyword) + } else { + KeywordScan::Absent + } + } + Some('d') => { + if scan_chars!(input, 'd', 'r', 'e', 's', 's') { + KeywordScan::Reserved(TokenKind::AddressKeyword) + } else { + KeywordScan::Absent + } + } + Some('f') => { + if scan_chars!(input, 't', 'e', 'r') { + KeywordScan::Reserved(TokenKind::AfterKeyword) + } else { + KeywordScan::Absent + } + } + Some('l') => { + if scan_chars!(input, 'i', 'a', 's') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::AliasKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'o', 'n', 'y', 'm', 'o', 'u', 's') { + KeywordScan::Reserved(TokenKind::AnonymousKeyword) + } else { + KeywordScan::Absent + } + } + Some('p') => { + if scan_chars!(input, 'p', 'l', 'y') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::ApplyKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('s') => match input.next() { + Some('s') => { + if scan_chars!(input, 'e', 'm', 'b', 'l', 'y') { + KeywordScan::Reserved(TokenKind::AssemblyKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Reserved(TokenKind::AsKeyword) + } + None => KeywordScan::Reserved(TokenKind::AsKeyword), + }, + Some('u') => { + if scan_chars!(input, 't', 'o') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::AutoKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('b') => match input.next() { + Some('o') => { + if scan_chars!(input, 'o', 'l') { + KeywordScan::Reserved(TokenKind::BoolKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'e', 'a', 'k') { + KeywordScan::Reserved(TokenKind::BreakKeyword) + } else { + KeywordScan::Absent + } + } + Some('y') => { + if scan_chars!(input, 't', 'e') { + KeywordScan::Reserved(TokenKind::ByteKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('c') => match input.next() { + Some('a') => match input.next() { + Some('l') => { + if scan_chars!(input, 'l', 'd', 'a', 't', 'a') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::CallDataKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('s') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::CaseKeyword) + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'c', 'h') { + KeywordScan::Reserved(TokenKind::CatchKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => match input.next() { + Some('n') => match input.next() { + Some('s') => { + if scan_chars!(input, 't') { + match input.next() { + Some('a') => { + if scan_chars!(input, 'n', 't') { + KeywordScan::Reserved( + TokenKind::ConstantKeyword, + ) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'u', 'c', 't', 'o', 'r') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved( + TokenKind::ConstructorKeyword, + ) + } else if self.version_is_at_least_0_4_22 { + KeywordScan::Present( + TokenKind::ConstructorKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } + } + Some('t') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n', 'u', 'e') { + KeywordScan::Reserved(TokenKind::ContinueKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'a', 'c', 't') { + KeywordScan::Reserved(TokenKind::ContractKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('p') => { + if scan_chars!(input, 'y', 'o', 'f') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::CopyOfKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('d') => match input.next() { + Some('a') => { + if scan_chars!(input, 'y', 's') { + KeywordScan::Reserved(TokenKind::DaysKeyword) + } else { + KeywordScan::Absent + } + } + Some('e') => match input.next() { + Some('f') => match input.next() { + Some('a') => { + if scan_chars!(input, 'u', 'l', 't') { + KeywordScan::Reserved(TokenKind::DefaultKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'n', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::DefineKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('l') => { + if scan_chars!(input, 'e', 't', 'e') { + KeywordScan::Reserved(TokenKind::DeleteKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => KeywordScan::Reserved(TokenKind::DoKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('e') => match input.next() { + Some('l') => { + if scan_chars!(input, 's', 'e') { + KeywordScan::Reserved(TokenKind::ElseKeyword) + } else { + KeywordScan::Absent + } + } + Some('m') => { + if scan_chars!(input, 'i', 't') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::EmitKeyword) + } else if self.version_is_at_least_0_4_21 { + KeywordScan::Present(TokenKind::EmitKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'u', 'm') { + KeywordScan::Reserved(TokenKind::EnumKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'r', 'o', 'r') { + if self.version_is_at_least_0_8_4 { + KeywordScan::Present(TokenKind::ErrorKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'h', 'e', 'r') { + KeywordScan::Reserved(TokenKind::EtherKeyword) + } else { + KeywordScan::Absent + } + } + Some('v') => { + if scan_chars!(input, 'e', 'n', 't') { + KeywordScan::Reserved(TokenKind::EventKeyword) + } else { + KeywordScan::Absent + } } - } - Some('n') => scan_chars!(input, 'o', 'n', 'y', 'm', 'o', 'u', 's') - .then_some(TokenKind::AnonymousKeyword), - Some('p') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'p', 'l', 'y').then_some(TokenKind::ApplyKeyword) - } else { - None + Some('x') => { + if scan_chars!(input, 't', 'e', 'r', 'n', 'a', 'l') { + KeywordScan::Reserved(TokenKind::ExternalKeyword) + } else { + KeywordScan::Absent + } } - } - Some('s') => match input.next() { - Some('s') => scan_chars!(input, 'e', 'm', 'b', 'l', 'y') - .then_some(TokenKind::AssemblyKeyword), Some(_) => { input.undo(); - Some(TokenKind::AsKeyword) + KeywordScan::Absent } - None => Some(TokenKind::AsKeyword), + None => KeywordScan::Absent, }, - Some('u') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 't', 'o').then_some(TokenKind::AutoKeyword) - } else { - None + Some('f') => match input.next() { + Some('a') => { + if scan_chars!(input, 'l') { + match input.next() { + Some('l') => { + if scan_chars!(input, 'b', 'a', 'c', 'k') { + if self.version_is_at_least_0_6_0 { + KeywordScan::Reserved( + TokenKind::FallbackKeyword, + ) + } else { + KeywordScan::Present(TokenKind::FallbackKeyword) + } + } else { + KeywordScan::Absent + } + } + Some('s') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::FalseKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('b') => match input.next() { - Some('o') => scan_chars!(input, 'o', 'l').then_some(TokenKind::BoolKeyword), - Some('r') => { - scan_chars!(input, 'e', 'a', 'k').then_some(TokenKind::BreakKeyword) - } - Some('y') => scan_chars!(input, 't', 'e').then_some(TokenKind::ByteKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('c') => match input.next() { - Some('a') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n') { + match input.next() { + Some('a') => { + if scan_chars!(input, 'l') { + KeywordScan::Reserved(TokenKind::FinalKeyword) + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'e', 'y') { + if !self.version_is_at_least_0_7_0 { + KeywordScan::Reserved(TokenKind::FinneyKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'r') { + KeywordScan::Reserved(TokenKind::ForKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'o', 'm') { + if true { + KeywordScan::Present(TokenKind::FromKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'n', 'c', 't', 'i', 'o', 'n') { + KeywordScan::Reserved(TokenKind::FunctionKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('g') => match input.next() { Some('l') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'l', 'd', 'a', 't', 'a') - .then_some(TokenKind::CallDataKeyword) + if scan_chars!(input, 'o', 'b', 'a', 'l') { + if self.version_is_at_least_0_8_13 { + KeywordScan::Present(TokenKind::GlobalKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('s') => scan_chars!(input, 'e').then_some(TokenKind::CaseKeyword), - Some('t') => { - scan_chars!(input, 'c', 'h').then_some(TokenKind::CatchKeyword) + Some('w') => { + if scan_chars!(input, 'e', 'i') { + if self.version_is_at_least_0_7_0 { + KeywordScan::Reserved(TokenKind::GweiKeyword) + } else if self.version_is_at_least_0_6_11 { + KeywordScan::Present(TokenKind::GweiKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('o') => match input.next() { + Some('h') => match input.next() { + Some('e') => { + if scan_chars!(input, 'x') { + KeywordScan::Reserved(TokenKind::HexKeyword) + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'u', 'r', 's') { + KeywordScan::Reserved(TokenKind::HoursKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('i') => match input.next() { + Some('f') => KeywordScan::Reserved(TokenKind::IfKeyword), + Some('m') => match input.next() { + Some('m') => { + if scan_chars!(input, 'u', 't', 'a', 'b', 'l', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::ImmutableKeyword) + } else if self.version_is_at_least_0_6_5 { + KeywordScan::Present(TokenKind::ImmutableKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('p') => match input.next() { + Some('l') => { + if scan_chars!(input, 'e', 'm', 'e', 'n', 't', 's') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::ImplementsKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'r', 't') { + KeywordScan::Reserved(TokenKind::ImportKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, Some('n') => match input.next() { - Some('s') => { - if scan_chars!(input, 't') { + Some('d') => { + if scan_chars!(input, 'e', 'x', 'e', 'd') { + KeywordScan::Reserved(TokenKind::IndexedKeyword) + } else { + KeywordScan::Absent + } + } + Some('l') => { + if scan_chars!(input, 'i', 'n', 'e') { + KeywordScan::Reserved(TokenKind::InlineKeyword) + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'e', 'r') { match input.next() { - Some('a') => scan_chars!(input, 'n', 't') - .then_some(TokenKind::ConstantKeyword), - Some('r') => { - if self.version_is_at_least_0_4_22 { - scan_chars!(input, 'u', 'c', 't', 'o', 'r') - .then_some(TokenKind::ConstructorKeyword) + Some('f') => { + if scan_chars!(input, 'a', 'c', 'e') { + KeywordScan::Reserved( + TokenKind::InterfaceKeyword, + ) + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'a', 'l') { + KeywordScan::Reserved( + TokenKind::InternalKeyword, + ) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, } } else { - None + KeywordScan::Absent } } - Some('t') => match input.next() { - Some('i') => scan_chars!(input, 'n', 'u', 'e') - .then_some(TokenKind::ContinueKeyword), - Some('r') => scan_chars!(input, 'a', 'c', 't') - .then_some(TokenKind::ContractKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, Some(_) => { input.undo(); - None + KeywordScan::Reserved(TokenKind::InKeyword) } - None => None, + None => KeywordScan::Reserved(TokenKind::InKeyword), }, - Some('p') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'y', 'o', 'f') - .then_some(TokenKind::CopyOfKeyword) + Some('s') => KeywordScan::Reserved(TokenKind::IsKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('l') => match input.next() { + Some('e') => { + if scan_chars!(input, 't') { + KeywordScan::Reserved(TokenKind::LetKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'b', 'r', 'a', 'r', 'y') { + KeywordScan::Reserved(TokenKind::LibraryKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('d') => match input.next() { - Some('a') => scan_chars!(input, 'y', 's').then_some(TokenKind::DaysKeyword), - Some('e') => match input.next() { - Some('f') => match input.next() { - Some('a') => scan_chars!(input, 'u', 'l', 't') - .then_some(TokenKind::DefaultKeyword), - Some('i') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'n', 'e') - .then_some(TokenKind::DefineKeyword) + Some('m') => match input.next() { + Some('a') => match input.next() { + Some('c') => { + if scan_chars!(input, 'r', 'o') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::MacroKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent + } + } + Some('p') => { + if scan_chars!(input, 'p', 'i', 'n', 'g') { + KeywordScan::Reserved(TokenKind::MappingKeyword) + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'c', 'h') { + KeywordScan::Reserved(TokenKind::MatchKeyword) + } else { + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('l') => scan_chars!(input, 'e', 't', 'e') - .then_some(TokenKind::DeleteKeyword), + Some('e') => { + if scan_chars!(input, 'm', 'o', 'r', 'y') { + KeywordScan::Reserved(TokenKind::MemoryKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'n', 'u', 't', 'e', 's') { + KeywordScan::Reserved(TokenKind::MinutesKeyword) + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'd', 'i', 'f', 'i', 'e', 'r') { + KeywordScan::Reserved(TokenKind::ModifierKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 't', 'a', 'b', 'l', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::MutableKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('o') => Some(TokenKind::DoKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('e') => match input.next() { - Some('l') => scan_chars!(input, 's', 'e').then_some(TokenKind::ElseKeyword), - Some('m') => { - if self.version_is_at_least_0_4_21 { - scan_chars!(input, 'i', 't').then_some(TokenKind::EmitKeyword) - } else { - None + Some('n') => match input.next() { + Some('e') => { + if scan_chars!(input, 'w') { + KeywordScan::Reserved(TokenKind::NewKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'l', 'l') { + KeywordScan::Reserved(TokenKind::NullKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => match input.next() { + Some('f') => KeywordScan::Reserved(TokenKind::OfKeyword), + Some('v') => { + if scan_chars!(input, 'e', 'r', 'r', 'i', 'd', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::OverrideKeyword) + } else { + KeywordScan::Present(TokenKind::OverrideKeyword) + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('p') => match input.next() { + Some('a') => match input.next() { + Some('r') => { + if scan_chars!(input, 't', 'i', 'a', 'l') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::PartialKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('y') => { + if scan_chars!(input, 'a', 'b', 'l', 'e') { + KeywordScan::Reserved(TokenKind::PayableKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('r') => match input.next() { + Some('a') => { + if scan_chars!(input, 'g', 'm', 'a') { + KeywordScan::Reserved(TokenKind::PragmaKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'v', 'a', 't', 'e') { + KeywordScan::Reserved(TokenKind::PrivateKeyword) + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'm', 'i', 's', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::PromiseKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('u') => match input.next() { + Some('b') => { + if scan_chars!(input, 'l', 'i', 'c') { + KeywordScan::Reserved(TokenKind::PublicKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::PureKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent } - } - Some('n') => scan_chars!(input, 'u', 'm').then_some(TokenKind::EnumKeyword), + None => KeywordScan::Absent, + }, Some('r') => { - if self.version_is_at_least_0_8_4 { - scan_chars!(input, 'r', 'o', 'r').then_some(TokenKind::ErrorKeyword) - } else { - None - } - } - Some('t') => { - scan_chars!(input, 'h', 'e', 'r').then_some(TokenKind::EtherKeyword) - } - Some('v') => { - scan_chars!(input, 'e', 'n', 't').then_some(TokenKind::EventKeyword) - } - Some('x') => scan_chars!(input, 't', 'e', 'r', 'n', 'a', 'l') - .then_some(TokenKind::ExternalKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('f') => match input.next() { - Some('a') => { - if scan_chars!(input, 'l') { + if scan_chars!(input, 'e') { match input.next() { + Some('c') => { + if scan_chars!(input, 'e', 'i', 'v', 'e') { + if self.version_is_at_least_0_6_0 { + KeywordScan::Reserved(TokenKind::ReceiveKeyword) + } else { + KeywordScan::Present(TokenKind::ReceiveKeyword) + } + } else { + KeywordScan::Absent + } + } + Some('f') => { + if scan_chars!(input, 'e', 'r', 'e', 'n', 'c', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::ReferenceKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } Some('l') => { - if self.version_is_at_least_0_6_0 { - scan_chars!(input, 'b', 'a', 'c', 'k') - .then_some(TokenKind::FallbackKeyword) + if scan_chars!( + input, 'o', 'c', 'a', 't', 'a', 'b', 'l', 'e' + ) { + KeywordScan::Reserved(TokenKind::RelocatableKeyword) } else { - None + KeywordScan::Absent } } - Some('s') => { - scan_chars!(input, 'e').then_some(TokenKind::FalseKeyword) + Some('t') => { + if scan_chars!(input, 'u', 'r', 'n') { + match input.next() { + Some('s') => { + KeywordScan::Reserved(TokenKind::ReturnsKeyword) + } + Some(_) => { + input.undo(); + KeywordScan::Reserved(TokenKind::ReturnKeyword) + } + None => { + KeywordScan::Reserved(TokenKind::ReturnKeyword) + } + } + } else { + KeywordScan::Absent + } + } + Some('v') => { + if scan_chars!(input, 'e', 'r', 't') { + if self.version_is_at_least_0_8_4 { + KeywordScan::Present(TokenKind::RevertKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, } } else { - None + KeywordScan::Absent } } - Some('i') => { - if scan_chars!(input, 'n') { - match input.next() { - Some('a') => { - scan_chars!(input, 'l').then_some(TokenKind::FinalKeyword) - } - Some('n') => { - if !self.version_is_at_least_0_7_0 { - scan_chars!(input, 'e', 'y') - .then_some(TokenKind::FinneyKeyword) + Some('s') => match input.next() { + Some('e') => match input.next() { + Some('a') => { + if scan_chars!(input, 'l', 'e', 'd') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::SealedKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some(_) => { - input.undo(); - None + } + Some('c') => { + if scan_chars!(input, 'o', 'n', 'd', 's') { + KeywordScan::Reserved(TokenKind::SecondsKeyword) + } else { + KeywordScan::Absent } - None => None, } - } else { - None - } - } - Some('o') => scan_chars!(input, 'r').then_some(TokenKind::ForKeyword), - Some('r') => scan_chars!(input, 'o', 'm').then_some(TokenKind::FromKeyword), - Some('u') => scan_chars!(input, 'n', 'c', 't', 'i', 'o', 'n') - .then_some(TokenKind::FunctionKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('g') => match input.next() { - Some('l') => { - if self.version_is_at_least_0_8_13 { - scan_chars!(input, 'o', 'b', 'a', 'l') - .then_some(TokenKind::GlobalKeyword) - } else { - None - } - } - Some('w') => { - if self.version_is_at_least_0_6_11 { - scan_chars!(input, 'e', 'i').then_some(TokenKind::GweiKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('h') => match input.next() { - Some('e') => scan_chars!(input, 'x').then_some(TokenKind::HexKeyword), - Some('o') => { - scan_chars!(input, 'u', 'r', 's').then_some(TokenKind::HoursKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('i') => match input.next() { - Some('f') => Some(TokenKind::IfKeyword), - Some('m') => match input.next() { - Some('m') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'u', 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::ImmutableKeyword) + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('i') => { + if scan_chars!(input, 'z', 'e', 'o', 'f') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::SizeOfKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('p') => match input.next() { - Some('l') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'e', 'm', 'e', 'n', 't', 's') - .then_some(TokenKind::ImplementsKeyword) + Some('t') => match input.next() { + Some('a') => { + if scan_chars!(input, 't', 'i', 'c') { + KeywordScan::Reserved(TokenKind::StaticKeyword) } else { - None + KeywordScan::Absent } } Some('o') => { - scan_chars!(input, 'r', 't').then_some(TokenKind::ImportKeyword) + if scan_chars!(input, 'r', 'a', 'g', 'e') { + KeywordScan::Reserved(TokenKind::StorageKeyword) + } else { + KeywordScan::Absent + } } + Some('r') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n', 'g') { + KeywordScan::Reserved(TokenKind::StringKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'c', 't') { + KeywordScan::Reserved(TokenKind::StructKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('n') => match input.next() { - Some('d') => scan_chars!(input, 'e', 'x', 'e', 'd') - .then_some(TokenKind::IndexedKeyword), - Some('l') => scan_chars!(input, 'i', 'n', 'e') - .then_some(TokenKind::InlineKeyword), - Some('t') => { - if scan_chars!(input, 'e', 'r') { - match input.next() { - Some('f') => scan_chars!(input, 'a', 'c', 'e') - .then_some(TokenKind::InterfaceKeyword), - Some('n') => scan_chars!(input, 'a', 'l') - .then_some(TokenKind::InternalKeyword), - Some(_) => { - input.undo(); - None - } - None => None, + Some('u') => { + if scan_chars!(input, 'p', 'p', 'o', 'r', 't', 's') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::SupportsKeyword) + } else { + KeywordScan::Absent } } else { - None + KeywordScan::Absent } } - Some(_) => { - input.undo(); - Some(TokenKind::InKeyword) - } - None => Some(TokenKind::InKeyword), - }, - Some('s') => Some(TokenKind::IsKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('l') => match input.next() { - Some('e') => scan_chars!(input, 't').then_some(TokenKind::LetKeyword), - Some('i') => scan_chars!(input, 'b', 'r', 'a', 'r', 'y') - .then_some(TokenKind::LibraryKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('m') => match input.next() { - Some('a') => match input.next() { - Some('c') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'r', 'o').then_some(TokenKind::MacroKeyword) + Some('w') => { + if scan_chars!(input, 'i', 't', 'c', 'h') { + KeywordScan::Reserved(TokenKind::SwitchKeyword) } else { - None + KeywordScan::Absent } } - Some('p') => scan_chars!(input, 'p', 'i', 'n', 'g') - .then_some(TokenKind::MappingKeyword), - Some('t') => { - scan_chars!(input, 'c', 'h').then_some(TokenKind::MatchKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('e') => scan_chars!(input, 'm', 'o', 'r', 'y') - .then_some(TokenKind::MemoryKeyword), - Some('i') => scan_chars!(input, 'n', 'u', 't', 'e', 's') - .then_some(TokenKind::MinutesKeyword), - Some('o') => scan_chars!(input, 'd', 'i', 'f', 'i', 'e', 'r') - .then_some(TokenKind::ModifierKeyword), - Some('u') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::MutableKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('n') => match input.next() { - Some('e') => scan_chars!(input, 'w').then_some(TokenKind::NewKeyword), - Some('u') => scan_chars!(input, 'l', 'l').then_some(TokenKind::NullKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('o') => match input.next() { - Some('f') => Some(TokenKind::OfKeyword), - Some('v') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'e', 'r', 'r', 'i', 'd', 'e') - .then_some(TokenKind::OverrideKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('p') => match input.next() { - Some('a') => match input.next() { - Some('r') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 't', 'i', 'a', 'l') - .then_some(TokenKind::PartialKeyword) + Some('z') => { + if scan_chars!(input, 'a', 'b', 'o') { + if !self.version_is_at_least_0_7_0 { + KeywordScan::Reserved(TokenKind::SzaboKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('y') => scan_chars!(input, 'a', 'b', 'l', 'e') - .then_some(TokenKind::PayableKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('r') => match input.next() { - Some('a') => scan_chars!(input, 'g', 'm', 'a') - .then_some(TokenKind::PragmaKeyword), - Some('i') => scan_chars!(input, 'v', 'a', 't', 'e') - .then_some(TokenKind::PrivateKeyword), - Some('o') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'm', 'i', 's', 'e') - .then_some(TokenKind::PromiseKeyword) + Some('t') => match input.next() { + Some('h') => { + if scan_chars!(input, 'r', 'o', 'w') { + KeywordScan::Reserved(TokenKind::ThrowKeyword) } else { - None + KeywordScan::Absent } } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('u') => match input.next() { - Some('b') => scan_chars!(input, 'l', 'i', 'c') - .then_some(TokenKind::PublicKeyword), - Some('r') => scan_chars!(input, 'e').then_some(TokenKind::PureKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('r') => { - if scan_chars!(input, 'e') { - match input.next() { - Some('c') => { - if self.version_is_at_least_0_6_0 { - scan_chars!(input, 'e', 'i', 'v', 'e') - .then_some(TokenKind::ReceiveKeyword) - } else { - None - } - } - Some('f') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'e', 'r', 'e', 'n', 'c', 'e') - .then_some(TokenKind::ReferenceKeyword) + Some('r') => match input.next() { + Some('u') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::TrueKeyword) } else { - None + KeywordScan::Absent } } - Some('l') => { - scan_chars!(input, 'o', 'c', 'a', 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::RelocatableKeyword) + Some('y') => KeywordScan::Reserved(TokenKind::TryKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent } - Some('t') => { - if scan_chars!(input, 'u', 'r', 'n') { - match input.next() { - Some('s') => Some(TokenKind::ReturnsKeyword), - Some(_) => { - input.undo(); - Some(TokenKind::ReturnKeyword) + None => KeywordScan::Absent, + }, + Some('y') => { + if scan_chars!(input, 'p', 'e') { + match input.next() { + Some('d') => { + if scan_chars!(input, 'e', 'f') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::TypeDefKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent } - None => Some(TokenKind::ReturnKeyword), } - } else { - None - } - } - Some('v') => { - if self.version_is_at_least_0_8_4 { - scan_chars!(input, 'e', 'r', 't') - .then_some(TokenKind::RevertKeyword) - } else { - None + Some('o') => { + if scan_chars!(input, 'f') { + KeywordScan::Reserved(TokenKind::TypeOfKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Reserved(TokenKind::TypeKeyword) + } + None => KeywordScan::Reserved(TokenKind::TypeKeyword), } - } - Some(_) => { - input.undo(); - None - } - None => None, - } - } else { - None - } - } - Some('s') => match input.next() { - Some('e') => match input.next() { - Some('a') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'l', 'e', 'd') - .then_some(TokenKind::SealedKeyword) } else { - None + KeywordScan::Absent } } - Some('c') => scan_chars!(input, 'o', 'n', 'd', 's') - .then_some(TokenKind::SecondsKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('i') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'z', 'e', 'o', 'f') - .then_some(TokenKind::SizeOfKeyword) - } else { - None - } - } - Some('t') => { - match input.next() { - Some('a') => scan_chars!(input, 't', 'i', 'c') - .then_some(TokenKind::StaticKeyword), - Some('o') => scan_chars!(input, 'r', 'a', 'g', 'e') - .then_some(TokenKind::StorageKeyword), - Some('r') => match input.next() { - Some('i') => scan_chars!(input, 'n', 'g') - .then_some(TokenKind::StringKeyword), - Some('u') => scan_chars!(input, 'c', 't') - .then_some(TokenKind::StructKeyword), - Some(_) => { - input.undo(); - None + Some('u') => match input.next() { + Some('n') => { + if scan_chars!(input, 'c', 'h', 'e', 'c', 'k', 'e', 'd') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::UncheckedKeyword) + } else if self.version_is_at_least_0_8_0 { + KeywordScan::Present(TokenKind::UncheckedKeyword) + } else { + KeywordScan::Absent } - None => None, - }, - Some(_) => { - input.undo(); - None + } else { + KeywordScan::Absent } - None => None, - } - } - Some('u') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'p', 'p', 'o', 'r', 't', 's') - .then_some(TokenKind::SupportsKeyword) - } else { - None } - } - Some('w') => scan_chars!(input, 'i', 't', 'c', 'h') - .then_some(TokenKind::SwitchKeyword), - Some('z') => { - if !self.version_is_at_least_0_7_0 { - scan_chars!(input, 'a', 'b', 'o').then_some(TokenKind::SzaboKeyword) - } else { - None + Some('s') => { + if scan_chars!(input, 'i', 'n', 'g') { + KeywordScan::Reserved(TokenKind::UsingKeyword) + } else { + KeywordScan::Absent + } } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('t') => match input.next() { - Some('h') => { - scan_chars!(input, 'r', 'o', 'w').then_some(TokenKind::ThrowKeyword) - } - Some('r') => match input.next() { - Some('u') => scan_chars!(input, 'e').then_some(TokenKind::TrueKeyword), - Some('y') => Some(TokenKind::TryKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('y') => { - if scan_chars!(input, 'p', 'e') { - match input.next() { - Some('d') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'e', 'f') - .then_some(TokenKind::TypeDefKeyword) + Some('v') => match input.next() { + Some('a') => { + if scan_chars!(input, 'r') { + KeywordScan::Reserved(TokenKind::VarKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => match input.next() { + Some('e') => { + if scan_chars!(input, 'w') { + KeywordScan::Reserved(TokenKind::ViewKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 't', 'u', 'a', 'l') { + if self.version_is_at_least_0_6_0 { + KeywordScan::Reserved(TokenKind::VirtualKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some('o') => { - scan_chars!(input, 'f').then_some(TokenKind::TypeOfKeyword) - } - Some(_) => { - input.undo(); - Some(TokenKind::TypeKeyword) - } - None => Some(TokenKind::TypeKeyword), } - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('u') => match input.next() { - Some('n') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'c', 'h', 'e', 'c', 'k', 'e', 'd') - .then_some(TokenKind::UncheckedKeyword) - } else { - None - } - } - Some('s') => { - scan_chars!(input, 'i', 'n', 'g').then_some(TokenKind::UsingKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('v') => match input.next() { - Some('a') => scan_chars!(input, 'r').then_some(TokenKind::VarKeyword), - Some('i') => match input.next() { - Some('e') => scan_chars!(input, 'w').then_some(TokenKind::ViewKeyword), - Some('r') => { - if self.version_is_at_least_0_6_0 { - scan_chars!(input, 't', 'u', 'a', 'l') - .then_some(TokenKind::VirtualKeyword) - } else { - None + Some(_) => { + input.undo(); + KeywordScan::Absent } - } + None => KeywordScan::Absent, + }, Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('w') => match input.next() { - Some('e') => match input.next() { - Some('e') => { - scan_chars!(input, 'k', 's').then_some(TokenKind::WeeksKeyword) + Some('w') => match input.next() { + Some('e') => match input.next() { + Some('e') => { + if scan_chars!(input, 'k', 's') { + KeywordScan::Reserved(TokenKind::WeeksKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => KeywordScan::Reserved(TokenKind::WeiKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('h') => { + if scan_chars!(input, 'i', 'l', 'e') { + KeywordScan::Reserved(TokenKind::WhileKeyword) + } else { + KeywordScan::Absent + } } - Some('i') => Some(TokenKind::WeiKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('h') => { - scan_chars!(input, 'i', 'l', 'e').then_some(TokenKind::WhileKeyword) + Some('y') => { + if scan_chars!(input, 'e', 'a', 'r', 's') { + KeywordScan::Reserved(TokenKind::YearsKeyword) + } else { + KeywordScan::Absent + } } Some(_) => { input.undo(); - None + KeywordScan::Absent + } + None => KeywordScan::Absent, + }; + let kw_scan = match kw_scan { + // Strict prefix; we need to match the whole identifier to promote + _ if input.position() < furthest_position => KeywordScan::Absent, + value => value, + }; + + // Perf: only scan for a compound keyword if we didn't already find one + let mut kw_scan = kw_scan; + if kw_scan == KeywordScan::Absent { + input.set_position(save); + + // TODO: Don't allocate a string here + let ident_value = input.content(save.utf8..furthest_position.utf8); + + for keyword_compound_scanner in [ + Self::bytes_keyword, + Self::fixed_keyword, + Self::int_keyword, + Self::ufixed_keyword, + Self::uint_keyword, + ] { + match keyword_compound_scanner(self, input, &ident_value) { + _ if input.position() < furthest_position => { /* Strict prefix */ } + KeywordScan::Absent => {} + value => kw_scan = value, + } + input.set_position(save); } - None => None, - }, - Some('y') => { - scan_chars!(input, 'e', 'a', 'r', 's').then_some(TokenKind::YearsKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - } { - // Make sure that this is not the start of an identifier - if !self.identifier_part(input) { - furthest_position = input.position(); - longest_token = Some(kind); } - } - input.set_position(save); + input.set_position(furthest_position); + return Some(ScannedToken::IdentifierOrKeyword { + identifier, + kw: kw_scan, + }); + } + } + LexicalContext::Pragma => { if let Some(kind) = match input.next() { - Some('!') => match input.next() { - Some('=') => Some(TokenKind::BangEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Bang) - } - None => Some(TokenKind::Bang), - }, - Some('%') => match input.next() { - Some('=') => Some(TokenKind::PercentEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Percent) - } - None => Some(TokenKind::Percent), - }, - Some('&') => match input.next() { - Some('&') => Some(TokenKind::AmpersandAmpersand), - Some('=') => Some(TokenKind::AmpersandEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Ampersand) - } - None => Some(TokenKind::Ampersand), - }, - Some('(') => Some(TokenKind::OpenParen), - Some(')') => Some(TokenKind::CloseParen), - Some('*') => match input.next() { - Some('*') => Some(TokenKind::AsteriskAsterisk), - Some('=') => Some(TokenKind::AsteriskEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Asterisk) - } - None => Some(TokenKind::Asterisk), - }, - Some('+') => match input.next() { - Some('+') => Some(TokenKind::PlusPlus), - Some('=') => Some(TokenKind::PlusEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Plus) - } - None => Some(TokenKind::Plus), - }, - Some(',') => Some(TokenKind::Comma), - Some('-') => match input.next() { - Some('-') => Some(TokenKind::MinusMinus), - Some('=') => Some(TokenKind::MinusEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Minus) - } - None => Some(TokenKind::Minus), - }, + Some('-') => Some(TokenKind::Minus), Some('.') => Some(TokenKind::Period), - Some('/') => match input.next() { - Some('=') => Some(TokenKind::SlashEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Slash) - } - None => Some(TokenKind::Slash), - }, - Some(':') => Some(TokenKind::Colon), Some(';') => Some(TokenKind::Semicolon), Some('<') => match input.next() { - Some('<') => match input.next() { - Some('=') => Some(TokenKind::LessThanLessThanEqual), - Some(_) => { - input.undo(); - Some(TokenKind::LessThanLessThan) - } - None => Some(TokenKind::LessThanLessThan), - }, Some('=') => Some(TokenKind::LessThanEqual), Some(_) => { input.undo(); @@ -9364,63 +10044,23 @@ impl Lexer for Language { } None => Some(TokenKind::LessThan), }, - Some('=') => match input.next() { - Some('=') => Some(TokenKind::EqualEqual), - Some('>') => Some(TokenKind::EqualGreaterThan), - Some(_) => { - input.undo(); - Some(TokenKind::Equal) - } - None => Some(TokenKind::Equal), - }, + Some('=') => Some(TokenKind::Equal), Some('>') => match input.next() { Some('=') => Some(TokenKind::GreaterThanEqual), - Some('>') => match input.next() { - Some('=') => Some(TokenKind::GreaterThanGreaterThanEqual), - Some('>') => match input.next() { - Some('=') => { - Some(TokenKind::GreaterThanGreaterThanGreaterThanEqual) - } - Some(_) => { - input.undo(); - Some(TokenKind::GreaterThanGreaterThanGreaterThan) - } - None => Some(TokenKind::GreaterThanGreaterThanGreaterThan), - }, - Some(_) => { - input.undo(); - Some(TokenKind::GreaterThanGreaterThan) - } - None => Some(TokenKind::GreaterThanGreaterThan), - }, Some(_) => { input.undo(); Some(TokenKind::GreaterThan) } None => Some(TokenKind::GreaterThan), }, - Some('?') => Some(TokenKind::QuestionMark), - Some('[') => Some(TokenKind::OpenBracket), - Some(']') => Some(TokenKind::CloseBracket), - Some('^') => match input.next() { - Some('=') => Some(TokenKind::CaretEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Caret) - } - None => Some(TokenKind::Caret), - }, - Some('{') => Some(TokenKind::OpenBrace), - Some('|') => match input.next() { - Some('=') => Some(TokenKind::BarEqual), - Some('|') => Some(TokenKind::BarBar), - Some(_) => { - input.undo(); - Some(TokenKind::Bar) + Some('^') => Some(TokenKind::Caret), + Some('|') => { + if scan_chars!(input, '|') { + Some(TokenKind::BarBar) + } else { + None } - None => Some(TokenKind::Bar), - }, - Some('}') => Some(TokenKind::CloseBrace), + } Some('~') => Some(TokenKind::Tilde), Some(_) => { input.undo(); @@ -9434,85 +10074,90 @@ impl Lexer for Language { input.set_position(save); longest_match! { - { AsciiStringLiteral = ascii_string_literal } - { BytesKeyword = bytes_keyword } - { DecimalLiteral = decimal_literal } - { EndOfLine = end_of_line } - { FixedKeyword = fixed_keyword } - { HexLiteral = hex_literal } - { HexStringLiteral = hex_string_literal } - { IntKeyword = int_keyword } - { MultilineComment = multiline_comment } - { SingleLineComment = single_line_comment } - { UfixedKeyword = ufixed_keyword } - { UintKeyword = uint_keyword } - { UnicodeStringLiteral = unicode_string_literal } - { Whitespace = whitespace } - { Identifier = identifier } + { AsciiStringLiteral = ascii_string_literal } + { VersionPragmaValue = version_pragma_value } } - } - LexicalContext::Pragma => { - macro_rules! longest_match { - ($( { $kind:ident = $function:ident } )*) => { - $( - if self.$function(input) && input.position() > furthest_position { - furthest_position = input.position(); - longest_token = Some(TokenKind::$kind); - } - input.set_position(save); - )* - }; - } - - if let Some(kind) = match input.next() { - Some('a') => scan_chars!(input, 'b', 'i', 'c', 'o', 'd', 'e', 'r') - .then_some(TokenKind::AbicoderKeyword), - Some('e') => { - scan_chars!(input, 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l') - .then_some(TokenKind::ExperimentalKeyword) - } - Some('p') => scan_chars!(input, 'r', 'a', 'g', 'm', 'a') - .then_some(TokenKind::PragmaKeyword), - Some('s') => scan_chars!(input, 'o', 'l', 'i', 'd', 'i', 't', 'y') - .then_some(TokenKind::SolidityKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - } { - // Make sure that this is not the start of an identifier - if !self.identifier_part(input) { - furthest_position = input.position(); - longest_token = Some(kind); - } + // Make sure promotable identifiers are last so they don't grab other things + longest_match! { + { Identifier = identifier } } - input.set_position(save); - if let Some(kind) = match input.next() { - Some('-') => Some(TokenKind::Minus), - Some('.') => Some(TokenKind::Period), - Some(';') => Some(TokenKind::Semicolon), - Some('<') => match input.next() { - Some('=') => Some(TokenKind::LessThanEqual), - Some(_) => { - input.undo(); - Some(TokenKind::LessThan) + // We have an identifier; we need to check if it's a keyword + if let Some(identifier) = + longest_token.filter(|tok| [TokenKind::Identifier].contains(tok)) + { + let kw_scan = match input.next() { + Some('a') => { + if scan_chars!(input, 'b', 'i', 'c', 'o', 'd', 'e', 'r') { + KeywordScan::Reserved(TokenKind::AbicoderKeyword) + } else { + KeywordScan::Absent + } + } + Some('e') => { + if scan_chars!( + input, 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l' + ) { + KeywordScan::Reserved(TokenKind::ExperimentalKeyword) + } else { + KeywordScan::Absent + } + } + Some('p') => { + if scan_chars!(input, 'r', 'a', 'g', 'm', 'a') { + KeywordScan::Reserved(TokenKind::PragmaKeyword) + } else { + KeywordScan::Absent + } + } + Some('s') => { + if scan_chars!(input, 'o', 'l', 'i', 'd', 'i', 't', 'y') { + KeywordScan::Reserved(TokenKind::SolidityKeyword) + } else { + KeywordScan::Absent + } } - None => Some(TokenKind::LessThan), - }, - Some('=') => Some(TokenKind::Equal), - Some('>') => match input.next() { - Some('=') => Some(TokenKind::GreaterThanEqual), Some(_) => { input.undo(); - Some(TokenKind::GreaterThan) + KeywordScan::Absent } - None => Some(TokenKind::GreaterThan), - }, - Some('^') => Some(TokenKind::Caret), - Some('|') => scan_chars!(input, '|').then_some(TokenKind::BarBar), - Some('~') => Some(TokenKind::Tilde), + None => KeywordScan::Absent, + }; + let kw_scan = match kw_scan { + // Strict prefix; we need to match the whole identifier to promote + _ if input.position() < furthest_position => KeywordScan::Absent, + value => value, + }; + + input.set_position(furthest_position); + return Some(ScannedToken::IdentifierOrKeyword { + identifier, + kw: kw_scan, + }); + } + } + LexicalContext::Yul => { + if let Some(kind) = match input.next() { + Some('(') => Some(TokenKind::OpenParen), + Some(')') => Some(TokenKind::CloseParen), + Some(',') => Some(TokenKind::Comma), + Some('-') => { + if scan_chars!(input, '>') { + Some(TokenKind::MinusGreaterThan) + } else { + None + } + } + Some('.') => Some(TokenKind::Period), + Some(':') => { + if scan_chars!(input, '=') { + Some(TokenKind::ColonEqual) + } else { + None + } + } + Some('{') => Some(TokenKind::OpenBrace), + Some('}') => Some(TokenKind::CloseBrace), Some(_) => { input.undo(); None @@ -9525,1177 +10170,1537 @@ impl Lexer for Language { input.set_position(save); longest_match! { - { AsciiStringLiteral = ascii_string_literal } - { VersionPragmaValue = version_pragma_value } - { Identifier = identifier } + { AsciiStringLiteral = ascii_string_literal } + { HexStringLiteral = hex_string_literal } + { YulDecimalLiteral = yul_decimal_literal } + { YulHexLiteral = yul_hex_literal } + } + // Make sure promotable identifiers are last so they don't grab other things + longest_match! { + { YulIdentifier = yul_identifier } } - } - LexicalContext::Yul => { - macro_rules! longest_match { - ($( { $kind:ident = $function:ident } )*) => { - $( - if self.$function(input) && input.position() > furthest_position { - furthest_position = input.position(); - longest_token = Some(TokenKind::$kind); - } - input.set_position(save); - )* - }; - } - if let Some(kind) = match input.next() { - Some('a') => match input.next() { - Some('b') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 's', 't', 'r', 'a', 'c', 't') - .then_some(TokenKind::YulAbstractKeyword) - } else { - None + // We have an identifier; we need to check if it's a keyword + if let Some(identifier) = + longest_token.filter(|tok| [TokenKind::YulIdentifier].contains(tok)) + { + let kw_scan = match input.next() { + Some('a') => match input.next() { + Some('b') => { + if scan_chars!(input, 's', 't', 'r', 'a', 'c', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAbstractKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('d') => scan_chars!(input, 'd', 'r', 'e', 's', 's') - .then_some(TokenKind::YulAddressKeyword), - Some('f') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'e', 'r') - .then_some(TokenKind::YulAfterKeyword) - } else { - None + Some('d') => { + if scan_chars!(input, 'd', 'r', 'e', 's', 's') { + KeywordScan::Reserved(TokenKind::YulAddressKeyword) + } else { + KeywordScan::Absent + } } - } - Some('l') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 'a', 's') - .then_some(TokenKind::YulAliasKeyword) - } else { - None + Some('f') => { + if scan_chars!(input, 't', 'e', 'r') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAfterKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('n') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'o', 'n', 'y', 'm', 'o', 'u', 's') - .then_some(TokenKind::YulAnonymousKeyword) - } else { - None + Some('l') => { + if scan_chars!(input, 'i', 'a', 's') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulAliasKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('p') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'p', 'l', 'y') - .then_some(TokenKind::YulApplyKeyword) - } else { - None + Some('n') => { + if scan_chars!(input, 'o', 'n', 'y', 'm', 'o', 'u', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAnonymousKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('s') => match input.next() { - Some('s') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'm', 'b', 'l', 'y') - .then_some(TokenKind::YulAssemblyKeyword) + Some('p') => { + if scan_chars!(input, 'p', 'l', 'y') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulApplyKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('s') => match input.next() { + Some('s') => { + if scan_chars!(input, 'e', 'm', 'b', 'l', 'y') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAssemblyKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAsKeyword) + } else { + KeywordScan::Absent + } + } + None => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAsKeyword) + } else { + KeywordScan::Absent + } + } + }, + Some('u') => { + if scan_chars!(input, 't', 'o') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulAutoKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulAsKeyword) + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('b') => match input.next() { + Some('o') => { + if scan_chars!(input, 'o', 'l') { + if !self.version_is_at_least_0_5_10 { + KeywordScan::Reserved(TokenKind::YulBoolKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - None => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulAsKeyword) + Some('r') => { + if scan_chars!(input, 'e', 'a', 'k') { + KeywordScan::Reserved(TokenKind::YulBreakKeyword) + } else { + KeywordScan::Absent + } + } + Some('y') => { + if scan_chars!(input, 't', 'e') { + KeywordScan::Reserved(TokenKind::YulByteKeyword) } else { - None + KeywordScan::Absent } } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, }, - Some('u') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'o').then_some(TokenKind::YulAutoKeyword) - } else { - None + Some('c') => match input.next() { + Some('a') => match input.next() { + Some('l') => { + if scan_chars!(input, 'l', 'd', 'a', 't', 'a') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulCallDataKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('s') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::YulCaseKeyword) + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'c', 'h') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulCatchKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => match input.next() { + Some('n') => match input.next() { + Some('s') => { + if scan_chars!(input, 't') { + match input.next() { + Some('a') => { + if scan_chars!(input, 'n', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulConstantKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'u', 'c', 't', 'o', 'r') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved( + TokenKind::YulConstructorKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } + } + Some('t') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n', 'u', 'e') { + KeywordScan::Reserved(TokenKind::YulContinueKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'a', 'c', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulContractKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('p') => { + if scan_chars!(input, 'y', 'o', 'f') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulCopyOfKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('b') => match input.next() { - Some('o') => { - if !self.version_is_at_least_0_5_10 { - scan_chars!(input, 'o', 'l').then_some(TokenKind::YulBoolKeyword) - } else { - None + None => KeywordScan::Absent, + }, + Some('d') => match input.next() { + Some('a') => { + if scan_chars!(input, 'y', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulDaysKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('r') => { - scan_chars!(input, 'e', 'a', 'k').then_some(TokenKind::YulBreakKeyword) - } - Some('y') => { - scan_chars!(input, 't', 'e').then_some(TokenKind::YulByteKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('c') => match input.next() { - Some('a') => match input.next() { + Some('e') => match input.next() { + Some('f') => match input.next() { + Some('a') => { + if scan_chars!(input, 'u', 'l', 't') { + KeywordScan::Reserved(TokenKind::YulDefaultKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'n', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulDefineKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('l') => { + if scan_chars!(input, 'e', 't', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulDeleteKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulDoKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('e') => match input.next() { Some('l') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'l', 'd', 'a', 't', 'a') - .then_some(TokenKind::YulCallDataKeyword) + if scan_chars!(input, 's', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulElseKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('s') => { - scan_chars!(input, 'e').then_some(TokenKind::YulCaseKeyword) + Some('m') => { + if scan_chars!(input, 'i', 't') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulEmitKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'u', 'm') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulEnumKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } Some('t') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'c', 'h') - .then_some(TokenKind::YulCatchKeyword) + if scan_chars!(input, 'h', 'e', 'r') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulEtherKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('v') => { + if scan_chars!(input, 'e', 'n', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulEventKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('x') => { + if scan_chars!(input, 't', 'e', 'r', 'n', 'a', 'l') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulExternalKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('o') => match input.next() { - Some('n') => match input.next() { - Some('s') => { - if scan_chars!(input, 't') { - match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'n', 't') - .then_some(TokenKind::YulConstantKeyword) - } else { - None - } - } - Some('r') => { - if self.version_is_at_least_0_5_0 + Some('f') => match input.next() { + Some('a') => { + if scan_chars!(input, 'l') { + match input.next() { + Some('l') => { + if scan_chars!(input, 'b', 'a', 'c', 'k') { + if self.version_is_at_least_0_6_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'u', 'c', 't', 'o', 'r') - .then_some(TokenKind::YulConstructorKeyword) + KeywordScan::Reserved( + TokenKind::YulFallbackKeyword, + ) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some(_) => { - input.undo(); - None + } + Some('s') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::YulFalseKeyword) + } else { + KeywordScan::Absent } - None => None, } - } else { - None + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, } + } else { + KeywordScan::Absent } - Some('t') => match input.next() { - Some('i') => scan_chars!(input, 'n', 'u', 'e') - .then_some(TokenKind::YulContinueKeyword), - Some('r') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'a', 'c', 't') - .then_some(TokenKind::YulContractKeyword) - } else { - None + } + Some('i') => { + if scan_chars!(input, 'n') { + match input.next() { + Some('a') => { + if scan_chars!(input, 'l') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulFinalKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } + Some('n') => { + if scan_chars!(input, 'e', 'y') { + if !self.version_is_at_least_0_7_0 { + KeywordScan::Reserved( + TokenKind::YulFinneyKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some(_) => { - input.undo(); - None + } else { + KeywordScan::Absent } - None => None, - }, - Some('p') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'y', 'o', 'f') - .then_some(TokenKind::YulCopyOfKeyword) + } + Some('o') => { + if scan_chars!(input, 'r') { + KeywordScan::Reserved(TokenKind::YulForKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'n', 'c', 't', 'i', 'o', 'n') { + KeywordScan::Reserved(TokenKind::YulFunctionKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('d') => match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'y', 's').then_some(TokenKind::YulDaysKeyword) + Some('g') => { + if scan_chars!(input, 'w', 'e', 'i') { + if self.version_is_at_least_0_7_0 && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulGweiKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('e') => match input.next() { - Some('f') => match input.next() { - Some('a') => scan_chars!(input, 'u', 'l', 't') - .then_some(TokenKind::YulDefaultKeyword), - Some('i') => { - if self.version_is_at_least_0_5_0 - && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'n', 'e') - .then_some(TokenKind::YulDefineKeyword) + Some('h') => match input.next() { + Some('e') => { + if scan_chars!(input, 'x') { + KeywordScan::Reserved(TokenKind::YulHexKeyword) + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'u', 'r', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulHoursKeyword) } else { - None + KeywordScan::Absent } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('l') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 't', 'e') - .then_some(TokenKind::YulDeleteKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('o') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulDoKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('e') => match input.next() { - Some('l') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 's', 'e').then_some(TokenKind::YulElseKeyword) - } else { - None - } - } - Some('m') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 't').then_some(TokenKind::YulEmitKeyword) - } else { - None - } - } - Some('n') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'u', 'm').then_some(TokenKind::YulEnumKeyword) - } else { - None - } - } - Some('t') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'h', 'e', 'r') - .then_some(TokenKind::YulEtherKeyword) - } else { - None - } - } - Some('v') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'n', 't') - .then_some(TokenKind::YulEventKeyword) - } else { - None - } - } - Some('x') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'e', 'r', 'n', 'a', 'l') - .then_some(TokenKind::YulExternalKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('f') => match input.next() { - Some('a') => { - if scan_chars!(input, 'l') { - match input.next() { - Some('l') => { - if self.version_is_at_least_0_6_0 + Some('i') => match input.next() { + Some('f') => KeywordScan::Reserved(TokenKind::YulIfKeyword), + Some('m') => match input.next() { + Some('m') => { + if scan_chars!(input, 'u', 't', 'a', 'b', 'l', 'e') { + if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'b', 'a', 'c', 'k') - .then_some(TokenKind::YulFallbackKeyword) + KeywordScan::Reserved(TokenKind::YulImmutableKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some('s') => scan_chars!(input, 'e') - .then_some(TokenKind::YulFalseKeyword), - Some(_) => { - input.undo(); - None - } - None => None, } - } else { - None - } - } - Some('i') => { - if scan_chars!(input, 'n') { - match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'l') - .then_some(TokenKind::YulFinalKeyword) + Some('p') => match input.next() { + Some('l') => { + if scan_chars!(input, 'e', 'm', 'e', 'n', 't', 's') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved( + TokenKind::YulImplementsKeyword, + ) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('n') => { - if !self.version_is_at_least_0_7_0 { - scan_chars!(input, 'e', 'y') - .then_some(TokenKind::YulFinneyKeyword) + Some('o') => { + if scan_chars!(input, 'r', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulImportKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent } - } else { - None - } - } - Some('o') => scan_chars!(input, 'r').then_some(TokenKind::YulForKeyword), - Some('u') => scan_chars!(input, 'n', 'c', 't', 'i', 'o', 'n') - .then_some(TokenKind::YulFunctionKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('g') => { - if self.version_is_at_least_0_7_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'w', 'e', 'i').then_some(TokenKind::YulGweiKeyword) - } else { - None - } - } - Some('h') => match input.next() { - Some('e') => scan_chars!(input, 'x').then_some(TokenKind::YulHexKeyword), - Some('o') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'u', 'r', 's') - .then_some(TokenKind::YulHoursKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('i') => match input.next() { - Some('f') => Some(TokenKind::YulIfKeyword), - Some('m') => match input.next() { - Some('m') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'u', 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::YulImmutableKeyword) - } else { - None + None => KeywordScan::Absent, + }, + Some('n') => match input.next() { + Some('d') => { + if scan_chars!(input, 'e', 'x', 'e', 'd') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulIndexedKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('p') => match input.next() { Some('l') => { - if self.version_is_at_least_0_5_0 - && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'e', 'm', 'e', 'n', 't', 's') - .then_some(TokenKind::YulImplementsKeyword) + if scan_chars!(input, 'i', 'n', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulInlineKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('o') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'r', 't') - .then_some(TokenKind::YulImportKeyword) + Some('t') => { + if scan_chars!(input, 'e', 'r') { + match input.next() { + Some('f') => { + if scan_chars!(input, 'a', 'c', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulInterfaceKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'a', 'l') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulInternalKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + if !self.version_is_at_least_0_6_8 { + KeywordScan::Reserved(TokenKind::YulInKeyword) + } else { + KeywordScan::Absent + } + } + None => { + if !self.version_is_at_least_0_6_8 { + KeywordScan::Reserved(TokenKind::YulInKeyword) + } else { + KeywordScan::Absent + } } - None => None, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('n') => match input.next() { - Some('d') => { + Some('s') => { if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'x', 'e', 'd') - .then_some(TokenKind::YulIndexedKeyword) + KeywordScan::Reserved(TokenKind::YulIsKeyword) } else { - None + KeywordScan::Absent } } - Some('l') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 'n', 'e') - .then_some(TokenKind::YulInlineKeyword) - } else { - None - } + Some(_) => { + input.undo(); + KeywordScan::Absent } - Some('t') => { - if scan_chars!(input, 'e', 'r') { - match input.next() { - Some('f') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'a', 'c', 'e') - .then_some(TokenKind::YulInterfaceKeyword) - } else { - None - } - } - Some('n') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'a', 'l') - .then_some(TokenKind::YulInternalKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None + None => KeywordScan::Absent, + }, + Some('l') => match input.next() { + Some('e') => match input.next() { + Some('a') => { + if scan_chars!(input, 'v', 'e') { + if self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulLeaveKeyword) + } else if self.version_is_at_least_0_6_0 { + KeywordScan::Present(TokenKind::YulLeaveKeyword) + } else { + KeywordScan::Absent } - None => None, + } else { + KeywordScan::Absent } - } else { - None - } - } - Some(_) => { - input.undo(); - if !self.version_is_at_least_0_6_8 { - Some(TokenKind::YulInKeyword) - } else { - None } - } - None => { - if !self.version_is_at_least_0_6_8 { - Some(TokenKind::YulInKeyword) - } else { - None + Some('t') => KeywordScan::Reserved(TokenKind::YulLetKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent } - } - }, - Some('s') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulIsKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('l') => match input.next() { - Some('e') => match input.next() { - Some('a') => { - if self.version_is_at_least_0_6_0 { - scan_chars!(input, 'v', 'e') - .then_some(TokenKind::YulLeaveKeyword) + None => KeywordScan::Absent, + }, + Some('i') => { + if scan_chars!(input, 'b', 'r', 'a', 'r', 'y') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulLibraryKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('t') => Some(TokenKind::YulLetKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('i') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'b', 'r', 'a', 'r', 'y') - .then_some(TokenKind::YulLibraryKeyword) - } else { - None + Some('m') => match input.next() { + Some('a') => match input.next() { + Some('c') => { + if scan_chars!(input, 'r', 'o') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulMacroKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('p') => { + if scan_chars!(input, 'p', 'i', 'n', 'g') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulMappingKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'c', 'h') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulMatchKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('e') => { + if scan_chars!(input, 'm', 'o', 'r', 'y') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulMemoryKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('m') => match input.next() { - Some('a') => match input.next() { - Some('c') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'r', 'o') - .then_some(TokenKind::YulMacroKeyword) + Some('i') => { + if scan_chars!(input, 'n', 'u', 't', 'e', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulMinutesKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('p') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'p', 'i', 'n', 'g') - .then_some(TokenKind::YulMappingKeyword) + Some('o') => { + if scan_chars!(input, 'd', 'i', 'f', 'i', 'e', 'r') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulModifierKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('t') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'c', 'h') - .then_some(TokenKind::YulMatchKeyword) + Some('u') => { + if scan_chars!(input, 't', 'a', 'b', 'l', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulMutableKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('e') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'm', 'o', 'r', 'y') - .then_some(TokenKind::YulMemoryKeyword) - } else { - None - } - } - Some('i') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'n', 'u', 't', 'e', 's') - .then_some(TokenKind::YulMinutesKeyword) - } else { - None - } - } - Some('o') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'd', 'i', 'f', 'i', 'e', 'r') - .then_some(TokenKind::YulModifierKeyword) - } else { - None - } - } - Some('u') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::YulMutableKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('n') => match input.next() { - Some('e') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'w').then_some(TokenKind::YulNewKeyword) - } else { - None - } - } - Some('u') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'l', 'l').then_some(TokenKind::YulNullKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('o') => match input.next() { - Some('f') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulOfKeyword) - } else { - None - } - } - Some('v') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'r', 'r', 'i', 'd', 'e') - .then_some(TokenKind::YulOverrideKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('p') => match input.next() { - Some('a') => match input.next() { - Some('r') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 't', 'i', 'a', 'l') - .then_some(TokenKind::YulPartialKeyword) + Some('n') => match input.next() { + Some('e') => { + if scan_chars!(input, 'w') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulNewKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('y') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'a', 'b', 'l', 'e') - .then_some(TokenKind::YulPayableKeyword) + Some('u') => { + if scan_chars!(input, 'l', 'l') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulNullKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('r') => match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'g', 'm', 'a') - .then_some(TokenKind::YulPragmaKeyword) - } else { - None - } - } - Some('i') => { + Some('o') => match input.next() { + Some('f') => { if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'v', 'a', 't', 'e') - .then_some(TokenKind::YulPrivateKeyword) + KeywordScan::Reserved(TokenKind::YulOfKeyword) } else { - None + KeywordScan::Absent } } - Some('o') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'm', 'i', 's', 'e') - .then_some(TokenKind::YulPromiseKeyword) + Some('v') => { + if scan_chars!(input, 'e', 'r', 'r', 'i', 'd', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulOverrideKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('u') => match input.next() { - Some('b') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'l', 'i', 'c') - .then_some(TokenKind::YulPublicKeyword) - } else { - None + Some('p') => match input.next() { + Some('a') => match input.next() { + Some('r') => { + if scan_chars!(input, 't', 'i', 'a', 'l') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulPartialKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('r') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e').then_some(TokenKind::YulPureKeyword) - } else { - None + Some('y') => { + if scan_chars!(input, 'a', 'b', 'l', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPayableKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('r') => match input.next() { + Some('a') => { + if scan_chars!(input, 'g', 'm', 'a') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPragmaKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'v', 'a', 't', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPrivateKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'm', 'i', 's', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulPromiseKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('u') => match input.next() { + Some('b') => { + if scan_chars!(input, 'l', 'i', 'c') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPublicKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPureKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None + Some('r') => { + if scan_chars!(input, 'e') { + match input.next() { + Some('c') => { + if scan_chars!(input, 'e', 'i', 'v', 'e') { + if self.version_is_at_least_0_6_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulReceiveKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('f') => { + if scan_chars!(input, 'e', 'r', 'e', 'n', 'c', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved( + TokenKind::YulReferenceKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('l') => { + if scan_chars!( + input, 'o', 'c', 'a', 't', 'a', 'b', 'l', 'e' + ) { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulRelocatableKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'u', 'r', 'n') { + match input.next() { + Some('s') => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulReturnsKeyword, + ) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Reserved( + TokenKind::YulReturnKeyword, + ) + } + None => KeywordScan::Reserved( + TokenKind::YulReturnKeyword, + ), + } + } else { + KeywordScan::Absent + } + } + Some('v') => { + if scan_chars!(input, 'e', 'r', 't') { + KeywordScan::Reserved(TokenKind::YulRevertKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } } - None => None, - }, - Some('r') => { - if scan_chars!(input, 'e') { - match input.next() { + Some('s') => match input.next() { + Some('e') => match input.next() { + Some('a') => { + if scan_chars!(input, 'l', 'e', 'd') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulSealedKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } Some('c') => { - if self.version_is_at_least_0_6_0 + if scan_chars!(input, 'o', 'n', 'd', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulSecondsKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('i') => { + if scan_chars!(input, 'z', 'e', 'o', 'f') { + if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'i', 'v', 'e') - .then_some(TokenKind::YulReceiveKeyword) + KeywordScan::Reserved(TokenKind::YulSizeOfKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some('f') => { - if self.version_is_at_least_0_5_0 - && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'e', 'r', 'e', 'n', 'c', 'e') - .then_some(TokenKind::YulReferenceKeyword) + } + Some('t') => match input.next() { + Some('a') => { + if scan_chars!(input, 't', 'i', 'c') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulStaticKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('l') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'o', 'c', 'a', 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::YulRelocatableKeyword) + Some('o') => { + if scan_chars!(input, 'r', 'a', 'g', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulStorageKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('t') => { - if scan_chars!(input, 'u', 'r', 'n') { - match input.next() { - Some('s') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulReturnsKeyword) - } else { - None - } + Some('r') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n', 'g') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulStringKeyword) + } else { + KeywordScan::Absent } - Some(_) => { - input.undo(); - Some(TokenKind::YulReturnKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'c', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulStructKeyword) + } else { + KeywordScan::Absent } - None => Some(TokenKind::YulReturnKeyword), + } else { + KeywordScan::Absent } - } else { - None } - } - Some('v') => scan_chars!(input, 'e', 'r', 't') - .then_some(TokenKind::YulRevertKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, Some(_) => { input.undo(); - None + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('u') => { + if scan_chars!(input, 'p', 'p', 'o', 'r', 't', 's') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulSupportsKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent } - None => None, } - } else { - None - } - } - Some('s') => match input.next() { - Some('e') => match input.next() { - Some('a') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'l', 'e', 'd') - .then_some(TokenKind::YulSealedKeyword) + Some('w') => { + if scan_chars!(input, 'i', 't', 'c', 'h') { + KeywordScan::Reserved(TokenKind::YulSwitchKeyword) } else { - None + KeywordScan::Absent } } - Some('c') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'o', 'n', 'd', 's') - .then_some(TokenKind::YulSecondsKeyword) + Some('z') => { + if scan_chars!(input, 'a', 'b', 'o') { + if !self.version_is_at_least_0_7_0 { + KeywordScan::Reserved(TokenKind::YulSzaboKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('i') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'z', 'e', 'o', 'f') - .then_some(TokenKind::YulSizeOfKeyword) - } else { - None - } - } Some('t') => match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'i', 'c') - .then_some(TokenKind::YulStaticKeyword) - } else { - None - } - } - Some('o') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'r', 'a', 'g', 'e') - .then_some(TokenKind::YulStorageKeyword) + Some('h') => { + if scan_chars!(input, 'r', 'o', 'w') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulThrowKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some('r') => match input.next() { - Some('i') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'n', 'g') - .then_some(TokenKind::YulStringKeyword) + Some('u') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::YulTrueKeyword) } else { - None + KeywordScan::Absent } } - Some('u') => { + Some('y') => { if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'c', 't') - .then_some(TokenKind::YulStructKeyword) + KeywordScan::Reserved(TokenKind::YulTryKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, + Some('y') => { + if scan_chars!(input, 'p', 'e') { + match input.next() { + Some('d') => { + if scan_chars!(input, 'e', 'f') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved( + TokenKind::YulTypeDefKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'f') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulTypeOfKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulTypeKeyword) + } else { + KeywordScan::Absent + } + } + None => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulTypeKeyword) + } else { + KeywordScan::Absent + } + } + } + } else { + KeywordScan::Absent + } + } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('u') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'p', 'p', 'o', 'r', 't', 's') - .then_some(TokenKind::YulSupportsKeyword) - } else { - None - } - } - Some('w') => scan_chars!(input, 'i', 't', 'c', 'h') - .then_some(TokenKind::YulSwitchKeyword), - Some('z') => { - if !self.version_is_at_least_0_7_0 { - scan_chars!(input, 'a', 'b', 'o') - .then_some(TokenKind::YulSzaboKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('t') => match input.next() { - Some('h') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'r', 'o', 'w') - .then_some(TokenKind::YulThrowKeyword) - } else { - None - } - } - Some('r') => match input.next() { - Some('u') => { - scan_chars!(input, 'e').then_some(TokenKind::YulTrueKeyword) + Some('u') => match input.next() { + Some('n') => { + if scan_chars!(input, 'c', 'h', 'e', 'c', 'k', 'e', 'd') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulUncheckedKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - Some('y') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulTryKeyword) + Some('s') => { + if scan_chars!(input, 'i', 'n', 'g') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulUsingKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('y') => { - if scan_chars!(input, 'p', 'e') { - match input.next() { - Some('d') => { - if self.version_is_at_least_0_5_0 - && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'e', 'f') - .then_some(TokenKind::YulTypeDefKeyword) - } else { - None - } + Some('v') => match input.next() { + Some('a') => { + if scan_chars!(input, 'r') { + if !self.version_is_at_least_0_6_5 { + KeywordScan::Reserved(TokenKind::YulVarKeyword) + } else { + KeywordScan::Absent } - Some('o') => { + } else { + KeywordScan::Absent + } + } + Some('i') => match input.next() { + Some('e') => { + if scan_chars!(input, 'w') { if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'f') - .then_some(TokenKind::YulTypeOfKeyword) + KeywordScan::Reserved(TokenKind::YulViewKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some(_) => { - input.undo(); - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulTypeKeyword) + } + Some('r') => { + if scan_chars!(input, 't', 'u', 'a', 'l') { + if self.version_is_at_least_0_6_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulVirtualKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - None => { + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('w') => match input.next() { + Some('e') => match input.next() { + Some('e') => { + if scan_chars!(input, 'k', 's') { if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulTypeKeyword) + KeywordScan::Reserved(TokenKind::YulWeeksKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } } - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('u') => match input.next() { - Some('n') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'c', 'h', 'e', 'c', 'k', 'e', 'd') - .then_some(TokenKind::YulUncheckedKeyword) - } else { - None - } - } - Some('s') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 'n', 'g') - .then_some(TokenKind::YulUsingKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('v') => match input.next() { - Some('a') => { - if !self.version_is_at_least_0_6_5 { - scan_chars!(input, 'r').then_some(TokenKind::YulVarKeyword) - } else { - None - } - } - Some('i') => match input.next() { - Some('e') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'w').then_some(TokenKind::YulViewKeyword) - } else { - None + Some('i') => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulWeiKeyword) + } else { + KeywordScan::Absent + } } - } - Some('r') => { - if self.version_is_at_least_0_6_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 't', 'u', 'a', 'l') - .then_some(TokenKind::YulVirtualKeyword) + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('h') => { + if scan_chars!(input, 'i', 'l', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulWhileKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('w') => match input.next() { - Some('e') => match input.next() { - Some('e') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'k', 's') - .then_some(TokenKind::YulWeeksKeyword) - } else { - None - } - } - Some('i') => { + Some('y') => { + if scan_chars!(input, 'e', 'a', 'r', 's') { if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulWeiKeyword) + KeywordScan::Reserved(TokenKind::YulYearsKeyword) } else { - None + KeywordScan::Absent } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('h') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 'l', 'e') - .then_some(TokenKind::YulWhileKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, - }, - Some('y') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'a', 'r', 's') - .then_some(TokenKind::YulYearsKeyword) - } else { - None + None => KeywordScan::Absent, + }; + let kw_scan = match kw_scan { + // Strict prefix; we need to match the whole identifier to promote + _ if input.position() < furthest_position => KeywordScan::Absent, + value => value, + }; + + // Perf: only scan for a compound keyword if we didn't already find one + let mut kw_scan = kw_scan; + if kw_scan == KeywordScan::Absent { + input.set_position(save); + + // TODO: Don't allocate a string here + let ident_value = input.content(save.utf8..furthest_position.utf8); + + for keyword_compound_scanner in [ + Self::yul_bytes_keyword, + Self::yul_fixed_keyword, + Self::yul_int_keyword, + Self::yul_ufixed_keyword, + Self::yul_uint_keyword, + ] { + match keyword_compound_scanner(self, input, &ident_value) { + _ if input.position() < furthest_position => { /* Strict prefix */ } + KeywordScan::Absent => {} + value => kw_scan = value, + } + input.set_position(save); } } - Some(_) => { - input.undo(); - None - } - None => None, - } { - // Make sure that this is not the start of an identifier - if !self.identifier_part(input) { - furthest_position = input.position(); - longest_token = Some(kind); - } - } - input.set_position(save); - - if let Some(kind) = match input.next() { - Some('(') => Some(TokenKind::OpenParen), - Some(')') => Some(TokenKind::CloseParen), - Some(',') => Some(TokenKind::Comma), - Some('-') => scan_chars!(input, '>').then_some(TokenKind::MinusGreaterThan), - Some('.') => Some(TokenKind::Period), - Some(':') => scan_chars!(input, '=').then_some(TokenKind::ColonEqual), - Some('{') => Some(TokenKind::OpenBrace), - Some('}') => Some(TokenKind::CloseBrace), - Some(_) => { - input.undo(); - None - } - None => None, - } { - furthest_position = input.position(); - longest_token = Some(kind); - } - input.set_position(save); - longest_match! { - { AsciiStringLiteral = ascii_string_literal } - { HexStringLiteral = hex_string_literal } - { YulBytesKeyword = yul_bytes_keyword } - { YulDecimalLiteral = yul_decimal_literal } - { YulFixedKeyword = yul_fixed_keyword } - { YulHexLiteral = yul_hex_literal } - { YulIdentifier = yul_identifier } - { YulIntKeyword = yul_int_keyword } - { YulUfixedKeyword = yul_ufixed_keyword } - { YulUintKeyword = yul_uint_keyword } + input.set_position(furthest_position); + return Some(ScannedToken::IdentifierOrKeyword { + identifier, + kw: kw_scan, + }); } } } match longest_token { - Some(..) => { + Some(token) => { input.set_position(furthest_position); - longest_token + Some(ScannedToken::Single(token)) } // Skip a character if possible and if we didn't recognize a token None if input.peek().is_some() => { let _ = input.next(); - Some(TokenKind::SKIPPED) + Some(ScannedToken::Single(TokenKind::SKIPPED)) } - // EOF None => None, } } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/lexer.rs b/crates/solidity/outputs/cargo/crate/src/generated/lexer.rs index 24d119f45c..4cece5532e 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/lexer.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/lexer.rs @@ -4,13 +4,63 @@ use crate::cst::{self, NamedNode}; use crate::kinds::{IsLexicalContext, TokenKind}; use crate::support::{ParserContext, ParserResult}; +/// Whether a keyword has been scanned and if so, whether it is reserved (unusable as an identifier) +/// or not. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KeywordScan { + /// The keyword is not present. + Absent, + /// The keyword is present, but is not reserved. + Present(TokenKind), + /// The keyword is present and is reserved. + Reserved(TokenKind), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ScannedToken { + Single(TokenKind), + IdentifierOrKeyword { + identifier: TokenKind, + kw: KeywordScan, + }, +} + +impl ScannedToken { + pub fn accepted_as(self, expected: TokenKind) -> bool { + match self { + Self::Single(kind) => kind == expected, + Self::IdentifierOrKeyword { identifier, kw } => match kw { + KeywordScan::Reserved(kind) => kind == expected, + KeywordScan::Present(kind) => kind == expected || identifier == expected, + KeywordScan::Absent => identifier == expected, + }, + } + } + + /// Returns the most general token kind that can be accepted for the scanned token. + /// + /// If the scanned token is an identifier, returns the specific keyword kind if the keyword is reserved, + /// otherwise returns the general identifier kind. For other tokens, returns the token kind itself. + pub fn unambiguous(self) -> TokenKind { + match self { + Self::Single(kind) => kind, + Self::IdentifierOrKeyword { identifier, kw } => match kw { + KeywordScan::Reserved(kind) => kind, + // Ambiguous; prefer using the more general identifier + KeywordScan::Present(..) => identifier, + KeywordScan::Absent => identifier, + }, + } + } +} + pub(crate) trait Lexer { // Generated by the templating engine #[doc(hidden)] fn next_token( &self, input: &mut ParserContext<'_>, - ) -> Option; + ) -> Option; // NOTE: These are context-insensitive #[doc(hidden)] fn leading_trivia(&self, input: &mut ParserContext<'_>) -> ParserResult; @@ -24,7 +74,7 @@ pub(crate) trait Lexer { fn peek_token( &self, input: &mut ParserContext<'_>, - ) -> Option { + ) -> Option { let start = input.position(); let token = self.next_token::(input); input.set_position(start); @@ -35,7 +85,7 @@ pub(crate) trait Lexer { fn peek_token_with_trivia( &self, input: &mut ParserContext<'_>, - ) -> Option { + ) -> Option { let start = input.position(); let _ = self.leading_trivia(input); @@ -52,7 +102,10 @@ pub(crate) trait Lexer { kind: TokenKind, ) -> ParserResult { let start = input.position(); - if self.next_token::(input) != Some(kind) { + if !self + .next_token::(input) + .is_some_and(|t| t.accepted_as(kind)) + { input.set_position(start); return ParserResult::no_match(vec![kind]); } @@ -84,7 +137,10 @@ pub(crate) trait Lexer { } let start = input.position(); - if self.next_token::(input) != Some(kind) { + if !self + .next_token::(input) + .is_some_and(|t| t.accepted_as(kind)) + { input.set_position(restore); return ParserResult::no_match(vec![kind]); } diff --git a/crates/solidity/outputs/cargo/crate/src/generated/support/recovery.rs b/crates/solidity/outputs/cargo/crate/src/generated/support/recovery.rs index d1f92a193a..d5976fff49 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/support/recovery.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/support/recovery.rs @@ -2,7 +2,7 @@ use crate::cst; use crate::kinds::{IsLexicalContext, TokenKind}; -use crate::lexer::Lexer; +use crate::lexer::{Lexer, ScannedToken}; use crate::parse_error::ParseError; use crate::support::context::ParserContext; use crate::support::parser_result::SkippedUntil; @@ -65,7 +65,10 @@ impl ParserResult { ParseResultKind::Incomplete, ), ParserResult::Match(result) - if lexer.peek_token_with_trivia::(input) != Some(expected) => + if lexer + .peek_token_with_trivia::(input) + .map(ScannedToken::unambiguous) + != Some(expected) => { (result.nodes, result.expected_tokens, ParseResultKind::Match) } @@ -131,7 +134,10 @@ pub(crate) fn skip_until_with_nested_delims( let mut local_delims = vec![]; loop { let save = input.position(); - match lexer.next_token::(input) { + match lexer + .next_token::(input) + .map(ScannedToken::unambiguous) + { // If we're not skipping past a local delimited group (delimiter stack is empty), // we can unwind on a token that's expected by us or by our ancestor. Some(token) diff --git a/crates/solidity/outputs/cargo/crate/src/generated/support/scanner_macros.rs b/crates/solidity/outputs/cargo/crate/src/generated/support/scanner_macros.rs index 03d7df5919..acc51fb266 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/support/scanner_macros.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/support/scanner_macros.rs @@ -68,6 +68,26 @@ macro_rules! scan_choice { }; } +#[allow(unused_macros)] +macro_rules! scan_keyword_choice { + ($stream:ident, $ident:ident, $($scanner:expr),*) => { + loop { + let save = $stream.position(); + $( + { + if let result @ (KeywordScan::Present(..) | KeywordScan::Reserved(..)) = ($scanner) { + if $ident.len() == $stream.position().utf8 - save.utf8 { + break result; + } + } + } + $stream.set_position(save); + )* + break KeywordScan::Absent; + } + }; +} + #[allow(unused_macros)] macro_rules! scan_zero_or_more { ($stream:ident, $scanner:expr) => { diff --git a/crates/solidity/outputs/cargo/crate/src/generated/support/separated_helper.rs b/crates/solidity/outputs/cargo/crate/src/generated/support/separated_helper.rs index b5c07d9c52..43b00a078c 100644 --- a/crates/solidity/outputs/cargo/crate/src/generated/support/separated_helper.rs +++ b/crates/solidity/outputs/cargo/crate/src/generated/support/separated_helper.rs @@ -26,7 +26,7 @@ impl SeparatedHelper { accum.extend(r#match.nodes); match lexer.peek_token_with_trivia::(input) { - Some(token) if token == separator => { + Some(scanned) if scanned.accepted_as(separator) => { match lexer .parse_token_with_trivia::(input, separator) .with_name(separator_field_name) diff --git a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/ContractDefinition.rs b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/ContractDefinition.rs index 7fb3b8e749..413727a0a2 100644 --- a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/ContractDefinition.rs +++ b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/ContractDefinition.rs @@ -9,6 +9,16 @@ fn abstract_contract() -> Result<()> { run("ContractDefinition", "abstract_contract") } +#[test] +fn constructor_contextual() -> Result<()> { + run("ContractDefinition", "constructor_contextual") +} + +#[test] +fn emit_contextual() -> Result<()> { + run("ContractDefinition", "emit_contextual") +} + #[test] fn empty_contract() -> Result<()> { run("ContractDefinition", "empty_contract") diff --git a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/Expression.rs b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/Expression.rs index 2560b6da8d..b3a1645017 100644 --- a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/Expression.rs +++ b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/Expression.rs @@ -227,6 +227,11 @@ fn keyword_typedef() -> Result<()> { run("Expression", "keyword_typedef") } +#[test] +fn keyword_ufixed() -> Result<()> { + run("Expression", "keyword_ufixed") +} + #[test] fn keyword_unchecked() -> Result<()> { run("Expression", "keyword_unchecked") diff --git a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/Statements.rs b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/Statements.rs index 9e4a2201fb..0a91987a8f 100644 --- a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/Statements.rs +++ b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/Statements.rs @@ -9,6 +9,11 @@ fn compound_tokens() -> Result<()> { run("Statements", "compound_tokens") } +#[test] +fn contextual_keywords() -> Result<()> { + run("Statements", "contextual_keywords") +} + #[test] fn invalid_termination() -> Result<()> { run("Statements", "invalid_termination") diff --git a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/VariableDeclarationStatement.rs b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/VariableDeclarationStatement.rs index 8910362e0a..7f8393a8ad 100644 --- a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/VariableDeclarationStatement.rs +++ b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/VariableDeclarationStatement.rs @@ -4,6 +4,41 @@ use anyhow::Result; use crate::cst_output::runner::run; +#[test] +fn keyword_bytes() -> Result<()> { + run("VariableDeclarationStatement", "keyword_bytes") +} + +#[test] +fn keyword_bytes1() -> Result<()> { + run("VariableDeclarationStatement", "keyword_bytes1") +} + +#[test] +fn keyword_bytes11() -> Result<()> { + run("VariableDeclarationStatement", "keyword_bytes11") +} + +#[test] +fn keyword_ufixed() -> Result<()> { + run("VariableDeclarationStatement", "keyword_ufixed") +} + +#[test] +fn keyword_ufixed184x80() -> Result<()> { + run("VariableDeclarationStatement", "keyword_ufixed184x80") +} + +#[test] +fn keyword_ufixed8x0() -> Result<()> { + run("VariableDeclarationStatement", "keyword_ufixed8x0") +} + +#[test] +fn keyword_ufixed8x8() -> Result<()> { + run("VariableDeclarationStatement", "keyword_ufixed8x8") +} + #[test] fn var() -> Result<()> { run("VariableDeclarationStatement", "var") diff --git a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/YulVariableDeclarationStatement.rs b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/YulVariableDeclarationStatement.rs new file mode 100644 index 0000000000..1935707179 --- /dev/null +++ b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/YulVariableDeclarationStatement.rs @@ -0,0 +1,35 @@ +// This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +use anyhow::Result; + +use crate::cst_output::runner::run; + +#[test] +fn keyword_bytes() -> Result<()> { + run("YulVariableDeclarationStatement", "keyword_bytes") +} + +#[test] +fn keyword_bytes1() -> Result<()> { + run("YulVariableDeclarationStatement", "keyword_bytes1") +} + +#[test] +fn keyword_bytes11() -> Result<()> { + run("YulVariableDeclarationStatement", "keyword_bytes11") +} + +#[test] +fn keyword_ufixed184x80() -> Result<()> { + run("YulVariableDeclarationStatement", "keyword_ufixed184x80") +} + +#[test] +fn keyword_ufixed8x0() -> Result<()> { + run("YulVariableDeclarationStatement", "keyword_ufixed8x0") +} + +#[test] +fn keyword_ufixed8x8() -> Result<()> { + run("YulVariableDeclarationStatement", "keyword_ufixed8x8") +} diff --git a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/mod.rs b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/mod.rs index 4b2c056109..2e9fd3bbec 100644 --- a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/mod.rs +++ b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/mod.rs @@ -91,6 +91,8 @@ mod YulBlock; mod YulExpression; #[allow(non_snake_case)] mod YulLeaveStatement; +#[allow(non_snake_case)] +mod YulVariableDeclarationStatement; pub const VERSION_BREAKS: [Version; 22] = [ Version::new(0, 4, 11), diff --git a/crates/solidity/outputs/npm/crate/src/generated/language.rs b/crates/solidity/outputs/npm/crate/src/generated/language.rs index 27de6b3b64..4f0078d1bb 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/language.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/language.rs @@ -17,7 +17,7 @@ use crate::cst; use crate::kinds::{ FieldName, IsLexicalContext, LexicalContext, LexicalContextType, RuleKind, TokenKind, }; -use crate::lexer::Lexer; +use crate::lexer::{KeywordScan, Lexer, ScannedToken}; #[cfg(feature = "slang_napi_interfaces")] use crate::napi::napi_parse_output::ParseOutput as NAPIParseOutput; use crate::parse_output::ParseOutput; @@ -6340,51 +6340,6 @@ impl Language { ) } - #[allow(unused_assignments, unused_parens)] - fn bytes_keyword(&self, input: &mut ParserContext<'_>) -> bool { - 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') - ) - ) - ) - } - #[allow(unused_assignments, unused_parens)] fn decimal_digits(&self, input: &mut ParserContext<'_>) -> bool { scan_sequence!( @@ -6531,66 +6486,403 @@ impl Language { } #[allow(unused_assignments, unused_parens)] - fn fixed_keyword(&self, input: &mut ParserContext<'_>) -> bool { + 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_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + 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 + } + ) + } + + #[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 hex_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + self.single_quoted_hex_string_literal(input), + self.double_quoted_hex_string_literal(input) + ) + } + + #[allow(unused_assignments, unused_parens)] + fn identifier(&self, input: &mut ParserContext<'_>) -> bool { + self.raw_identifier(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 multiline_comment(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, '/'), + scan_chars!(input, '*'), + scan_zero_or_more!( + 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', '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_none_of!(input, '*'), + scan_not_followed_by!(input, scan_chars!(input, '*'), scan_chars!(input, '/')) + ) + ), + scan_chars!(input, '*'), + scan_chars!(input, '/') + ) + } + + #[allow(unused_assignments, unused_parens)] + fn raw_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 single_line_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_ascii_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_sequence!( + scan_chars!(input, '\''), + scan_zero_or_more!( + input, 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') + 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_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_unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + if self.version_is_at_least_0_7_0 { scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), - scan_choice!( + scan_chars!(input, 'u', 'n', 'i', 'c', 'o', 'd', 'e', '\''), + scan_zero_or_more!( 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_choice!( + input, + self.escape_sequence(input), + scan_none_of!(input, '\'', '\\', '\r', '\n') + ) + ), + scan_chars!(input, '\'') + ) + } else { + false + } + } + + #[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 unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { + scan_choice!( + input, + if self.version_is_at_least_0_7_0 { + self.single_quoted_unicode_string_literal(input) + } else { + false + }, + if self.version_is_at_least_0_7_0 { + self.double_quoted_unicode_string_literal(input) + } else { + false + } + ) + } + + #[allow(unused_assignments, unused_parens)] + fn version_pragma_value(&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 { + self.raw_identifier(input) + } + + // Keyword scanners + #[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(TokenKind::BytesKeyword) + } else { + KeywordScan::Absent + } + ) + } + + #[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(TokenKind::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(TokenKind::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'), @@ -6627,75 +6919,213 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '2', '4'), scan_chars!(input, '1', '8', '4', 'x', '1', '6') ) - ), - if self.version_is_at_least_0_4_14 { - 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(TokenKind::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(TokenKind::FixedKeyword) + } else { + KeywordScan::Present(TokenKind::FixedKeyword) + } } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 { - scan_sequence!( - scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), + 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(TokenKind::FixedKeyword) + } else { + KeywordScan::Present(TokenKind::FixedKeyword) + } + } else { + KeywordScan::Absent + } + ) + } + + #[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'), @@ -6730,373 +7160,73 @@ impl Language { 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(TokenKind::IntKeyword) } else { - false + KeywordScan::Absent } ) } - #[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!( + #[inline] + fn ufixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_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)) - ) - ) + ident, + if scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TokenKind::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') ), - self.identifier_start(input) - ), - if !self.version_is_at_least_0_5_0 { - scan_not_followed_by!( + scan_chars!(input, 'x'), + scan_choice!( 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) + 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(TokenKind::UfixedKeyword) } else { - false - } - ) - } - - #[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 hex_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - self.single_quoted_hex_string_literal(input), - self.double_quoted_hex_string_literal(input) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn identifier(&self, input: &mut ParserContext<'_>) -> bool { - self.raw_identifier(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 int_keyword(&self, input: &mut ParserContext<'_>) -> bool { - 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') - ) - ) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn multiline_comment(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - 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, '*'), - scan_chars!(input, '/') - ) - } - - #[allow(unused_assignments, unused_parens)] - fn raw_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 single_line_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_ascii_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - 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_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_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 ufixed_keyword(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), - 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') - ) - ), - scan_sequence!( + KeywordScan::Absent + }, + if scan_sequence!( scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7146,198 +7276,82 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '2', '4'), scan_chars!(input, '1', '8', '4', 'x', '1', '6') ) - ), - if self.version_is_at_least_0_4_14 { - 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(TokenKind::UfixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 { - 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 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(TokenKind::UfixedKeyword) + } else { + KeywordScan::Present(TokenKind::UfixedKeyword) + } } else { - false - } - ) - } - - #[allow(unused_assignments, unused_parens)] - fn uint_keyword(&self, input: &mut ParserContext<'_>) -> bool { - scan_sequence!( - scan_chars!(input, 'u', 'i', 'n', 't'), - scan_optional!( - input, + KeywordScan::Absent + }, + if scan_sequence!( + scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, scan_chars!(input, '9', '6'), @@ -7372,137 +7386,214 @@ impl Language { 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') ) - ) - ) - } - - #[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 unicode_string_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( - input, - if self.version_is_at_least_0_7_0 { - self.single_quoted_unicode_string_literal(input) - } else { - false - }, - if self.version_is_at_least_0_7_0 { - self.double_quoted_unicode_string_literal(input) + ) { + if self.version_is_at_least_0_4_14 { + KeywordScan::Reserved(TokenKind::UfixedKeyword) + } else { + KeywordScan::Present(TokenKind::UfixedKeyword) + } } else { - false + KeywordScan::Absent } ) } - #[allow(unused_assignments, unused_parens)] - fn version_pragma_value(&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!( + #[inline] + fn uint_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( input, - scan_choice!(input, scan_chars!(input, ' '), scan_chars!(input, '\t')) - ) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_bytes_keyword(&self, input: &mut ParserContext<'_>) -> bool { - if !self.version_is_at_least_0_7_1 { - scan_sequence!( - scan_chars!(input, 'b', 'y', 't', 'e', 's'), + ident, + if scan_sequence!( + scan_chars!(input, 'u', 'i', 'n', 't'), scan_optional!( input, scan_choice!( input, - scan_chars!(input, '9'), + scan_chars!(input, '9', '6'), + scan_chars!(input, '8', '8'), + scan_chars!(input, '8', '0'), scan_chars!(input, '8'), - scan_chars!(input, '7'), - scan_chars!(input, '6'), - scan_chars!(input, '5'), - scan_chars!(input, '4'), + 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, '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', '5', '6'), + scan_chars!(input, '2', '4', '8'), + scan_chars!(input, '2', '4', '0'), 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, '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'), - 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, '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') ) ) - ) - } else { - false - } + ) { + KeywordScan::Reserved(TokenKind::UintKeyword) + } else { + KeywordScan::Absent + } + ) } - #[allow(unused_assignments, unused_parens)] - fn yul_decimal_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_not_followed_by!( + #[inline] + fn yul_bytes_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( 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')) + 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') + ) + ) ) - ), - self.identifier_start(input) + { + KeywordScan::Reserved(TokenKind::YulBytesKeyword) + } else { + KeywordScan::Absent + } ) } - #[allow(unused_assignments, unused_parens)] - fn yul_fixed_keyword(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( + #[inline] + fn yul_fixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( input, - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'f', 'i', 'x', 'e', 'd') + ident, + if !self.version_is_at_least_0_7_1 && scan_chars!(input, 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent }, - if !self.version_is_at_least_0_7_1 { - scan_sequence!( + if !self.version_is_at_least_0_7_1 + && scan_sequence!( scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7544,11 +7635,13 @@ impl Language { scan_chars!(input, '1', '6') ) ) + { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent }, - if !self.version_is_at_least_0_7_1 { - scan_sequence!( + if !self.version_is_at_least_0_7_1 + && scan_sequence!( scan_chars!(input, 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7599,11 +7692,14 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '1', '6') ) ) + { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 && !self.version_is_at_least_0_7_1 { - scan_sequence!( + 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, @@ -7664,11 +7760,14 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '8', '0') ) ) + { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 && !self.version_is_at_least_0_7_1 { - scan_sequence!( + 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, @@ -7781,89 +7880,81 @@ impl Language { scan_chars!(input, '0') ) ) + { + KeywordScan::Reserved(TokenKind::YulFixedKeyword) } else { - false + KeywordScan::Absent } ) } - #[allow(unused_assignments, unused_parens)] - fn yul_hex_literal(&self, input: &mut ParserContext<'_>) -> bool { - scan_not_followed_by!( + #[inline] + fn yul_int_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( 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 { - self.raw_identifier(input) - } - - #[allow(unused_assignments, unused_parens)] - fn yul_int_keyword(&self, input: &mut ParserContext<'_>) -> bool { - if !self.version_is_at_least_0_7_1 { - scan_sequence!( - scan_chars!(input, 'i', 'n', 't'), - scan_optional!( - input, - scan_choice!( + ident, + if !self.version_is_at_least_0_7_1 + && scan_sequence!( + scan_chars!(input, 'i', 'n', 't'), + scan_optional!( 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_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') + ) ) ) - ) - } else { - false - } + { + KeywordScan::Reserved(TokenKind::YulIntKeyword) + } else { + KeywordScan::Absent + } + ) } - #[allow(unused_assignments, unused_parens)] - fn yul_ufixed_keyword(&self, input: &mut ParserContext<'_>) -> bool { - scan_choice!( + #[inline] + fn yul_ufixed_keyword(&self, input: &mut ParserContext<'_>, ident: &str) -> KeywordScan { + scan_keyword_choice!( input, - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') + ident, + if !self.version_is_at_least_0_7_1 && scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd') { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent }, - if !self.version_is_at_least_0_7_1 { - scan_sequence!( + if !self.version_is_at_least_0_7_1 + && scan_sequence!( scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7905,11 +7996,13 @@ impl Language { scan_chars!(input, '1', '6') ) ) + { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent }, - if !self.version_is_at_least_0_7_1 { - scan_sequence!( + if !self.version_is_at_least_0_7_1 + && scan_sequence!( scan_chars!(input, 'u', 'f', 'i', 'x', 'e', 'd'), scan_choice!( input, @@ -7960,11 +8053,14 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '1', '6') ) ) + { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 && !self.version_is_at_least_0_7_1 { - scan_sequence!( + 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, @@ -8025,11 +8121,14 @@ impl Language { scan_chars!(input, '1', '8', '4', 'x', '8', '0') ) ) + { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent }, - if self.version_is_at_least_0_4_14 && !self.version_is_at_least_0_7_1 { - scan_sequence!( + 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, @@ -8142,59 +8241,67 @@ impl Language { scan_chars!(input, '0') ) ) + { + KeywordScan::Reserved(TokenKind::YulUfixedKeyword) } else { - false + KeywordScan::Absent } ) } - #[allow(unused_assignments, unused_parens)] - fn yul_uint_keyword(&self, input: &mut ParserContext<'_>) -> bool { - if !self.version_is_at_least_0_7_1 { - scan_sequence!( - scan_chars!(input, 'u', 'i', 'n', 't'), - scan_optional!( - input, - scan_choice!( + #[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_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_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') + ) ) ) - ) - } else { - false - } + { + KeywordScan::Reserved(TokenKind::YulUintKeyword) + } else { + KeywordScan::Absent + } + ) } pub fn parse(&self, kind: RuleKind, input: &str) -> ParseOutput { @@ -8514,849 +8621,1422 @@ impl Lexer for Language { fn next_token( &self, input: &mut ParserContext<'_>, - ) -> Option { + ) -> Option { let save = input.position(); let mut furthest_position = input.position(); let mut longest_token = None; - match LexCtx::value() { - LexicalContext::Default => { - macro_rules! longest_match { - ($( { $kind:ident = $function:ident } )*) => { - $( - if self.$function(input) && input.position() > furthest_position { - furthest_position = input.position(); - longest_token = Some(TokenKind::$kind); - } - input.set_position(save); - )* - }; + macro_rules! longest_match { + ($( { $kind:ident = $function:ident } )*) => { + $( + if self.$function(input) && input.position() > furthest_position { + furthest_position = input.position(); + + longest_token = Some(TokenKind::$kind); } + input.set_position(save); + )* + }; + } + match LexCtx::value() { + LexicalContext::Default => { if let Some(kind) = match input.next() { - Some('a') => match input.next() { - Some('b') => scan_chars!(input, 's', 't', 'r', 'a', 'c', 't') - .then_some(TokenKind::AbstractKeyword), - Some('d') => scan_chars!(input, 'd', 'r', 'e', 's', 's') - .then_some(TokenKind::AddressKeyword), - Some('f') => { - scan_chars!(input, 't', 'e', 'r').then_some(TokenKind::AfterKeyword) + Some('!') => match input.next() { + Some('=') => Some(TokenKind::BangEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Bang) } - Some('l') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'i', 'a', 's').then_some(TokenKind::AliasKeyword) - } else { - None + None => Some(TokenKind::Bang), + }, + Some('%') => match input.next() { + Some('=') => Some(TokenKind::PercentEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Percent) + } + None => Some(TokenKind::Percent), + }, + Some('&') => match input.next() { + Some('&') => Some(TokenKind::AmpersandAmpersand), + Some('=') => Some(TokenKind::AmpersandEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Ampersand) + } + None => Some(TokenKind::Ampersand), + }, + Some('(') => Some(TokenKind::OpenParen), + Some(')') => Some(TokenKind::CloseParen), + Some('*') => match input.next() { + Some('*') => Some(TokenKind::AsteriskAsterisk), + Some('=') => Some(TokenKind::AsteriskEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Asterisk) + } + None => Some(TokenKind::Asterisk), + }, + Some('+') => match input.next() { + Some('+') => Some(TokenKind::PlusPlus), + Some('=') => Some(TokenKind::PlusEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Plus) + } + None => Some(TokenKind::Plus), + }, + Some(',') => Some(TokenKind::Comma), + Some('-') => match input.next() { + Some('-') => Some(TokenKind::MinusMinus), + Some('=') => Some(TokenKind::MinusEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Minus) + } + None => Some(TokenKind::Minus), + }, + Some('.') => Some(TokenKind::Period), + Some('/') => match input.next() { + Some('=') => Some(TokenKind::SlashEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Slash) + } + None => Some(TokenKind::Slash), + }, + Some(':') => Some(TokenKind::Colon), + Some(';') => Some(TokenKind::Semicolon), + Some('<') => match input.next() { + Some('<') => match input.next() { + Some('=') => Some(TokenKind::LessThanLessThanEqual), + Some(_) => { + input.undo(); + Some(TokenKind::LessThanLessThan) + } + None => Some(TokenKind::LessThanLessThan), + }, + Some('=') => Some(TokenKind::LessThanEqual), + Some(_) => { + input.undo(); + Some(TokenKind::LessThan) + } + None => Some(TokenKind::LessThan), + }, + Some('=') => match input.next() { + Some('=') => Some(TokenKind::EqualEqual), + Some('>') => Some(TokenKind::EqualGreaterThan), + Some(_) => { + input.undo(); + Some(TokenKind::Equal) + } + None => Some(TokenKind::Equal), + }, + Some('>') => match input.next() { + Some('=') => Some(TokenKind::GreaterThanEqual), + Some('>') => match input.next() { + Some('=') => Some(TokenKind::GreaterThanGreaterThanEqual), + Some('>') => match input.next() { + Some('=') => { + Some(TokenKind::GreaterThanGreaterThanGreaterThanEqual) + } + Some(_) => { + input.undo(); + Some(TokenKind::GreaterThanGreaterThanGreaterThan) + } + None => Some(TokenKind::GreaterThanGreaterThanGreaterThan), + }, + Some(_) => { + input.undo(); + Some(TokenKind::GreaterThanGreaterThan) + } + None => Some(TokenKind::GreaterThanGreaterThan), + }, + Some(_) => { + input.undo(); + Some(TokenKind::GreaterThan) + } + None => Some(TokenKind::GreaterThan), + }, + Some('?') => Some(TokenKind::QuestionMark), + Some('[') => Some(TokenKind::OpenBracket), + Some(']') => Some(TokenKind::CloseBracket), + Some('^') => match input.next() { + Some('=') => Some(TokenKind::CaretEqual), + Some(_) => { + input.undo(); + Some(TokenKind::Caret) + } + None => Some(TokenKind::Caret), + }, + Some('{') => Some(TokenKind::OpenBrace), + Some('|') => match input.next() { + Some('=') => Some(TokenKind::BarEqual), + Some('|') => Some(TokenKind::BarBar), + Some(_) => { + input.undo(); + Some(TokenKind::Bar) + } + None => Some(TokenKind::Bar), + }, + Some('}') => Some(TokenKind::CloseBrace), + Some('~') => Some(TokenKind::Tilde), + Some(_) => { + input.undo(); + None + } + None => None, + } { + furthest_position = input.position(); + longest_token = Some(kind); + } + input.set_position(save); + + longest_match! { + { AsciiStringLiteral = ascii_string_literal } + { DecimalLiteral = decimal_literal } + { EndOfLine = end_of_line } + { HexLiteral = hex_literal } + { HexStringLiteral = hex_string_literal } + { MultilineComment = multiline_comment } + { SingleLineComment = single_line_comment } + { UnicodeStringLiteral = unicode_string_literal } + { Whitespace = whitespace } + } + // Make sure promotable identifiers are last so they don't grab other things + longest_match! { + { Identifier = identifier } + } + + // We have an identifier; we need to check if it's a keyword + if let Some(identifier) = + longest_token.filter(|tok| [TokenKind::Identifier].contains(tok)) + { + let kw_scan = match input.next() { + Some('a') => match input.next() { + Some('b') => { + if scan_chars!(input, 's', 't', 'r', 'a', 'c', 't') { + KeywordScan::Reserved(TokenKind::AbstractKeyword) + } else { + KeywordScan::Absent + } + } + Some('d') => { + if scan_chars!(input, 'd', 'r', 'e', 's', 's') { + KeywordScan::Reserved(TokenKind::AddressKeyword) + } else { + KeywordScan::Absent + } + } + Some('f') => { + if scan_chars!(input, 't', 'e', 'r') { + KeywordScan::Reserved(TokenKind::AfterKeyword) + } else { + KeywordScan::Absent + } + } + Some('l') => { + if scan_chars!(input, 'i', 'a', 's') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::AliasKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'o', 'n', 'y', 'm', 'o', 'u', 's') { + KeywordScan::Reserved(TokenKind::AnonymousKeyword) + } else { + KeywordScan::Absent + } + } + Some('p') => { + if scan_chars!(input, 'p', 'l', 'y') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::ApplyKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('s') => match input.next() { + Some('s') => { + if scan_chars!(input, 'e', 'm', 'b', 'l', 'y') { + KeywordScan::Reserved(TokenKind::AssemblyKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Reserved(TokenKind::AsKeyword) + } + None => KeywordScan::Reserved(TokenKind::AsKeyword), + }, + Some('u') => { + if scan_chars!(input, 't', 'o') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::AutoKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('b') => match input.next() { + Some('o') => { + if scan_chars!(input, 'o', 'l') { + KeywordScan::Reserved(TokenKind::BoolKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'e', 'a', 'k') { + KeywordScan::Reserved(TokenKind::BreakKeyword) + } else { + KeywordScan::Absent + } + } + Some('y') => { + if scan_chars!(input, 't', 'e') { + KeywordScan::Reserved(TokenKind::ByteKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('c') => match input.next() { + Some('a') => match input.next() { + Some('l') => { + if scan_chars!(input, 'l', 'd', 'a', 't', 'a') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::CallDataKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('s') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::CaseKeyword) + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'c', 'h') { + KeywordScan::Reserved(TokenKind::CatchKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => match input.next() { + Some('n') => match input.next() { + Some('s') => { + if scan_chars!(input, 't') { + match input.next() { + Some('a') => { + if scan_chars!(input, 'n', 't') { + KeywordScan::Reserved( + TokenKind::ConstantKeyword, + ) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'u', 'c', 't', 'o', 'r') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved( + TokenKind::ConstructorKeyword, + ) + } else if self.version_is_at_least_0_4_22 { + KeywordScan::Present( + TokenKind::ConstructorKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } + } + Some('t') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n', 'u', 'e') { + KeywordScan::Reserved(TokenKind::ContinueKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'a', 'c', 't') { + KeywordScan::Reserved(TokenKind::ContractKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('p') => { + if scan_chars!(input, 'y', 'o', 'f') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::CopyOfKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('d') => match input.next() { + Some('a') => { + if scan_chars!(input, 'y', 's') { + KeywordScan::Reserved(TokenKind::DaysKeyword) + } else { + KeywordScan::Absent + } + } + Some('e') => match input.next() { + Some('f') => match input.next() { + Some('a') => { + if scan_chars!(input, 'u', 'l', 't') { + KeywordScan::Reserved(TokenKind::DefaultKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'n', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::DefineKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('l') => { + if scan_chars!(input, 'e', 't', 'e') { + KeywordScan::Reserved(TokenKind::DeleteKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => KeywordScan::Reserved(TokenKind::DoKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('e') => match input.next() { + Some('l') => { + if scan_chars!(input, 's', 'e') { + KeywordScan::Reserved(TokenKind::ElseKeyword) + } else { + KeywordScan::Absent + } + } + Some('m') => { + if scan_chars!(input, 'i', 't') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::EmitKeyword) + } else if self.version_is_at_least_0_4_21 { + KeywordScan::Present(TokenKind::EmitKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'u', 'm') { + KeywordScan::Reserved(TokenKind::EnumKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'r', 'o', 'r') { + if self.version_is_at_least_0_8_4 { + KeywordScan::Present(TokenKind::ErrorKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'h', 'e', 'r') { + KeywordScan::Reserved(TokenKind::EtherKeyword) + } else { + KeywordScan::Absent + } + } + Some('v') => { + if scan_chars!(input, 'e', 'n', 't') { + KeywordScan::Reserved(TokenKind::EventKeyword) + } else { + KeywordScan::Absent + } } - } - Some('n') => scan_chars!(input, 'o', 'n', 'y', 'm', 'o', 'u', 's') - .then_some(TokenKind::AnonymousKeyword), - Some('p') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'p', 'l', 'y').then_some(TokenKind::ApplyKeyword) - } else { - None + Some('x') => { + if scan_chars!(input, 't', 'e', 'r', 'n', 'a', 'l') { + KeywordScan::Reserved(TokenKind::ExternalKeyword) + } else { + KeywordScan::Absent + } } - } - Some('s') => match input.next() { - Some('s') => scan_chars!(input, 'e', 'm', 'b', 'l', 'y') - .then_some(TokenKind::AssemblyKeyword), Some(_) => { input.undo(); - Some(TokenKind::AsKeyword) + KeywordScan::Absent } - None => Some(TokenKind::AsKeyword), + None => KeywordScan::Absent, }, - Some('u') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 't', 'o').then_some(TokenKind::AutoKeyword) - } else { - None + Some('f') => match input.next() { + Some('a') => { + if scan_chars!(input, 'l') { + match input.next() { + Some('l') => { + if scan_chars!(input, 'b', 'a', 'c', 'k') { + if self.version_is_at_least_0_6_0 { + KeywordScan::Reserved( + TokenKind::FallbackKeyword, + ) + } else { + KeywordScan::Present(TokenKind::FallbackKeyword) + } + } else { + KeywordScan::Absent + } + } + Some('s') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::FalseKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('b') => match input.next() { - Some('o') => scan_chars!(input, 'o', 'l').then_some(TokenKind::BoolKeyword), - Some('r') => { - scan_chars!(input, 'e', 'a', 'k').then_some(TokenKind::BreakKeyword) - } - Some('y') => scan_chars!(input, 't', 'e').then_some(TokenKind::ByteKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('c') => match input.next() { - Some('a') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n') { + match input.next() { + Some('a') => { + if scan_chars!(input, 'l') { + KeywordScan::Reserved(TokenKind::FinalKeyword) + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'e', 'y') { + if !self.version_is_at_least_0_7_0 { + KeywordScan::Reserved(TokenKind::FinneyKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'r') { + KeywordScan::Reserved(TokenKind::ForKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'o', 'm') { + if true { + KeywordScan::Present(TokenKind::FromKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'n', 'c', 't', 'i', 'o', 'n') { + KeywordScan::Reserved(TokenKind::FunctionKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('g') => match input.next() { Some('l') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'l', 'd', 'a', 't', 'a') - .then_some(TokenKind::CallDataKeyword) + if scan_chars!(input, 'o', 'b', 'a', 'l') { + if self.version_is_at_least_0_8_13 { + KeywordScan::Present(TokenKind::GlobalKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('s') => scan_chars!(input, 'e').then_some(TokenKind::CaseKeyword), - Some('t') => { - scan_chars!(input, 'c', 'h').then_some(TokenKind::CatchKeyword) + Some('w') => { + if scan_chars!(input, 'e', 'i') { + if self.version_is_at_least_0_7_0 { + KeywordScan::Reserved(TokenKind::GweiKeyword) + } else if self.version_is_at_least_0_6_11 { + KeywordScan::Present(TokenKind::GweiKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('o') => match input.next() { + Some('h') => match input.next() { + Some('e') => { + if scan_chars!(input, 'x') { + KeywordScan::Reserved(TokenKind::HexKeyword) + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'u', 'r', 's') { + KeywordScan::Reserved(TokenKind::HoursKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('i') => match input.next() { + Some('f') => KeywordScan::Reserved(TokenKind::IfKeyword), + Some('m') => match input.next() { + Some('m') => { + if scan_chars!(input, 'u', 't', 'a', 'b', 'l', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::ImmutableKeyword) + } else if self.version_is_at_least_0_6_5 { + KeywordScan::Present(TokenKind::ImmutableKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('p') => match input.next() { + Some('l') => { + if scan_chars!(input, 'e', 'm', 'e', 'n', 't', 's') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::ImplementsKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'r', 't') { + KeywordScan::Reserved(TokenKind::ImportKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, Some('n') => match input.next() { - Some('s') => { - if scan_chars!(input, 't') { + Some('d') => { + if scan_chars!(input, 'e', 'x', 'e', 'd') { + KeywordScan::Reserved(TokenKind::IndexedKeyword) + } else { + KeywordScan::Absent + } + } + Some('l') => { + if scan_chars!(input, 'i', 'n', 'e') { + KeywordScan::Reserved(TokenKind::InlineKeyword) + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'e', 'r') { match input.next() { - Some('a') => scan_chars!(input, 'n', 't') - .then_some(TokenKind::ConstantKeyword), - Some('r') => { - if self.version_is_at_least_0_4_22 { - scan_chars!(input, 'u', 'c', 't', 'o', 'r') - .then_some(TokenKind::ConstructorKeyword) + Some('f') => { + if scan_chars!(input, 'a', 'c', 'e') { + KeywordScan::Reserved( + TokenKind::InterfaceKeyword, + ) + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'a', 'l') { + KeywordScan::Reserved( + TokenKind::InternalKeyword, + ) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, } } else { - None + KeywordScan::Absent } } - Some('t') => match input.next() { - Some('i') => scan_chars!(input, 'n', 'u', 'e') - .then_some(TokenKind::ContinueKeyword), - Some('r') => scan_chars!(input, 'a', 'c', 't') - .then_some(TokenKind::ContractKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, Some(_) => { input.undo(); - None + KeywordScan::Reserved(TokenKind::InKeyword) } - None => None, + None => KeywordScan::Reserved(TokenKind::InKeyword), }, - Some('p') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'y', 'o', 'f') - .then_some(TokenKind::CopyOfKeyword) + Some('s') => KeywordScan::Reserved(TokenKind::IsKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('l') => match input.next() { + Some('e') => { + if scan_chars!(input, 't') { + KeywordScan::Reserved(TokenKind::LetKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'b', 'r', 'a', 'r', 'y') { + KeywordScan::Reserved(TokenKind::LibraryKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('d') => match input.next() { - Some('a') => scan_chars!(input, 'y', 's').then_some(TokenKind::DaysKeyword), - Some('e') => match input.next() { - Some('f') => match input.next() { - Some('a') => scan_chars!(input, 'u', 'l', 't') - .then_some(TokenKind::DefaultKeyword), - Some('i') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'n', 'e') - .then_some(TokenKind::DefineKeyword) + Some('m') => match input.next() { + Some('a') => match input.next() { + Some('c') => { + if scan_chars!(input, 'r', 'o') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::MacroKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent + } + } + Some('p') => { + if scan_chars!(input, 'p', 'i', 'n', 'g') { + KeywordScan::Reserved(TokenKind::MappingKeyword) + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'c', 'h') { + KeywordScan::Reserved(TokenKind::MatchKeyword) + } else { + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('l') => scan_chars!(input, 'e', 't', 'e') - .then_some(TokenKind::DeleteKeyword), + Some('e') => { + if scan_chars!(input, 'm', 'o', 'r', 'y') { + KeywordScan::Reserved(TokenKind::MemoryKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'n', 'u', 't', 'e', 's') { + KeywordScan::Reserved(TokenKind::MinutesKeyword) + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'd', 'i', 'f', 'i', 'e', 'r') { + KeywordScan::Reserved(TokenKind::ModifierKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 't', 'a', 'b', 'l', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::MutableKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('o') => Some(TokenKind::DoKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('e') => match input.next() { - Some('l') => scan_chars!(input, 's', 'e').then_some(TokenKind::ElseKeyword), - Some('m') => { - if self.version_is_at_least_0_4_21 { - scan_chars!(input, 'i', 't').then_some(TokenKind::EmitKeyword) - } else { - None + Some('n') => match input.next() { + Some('e') => { + if scan_chars!(input, 'w') { + KeywordScan::Reserved(TokenKind::NewKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'l', 'l') { + KeywordScan::Reserved(TokenKind::NullKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => match input.next() { + Some('f') => KeywordScan::Reserved(TokenKind::OfKeyword), + Some('v') => { + if scan_chars!(input, 'e', 'r', 'r', 'i', 'd', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::OverrideKeyword) + } else { + KeywordScan::Present(TokenKind::OverrideKeyword) + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('p') => match input.next() { + Some('a') => match input.next() { + Some('r') => { + if scan_chars!(input, 't', 'i', 'a', 'l') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::PartialKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('y') => { + if scan_chars!(input, 'a', 'b', 'l', 'e') { + KeywordScan::Reserved(TokenKind::PayableKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('r') => match input.next() { + Some('a') => { + if scan_chars!(input, 'g', 'm', 'a') { + KeywordScan::Reserved(TokenKind::PragmaKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'v', 'a', 't', 'e') { + KeywordScan::Reserved(TokenKind::PrivateKeyword) + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'm', 'i', 's', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::PromiseKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('u') => match input.next() { + Some('b') => { + if scan_chars!(input, 'l', 'i', 'c') { + KeywordScan::Reserved(TokenKind::PublicKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::PureKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent } - } - Some('n') => scan_chars!(input, 'u', 'm').then_some(TokenKind::EnumKeyword), + None => KeywordScan::Absent, + }, Some('r') => { - if self.version_is_at_least_0_8_4 { - scan_chars!(input, 'r', 'o', 'r').then_some(TokenKind::ErrorKeyword) - } else { - None - } - } - Some('t') => { - scan_chars!(input, 'h', 'e', 'r').then_some(TokenKind::EtherKeyword) - } - Some('v') => { - scan_chars!(input, 'e', 'n', 't').then_some(TokenKind::EventKeyword) - } - Some('x') => scan_chars!(input, 't', 'e', 'r', 'n', 'a', 'l') - .then_some(TokenKind::ExternalKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('f') => match input.next() { - Some('a') => { - if scan_chars!(input, 'l') { + if scan_chars!(input, 'e') { match input.next() { + Some('c') => { + if scan_chars!(input, 'e', 'i', 'v', 'e') { + if self.version_is_at_least_0_6_0 { + KeywordScan::Reserved(TokenKind::ReceiveKeyword) + } else { + KeywordScan::Present(TokenKind::ReceiveKeyword) + } + } else { + KeywordScan::Absent + } + } + Some('f') => { + if scan_chars!(input, 'e', 'r', 'e', 'n', 'c', 'e') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::ReferenceKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } Some('l') => { - if self.version_is_at_least_0_6_0 { - scan_chars!(input, 'b', 'a', 'c', 'k') - .then_some(TokenKind::FallbackKeyword) + if scan_chars!( + input, 'o', 'c', 'a', 't', 'a', 'b', 'l', 'e' + ) { + KeywordScan::Reserved(TokenKind::RelocatableKeyword) } else { - None + KeywordScan::Absent } } - Some('s') => { - scan_chars!(input, 'e').then_some(TokenKind::FalseKeyword) + Some('t') => { + if scan_chars!(input, 'u', 'r', 'n') { + match input.next() { + Some('s') => { + KeywordScan::Reserved(TokenKind::ReturnsKeyword) + } + Some(_) => { + input.undo(); + KeywordScan::Reserved(TokenKind::ReturnKeyword) + } + None => { + KeywordScan::Reserved(TokenKind::ReturnKeyword) + } + } + } else { + KeywordScan::Absent + } + } + Some('v') => { + if scan_chars!(input, 'e', 'r', 't') { + if self.version_is_at_least_0_8_4 { + KeywordScan::Present(TokenKind::RevertKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, } } else { - None + KeywordScan::Absent } } - Some('i') => { - if scan_chars!(input, 'n') { - match input.next() { - Some('a') => { - scan_chars!(input, 'l').then_some(TokenKind::FinalKeyword) - } - Some('n') => { - if !self.version_is_at_least_0_7_0 { - scan_chars!(input, 'e', 'y') - .then_some(TokenKind::FinneyKeyword) + Some('s') => match input.next() { + Some('e') => match input.next() { + Some('a') => { + if scan_chars!(input, 'l', 'e', 'd') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::SealedKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some(_) => { - input.undo(); - None + } + Some('c') => { + if scan_chars!(input, 'o', 'n', 'd', 's') { + KeywordScan::Reserved(TokenKind::SecondsKeyword) + } else { + KeywordScan::Absent } - None => None, } - } else { - None - } - } - Some('o') => scan_chars!(input, 'r').then_some(TokenKind::ForKeyword), - Some('r') => scan_chars!(input, 'o', 'm').then_some(TokenKind::FromKeyword), - Some('u') => scan_chars!(input, 'n', 'c', 't', 'i', 'o', 'n') - .then_some(TokenKind::FunctionKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('g') => match input.next() { - Some('l') => { - if self.version_is_at_least_0_8_13 { - scan_chars!(input, 'o', 'b', 'a', 'l') - .then_some(TokenKind::GlobalKeyword) - } else { - None - } - } - Some('w') => { - if self.version_is_at_least_0_6_11 { - scan_chars!(input, 'e', 'i').then_some(TokenKind::GweiKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('h') => match input.next() { - Some('e') => scan_chars!(input, 'x').then_some(TokenKind::HexKeyword), - Some('o') => { - scan_chars!(input, 'u', 'r', 's').then_some(TokenKind::HoursKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('i') => match input.next() { - Some('f') => Some(TokenKind::IfKeyword), - Some('m') => match input.next() { - Some('m') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'u', 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::ImmutableKeyword) + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('i') => { + if scan_chars!(input, 'z', 'e', 'o', 'f') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::SizeOfKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('p') => match input.next() { - Some('l') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'e', 'm', 'e', 'n', 't', 's') - .then_some(TokenKind::ImplementsKeyword) + Some('t') => match input.next() { + Some('a') => { + if scan_chars!(input, 't', 'i', 'c') { + KeywordScan::Reserved(TokenKind::StaticKeyword) } else { - None + KeywordScan::Absent } } Some('o') => { - scan_chars!(input, 'r', 't').then_some(TokenKind::ImportKeyword) + if scan_chars!(input, 'r', 'a', 'g', 'e') { + KeywordScan::Reserved(TokenKind::StorageKeyword) + } else { + KeywordScan::Absent + } } + Some('r') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n', 'g') { + KeywordScan::Reserved(TokenKind::StringKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'c', 't') { + KeywordScan::Reserved(TokenKind::StructKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('n') => match input.next() { - Some('d') => scan_chars!(input, 'e', 'x', 'e', 'd') - .then_some(TokenKind::IndexedKeyword), - Some('l') => scan_chars!(input, 'i', 'n', 'e') - .then_some(TokenKind::InlineKeyword), - Some('t') => { - if scan_chars!(input, 'e', 'r') { - match input.next() { - Some('f') => scan_chars!(input, 'a', 'c', 'e') - .then_some(TokenKind::InterfaceKeyword), - Some('n') => scan_chars!(input, 'a', 'l') - .then_some(TokenKind::InternalKeyword), - Some(_) => { - input.undo(); - None - } - None => None, + Some('u') => { + if scan_chars!(input, 'p', 'p', 'o', 'r', 't', 's') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::SupportsKeyword) + } else { + KeywordScan::Absent } } else { - None + KeywordScan::Absent } } - Some(_) => { - input.undo(); - Some(TokenKind::InKeyword) - } - None => Some(TokenKind::InKeyword), - }, - Some('s') => Some(TokenKind::IsKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('l') => match input.next() { - Some('e') => scan_chars!(input, 't').then_some(TokenKind::LetKeyword), - Some('i') => scan_chars!(input, 'b', 'r', 'a', 'r', 'y') - .then_some(TokenKind::LibraryKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('m') => match input.next() { - Some('a') => match input.next() { - Some('c') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'r', 'o').then_some(TokenKind::MacroKeyword) + Some('w') => { + if scan_chars!(input, 'i', 't', 'c', 'h') { + KeywordScan::Reserved(TokenKind::SwitchKeyword) } else { - None + KeywordScan::Absent } } - Some('p') => scan_chars!(input, 'p', 'i', 'n', 'g') - .then_some(TokenKind::MappingKeyword), - Some('t') => { - scan_chars!(input, 'c', 'h').then_some(TokenKind::MatchKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('e') => scan_chars!(input, 'm', 'o', 'r', 'y') - .then_some(TokenKind::MemoryKeyword), - Some('i') => scan_chars!(input, 'n', 'u', 't', 'e', 's') - .then_some(TokenKind::MinutesKeyword), - Some('o') => scan_chars!(input, 'd', 'i', 'f', 'i', 'e', 'r') - .then_some(TokenKind::ModifierKeyword), - Some('u') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::MutableKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('n') => match input.next() { - Some('e') => scan_chars!(input, 'w').then_some(TokenKind::NewKeyword), - Some('u') => scan_chars!(input, 'l', 'l').then_some(TokenKind::NullKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('o') => match input.next() { - Some('f') => Some(TokenKind::OfKeyword), - Some('v') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'e', 'r', 'r', 'i', 'd', 'e') - .then_some(TokenKind::OverrideKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('p') => match input.next() { - Some('a') => match input.next() { - Some('r') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 't', 'i', 'a', 'l') - .then_some(TokenKind::PartialKeyword) + Some('z') => { + if scan_chars!(input, 'a', 'b', 'o') { + if !self.version_is_at_least_0_7_0 { + KeywordScan::Reserved(TokenKind::SzaboKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('y') => scan_chars!(input, 'a', 'b', 'l', 'e') - .then_some(TokenKind::PayableKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('r') => match input.next() { - Some('a') => scan_chars!(input, 'g', 'm', 'a') - .then_some(TokenKind::PragmaKeyword), - Some('i') => scan_chars!(input, 'v', 'a', 't', 'e') - .then_some(TokenKind::PrivateKeyword), - Some('o') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'm', 'i', 's', 'e') - .then_some(TokenKind::PromiseKeyword) + Some('t') => match input.next() { + Some('h') => { + if scan_chars!(input, 'r', 'o', 'w') { + KeywordScan::Reserved(TokenKind::ThrowKeyword) } else { - None + KeywordScan::Absent } } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('u') => match input.next() { - Some('b') => scan_chars!(input, 'l', 'i', 'c') - .then_some(TokenKind::PublicKeyword), - Some('r') => scan_chars!(input, 'e').then_some(TokenKind::PureKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('r') => { - if scan_chars!(input, 'e') { - match input.next() { - Some('c') => { - if self.version_is_at_least_0_6_0 { - scan_chars!(input, 'e', 'i', 'v', 'e') - .then_some(TokenKind::ReceiveKeyword) - } else { - None - } - } - Some('f') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'e', 'r', 'e', 'n', 'c', 'e') - .then_some(TokenKind::ReferenceKeyword) + Some('r') => match input.next() { + Some('u') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::TrueKeyword) } else { - None + KeywordScan::Absent } } - Some('l') => { - scan_chars!(input, 'o', 'c', 'a', 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::RelocatableKeyword) + Some('y') => KeywordScan::Reserved(TokenKind::TryKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent } - Some('t') => { - if scan_chars!(input, 'u', 'r', 'n') { - match input.next() { - Some('s') => Some(TokenKind::ReturnsKeyword), - Some(_) => { - input.undo(); - Some(TokenKind::ReturnKeyword) + None => KeywordScan::Absent, + }, + Some('y') => { + if scan_chars!(input, 'p', 'e') { + match input.next() { + Some('d') => { + if scan_chars!(input, 'e', 'f') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::TypeDefKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent } - None => Some(TokenKind::ReturnKeyword), } - } else { - None - } - } - Some('v') => { - if self.version_is_at_least_0_8_4 { - scan_chars!(input, 'e', 'r', 't') - .then_some(TokenKind::RevertKeyword) - } else { - None + Some('o') => { + if scan_chars!(input, 'f') { + KeywordScan::Reserved(TokenKind::TypeOfKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Reserved(TokenKind::TypeKeyword) + } + None => KeywordScan::Reserved(TokenKind::TypeKeyword), } - } - Some(_) => { - input.undo(); - None - } - None => None, - } - } else { - None - } - } - Some('s') => match input.next() { - Some('e') => match input.next() { - Some('a') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'l', 'e', 'd') - .then_some(TokenKind::SealedKeyword) } else { - None + KeywordScan::Absent } } - Some('c') => scan_chars!(input, 'o', 'n', 'd', 's') - .then_some(TokenKind::SecondsKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('i') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'z', 'e', 'o', 'f') - .then_some(TokenKind::SizeOfKeyword) - } else { - None - } - } - Some('t') => { - match input.next() { - Some('a') => scan_chars!(input, 't', 'i', 'c') - .then_some(TokenKind::StaticKeyword), - Some('o') => scan_chars!(input, 'r', 'a', 'g', 'e') - .then_some(TokenKind::StorageKeyword), - Some('r') => match input.next() { - Some('i') => scan_chars!(input, 'n', 'g') - .then_some(TokenKind::StringKeyword), - Some('u') => scan_chars!(input, 'c', 't') - .then_some(TokenKind::StructKeyword), - Some(_) => { - input.undo(); - None + Some('u') => match input.next() { + Some('n') => { + if scan_chars!(input, 'c', 'h', 'e', 'c', 'k', 'e', 'd') { + if self.version_is_at_least_0_5_0 { + KeywordScan::Reserved(TokenKind::UncheckedKeyword) + } else if self.version_is_at_least_0_8_0 { + KeywordScan::Present(TokenKind::UncheckedKeyword) + } else { + KeywordScan::Absent } - None => None, - }, - Some(_) => { - input.undo(); - None + } else { + KeywordScan::Absent } - None => None, - } - } - Some('u') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'p', 'p', 'o', 'r', 't', 's') - .then_some(TokenKind::SupportsKeyword) - } else { - None } - } - Some('w') => scan_chars!(input, 'i', 't', 'c', 'h') - .then_some(TokenKind::SwitchKeyword), - Some('z') => { - if !self.version_is_at_least_0_7_0 { - scan_chars!(input, 'a', 'b', 'o').then_some(TokenKind::SzaboKeyword) - } else { - None + Some('s') => { + if scan_chars!(input, 'i', 'n', 'g') { + KeywordScan::Reserved(TokenKind::UsingKeyword) + } else { + KeywordScan::Absent + } } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('t') => match input.next() { - Some('h') => { - scan_chars!(input, 'r', 'o', 'w').then_some(TokenKind::ThrowKeyword) - } - Some('r') => match input.next() { - Some('u') => scan_chars!(input, 'e').then_some(TokenKind::TrueKeyword), - Some('y') => Some(TokenKind::TryKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('y') => { - if scan_chars!(input, 'p', 'e') { - match input.next() { - Some('d') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'e', 'f') - .then_some(TokenKind::TypeDefKeyword) + Some('v') => match input.next() { + Some('a') => { + if scan_chars!(input, 'r') { + KeywordScan::Reserved(TokenKind::VarKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => match input.next() { + Some('e') => { + if scan_chars!(input, 'w') { + KeywordScan::Reserved(TokenKind::ViewKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 't', 'u', 'a', 'l') { + if self.version_is_at_least_0_6_0 { + KeywordScan::Reserved(TokenKind::VirtualKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some('o') => { - scan_chars!(input, 'f').then_some(TokenKind::TypeOfKeyword) - } - Some(_) => { - input.undo(); - Some(TokenKind::TypeKeyword) - } - None => Some(TokenKind::TypeKeyword), } - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('u') => match input.next() { - Some('n') => { - if self.version_is_at_least_0_5_0 { - scan_chars!(input, 'c', 'h', 'e', 'c', 'k', 'e', 'd') - .then_some(TokenKind::UncheckedKeyword) - } else { - None - } - } - Some('s') => { - scan_chars!(input, 'i', 'n', 'g').then_some(TokenKind::UsingKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('v') => match input.next() { - Some('a') => scan_chars!(input, 'r').then_some(TokenKind::VarKeyword), - Some('i') => match input.next() { - Some('e') => scan_chars!(input, 'w').then_some(TokenKind::ViewKeyword), - Some('r') => { - if self.version_is_at_least_0_6_0 { - scan_chars!(input, 't', 'u', 'a', 'l') - .then_some(TokenKind::VirtualKeyword) - } else { - None + Some(_) => { + input.undo(); + KeywordScan::Absent } - } + None => KeywordScan::Absent, + }, Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('w') => match input.next() { - Some('e') => match input.next() { - Some('e') => { - scan_chars!(input, 'k', 's').then_some(TokenKind::WeeksKeyword) + Some('w') => match input.next() { + Some('e') => match input.next() { + Some('e') => { + if scan_chars!(input, 'k', 's') { + KeywordScan::Reserved(TokenKind::WeeksKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => KeywordScan::Reserved(TokenKind::WeiKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('h') => { + if scan_chars!(input, 'i', 'l', 'e') { + KeywordScan::Reserved(TokenKind::WhileKeyword) + } else { + KeywordScan::Absent + } } - Some('i') => Some(TokenKind::WeiKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('h') => { - scan_chars!(input, 'i', 'l', 'e').then_some(TokenKind::WhileKeyword) + Some('y') => { + if scan_chars!(input, 'e', 'a', 'r', 's') { + KeywordScan::Reserved(TokenKind::YearsKeyword) + } else { + KeywordScan::Absent + } } Some(_) => { input.undo(); - None + KeywordScan::Absent + } + None => KeywordScan::Absent, + }; + let kw_scan = match kw_scan { + // Strict prefix; we need to match the whole identifier to promote + _ if input.position() < furthest_position => KeywordScan::Absent, + value => value, + }; + + // Perf: only scan for a compound keyword if we didn't already find one + let mut kw_scan = kw_scan; + if kw_scan == KeywordScan::Absent { + input.set_position(save); + + // TODO: Don't allocate a string here + let ident_value = input.content(save.utf8..furthest_position.utf8); + + for keyword_compound_scanner in [ + Self::bytes_keyword, + Self::fixed_keyword, + Self::int_keyword, + Self::ufixed_keyword, + Self::uint_keyword, + ] { + match keyword_compound_scanner(self, input, &ident_value) { + _ if input.position() < furthest_position => { /* Strict prefix */ } + KeywordScan::Absent => {} + value => kw_scan = value, + } + input.set_position(save); } - None => None, - }, - Some('y') => { - scan_chars!(input, 'e', 'a', 'r', 's').then_some(TokenKind::YearsKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - } { - // Make sure that this is not the start of an identifier - if !self.identifier_part(input) { - furthest_position = input.position(); - longest_token = Some(kind); } - } - input.set_position(save); + input.set_position(furthest_position); + return Some(ScannedToken::IdentifierOrKeyword { + identifier, + kw: kw_scan, + }); + } + } + LexicalContext::Pragma => { if let Some(kind) = match input.next() { - Some('!') => match input.next() { - Some('=') => Some(TokenKind::BangEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Bang) - } - None => Some(TokenKind::Bang), - }, - Some('%') => match input.next() { - Some('=') => Some(TokenKind::PercentEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Percent) - } - None => Some(TokenKind::Percent), - }, - Some('&') => match input.next() { - Some('&') => Some(TokenKind::AmpersandAmpersand), - Some('=') => Some(TokenKind::AmpersandEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Ampersand) - } - None => Some(TokenKind::Ampersand), - }, - Some('(') => Some(TokenKind::OpenParen), - Some(')') => Some(TokenKind::CloseParen), - Some('*') => match input.next() { - Some('*') => Some(TokenKind::AsteriskAsterisk), - Some('=') => Some(TokenKind::AsteriskEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Asterisk) - } - None => Some(TokenKind::Asterisk), - }, - Some('+') => match input.next() { - Some('+') => Some(TokenKind::PlusPlus), - Some('=') => Some(TokenKind::PlusEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Plus) - } - None => Some(TokenKind::Plus), - }, - Some(',') => Some(TokenKind::Comma), - Some('-') => match input.next() { - Some('-') => Some(TokenKind::MinusMinus), - Some('=') => Some(TokenKind::MinusEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Minus) - } - None => Some(TokenKind::Minus), - }, + Some('-') => Some(TokenKind::Minus), Some('.') => Some(TokenKind::Period), - Some('/') => match input.next() { - Some('=') => Some(TokenKind::SlashEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Slash) - } - None => Some(TokenKind::Slash), - }, - Some(':') => Some(TokenKind::Colon), Some(';') => Some(TokenKind::Semicolon), Some('<') => match input.next() { - Some('<') => match input.next() { - Some('=') => Some(TokenKind::LessThanLessThanEqual), - Some(_) => { - input.undo(); - Some(TokenKind::LessThanLessThan) - } - None => Some(TokenKind::LessThanLessThan), - }, Some('=') => Some(TokenKind::LessThanEqual), Some(_) => { input.undo(); @@ -9364,63 +10044,23 @@ impl Lexer for Language { } None => Some(TokenKind::LessThan), }, - Some('=') => match input.next() { - Some('=') => Some(TokenKind::EqualEqual), - Some('>') => Some(TokenKind::EqualGreaterThan), - Some(_) => { - input.undo(); - Some(TokenKind::Equal) - } - None => Some(TokenKind::Equal), - }, + Some('=') => Some(TokenKind::Equal), Some('>') => match input.next() { Some('=') => Some(TokenKind::GreaterThanEqual), - Some('>') => match input.next() { - Some('=') => Some(TokenKind::GreaterThanGreaterThanEqual), - Some('>') => match input.next() { - Some('=') => { - Some(TokenKind::GreaterThanGreaterThanGreaterThanEqual) - } - Some(_) => { - input.undo(); - Some(TokenKind::GreaterThanGreaterThanGreaterThan) - } - None => Some(TokenKind::GreaterThanGreaterThanGreaterThan), - }, - Some(_) => { - input.undo(); - Some(TokenKind::GreaterThanGreaterThan) - } - None => Some(TokenKind::GreaterThanGreaterThan), - }, Some(_) => { input.undo(); Some(TokenKind::GreaterThan) } None => Some(TokenKind::GreaterThan), }, - Some('?') => Some(TokenKind::QuestionMark), - Some('[') => Some(TokenKind::OpenBracket), - Some(']') => Some(TokenKind::CloseBracket), - Some('^') => match input.next() { - Some('=') => Some(TokenKind::CaretEqual), - Some(_) => { - input.undo(); - Some(TokenKind::Caret) - } - None => Some(TokenKind::Caret), - }, - Some('{') => Some(TokenKind::OpenBrace), - Some('|') => match input.next() { - Some('=') => Some(TokenKind::BarEqual), - Some('|') => Some(TokenKind::BarBar), - Some(_) => { - input.undo(); - Some(TokenKind::Bar) + Some('^') => Some(TokenKind::Caret), + Some('|') => { + if scan_chars!(input, '|') { + Some(TokenKind::BarBar) + } else { + None } - None => Some(TokenKind::Bar), - }, - Some('}') => Some(TokenKind::CloseBrace), + } Some('~') => Some(TokenKind::Tilde), Some(_) => { input.undo(); @@ -9434,85 +10074,90 @@ impl Lexer for Language { input.set_position(save); longest_match! { - { AsciiStringLiteral = ascii_string_literal } - { BytesKeyword = bytes_keyword } - { DecimalLiteral = decimal_literal } - { EndOfLine = end_of_line } - { FixedKeyword = fixed_keyword } - { HexLiteral = hex_literal } - { HexStringLiteral = hex_string_literal } - { IntKeyword = int_keyword } - { MultilineComment = multiline_comment } - { SingleLineComment = single_line_comment } - { UfixedKeyword = ufixed_keyword } - { UintKeyword = uint_keyword } - { UnicodeStringLiteral = unicode_string_literal } - { Whitespace = whitespace } - { Identifier = identifier } + { AsciiStringLiteral = ascii_string_literal } + { VersionPragmaValue = version_pragma_value } } - } - LexicalContext::Pragma => { - macro_rules! longest_match { - ($( { $kind:ident = $function:ident } )*) => { - $( - if self.$function(input) && input.position() > furthest_position { - furthest_position = input.position(); - longest_token = Some(TokenKind::$kind); - } - input.set_position(save); - )* - }; - } - - if let Some(kind) = match input.next() { - Some('a') => scan_chars!(input, 'b', 'i', 'c', 'o', 'd', 'e', 'r') - .then_some(TokenKind::AbicoderKeyword), - Some('e') => { - scan_chars!(input, 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l') - .then_some(TokenKind::ExperimentalKeyword) - } - Some('p') => scan_chars!(input, 'r', 'a', 'g', 'm', 'a') - .then_some(TokenKind::PragmaKeyword), - Some('s') => scan_chars!(input, 'o', 'l', 'i', 'd', 'i', 't', 'y') - .then_some(TokenKind::SolidityKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - } { - // Make sure that this is not the start of an identifier - if !self.identifier_part(input) { - furthest_position = input.position(); - longest_token = Some(kind); - } + // Make sure promotable identifiers are last so they don't grab other things + longest_match! { + { Identifier = identifier } } - input.set_position(save); - if let Some(kind) = match input.next() { - Some('-') => Some(TokenKind::Minus), - Some('.') => Some(TokenKind::Period), - Some(';') => Some(TokenKind::Semicolon), - Some('<') => match input.next() { - Some('=') => Some(TokenKind::LessThanEqual), - Some(_) => { - input.undo(); - Some(TokenKind::LessThan) + // We have an identifier; we need to check if it's a keyword + if let Some(identifier) = + longest_token.filter(|tok| [TokenKind::Identifier].contains(tok)) + { + let kw_scan = match input.next() { + Some('a') => { + if scan_chars!(input, 'b', 'i', 'c', 'o', 'd', 'e', 'r') { + KeywordScan::Reserved(TokenKind::AbicoderKeyword) + } else { + KeywordScan::Absent + } + } + Some('e') => { + if scan_chars!( + input, 'x', 'p', 'e', 'r', 'i', 'm', 'e', 'n', 't', 'a', 'l' + ) { + KeywordScan::Reserved(TokenKind::ExperimentalKeyword) + } else { + KeywordScan::Absent + } + } + Some('p') => { + if scan_chars!(input, 'r', 'a', 'g', 'm', 'a') { + KeywordScan::Reserved(TokenKind::PragmaKeyword) + } else { + KeywordScan::Absent + } + } + Some('s') => { + if scan_chars!(input, 'o', 'l', 'i', 'd', 'i', 't', 'y') { + KeywordScan::Reserved(TokenKind::SolidityKeyword) + } else { + KeywordScan::Absent + } } - None => Some(TokenKind::LessThan), - }, - Some('=') => Some(TokenKind::Equal), - Some('>') => match input.next() { - Some('=') => Some(TokenKind::GreaterThanEqual), Some(_) => { input.undo(); - Some(TokenKind::GreaterThan) + KeywordScan::Absent } - None => Some(TokenKind::GreaterThan), - }, - Some('^') => Some(TokenKind::Caret), - Some('|') => scan_chars!(input, '|').then_some(TokenKind::BarBar), - Some('~') => Some(TokenKind::Tilde), + None => KeywordScan::Absent, + }; + let kw_scan = match kw_scan { + // Strict prefix; we need to match the whole identifier to promote + _ if input.position() < furthest_position => KeywordScan::Absent, + value => value, + }; + + input.set_position(furthest_position); + return Some(ScannedToken::IdentifierOrKeyword { + identifier, + kw: kw_scan, + }); + } + } + LexicalContext::Yul => { + if let Some(kind) = match input.next() { + Some('(') => Some(TokenKind::OpenParen), + Some(')') => Some(TokenKind::CloseParen), + Some(',') => Some(TokenKind::Comma), + Some('-') => { + if scan_chars!(input, '>') { + Some(TokenKind::MinusGreaterThan) + } else { + None + } + } + Some('.') => Some(TokenKind::Period), + Some(':') => { + if scan_chars!(input, '=') { + Some(TokenKind::ColonEqual) + } else { + None + } + } + Some('{') => Some(TokenKind::OpenBrace), + Some('}') => Some(TokenKind::CloseBrace), Some(_) => { input.undo(); None @@ -9525,1177 +10170,1537 @@ impl Lexer for Language { input.set_position(save); longest_match! { - { AsciiStringLiteral = ascii_string_literal } - { VersionPragmaValue = version_pragma_value } - { Identifier = identifier } + { AsciiStringLiteral = ascii_string_literal } + { HexStringLiteral = hex_string_literal } + { YulDecimalLiteral = yul_decimal_literal } + { YulHexLiteral = yul_hex_literal } + } + // Make sure promotable identifiers are last so they don't grab other things + longest_match! { + { YulIdentifier = yul_identifier } } - } - LexicalContext::Yul => { - macro_rules! longest_match { - ($( { $kind:ident = $function:ident } )*) => { - $( - if self.$function(input) && input.position() > furthest_position { - furthest_position = input.position(); - longest_token = Some(TokenKind::$kind); - } - input.set_position(save); - )* - }; - } - if let Some(kind) = match input.next() { - Some('a') => match input.next() { - Some('b') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 's', 't', 'r', 'a', 'c', 't') - .then_some(TokenKind::YulAbstractKeyword) - } else { - None + // We have an identifier; we need to check if it's a keyword + if let Some(identifier) = + longest_token.filter(|tok| [TokenKind::YulIdentifier].contains(tok)) + { + let kw_scan = match input.next() { + Some('a') => match input.next() { + Some('b') => { + if scan_chars!(input, 's', 't', 'r', 'a', 'c', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAbstractKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('d') => scan_chars!(input, 'd', 'r', 'e', 's', 's') - .then_some(TokenKind::YulAddressKeyword), - Some('f') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'e', 'r') - .then_some(TokenKind::YulAfterKeyword) - } else { - None + Some('d') => { + if scan_chars!(input, 'd', 'r', 'e', 's', 's') { + KeywordScan::Reserved(TokenKind::YulAddressKeyword) + } else { + KeywordScan::Absent + } } - } - Some('l') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 'a', 's') - .then_some(TokenKind::YulAliasKeyword) - } else { - None + Some('f') => { + if scan_chars!(input, 't', 'e', 'r') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAfterKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('n') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'o', 'n', 'y', 'm', 'o', 'u', 's') - .then_some(TokenKind::YulAnonymousKeyword) - } else { - None + Some('l') => { + if scan_chars!(input, 'i', 'a', 's') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulAliasKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('p') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'p', 'l', 'y') - .then_some(TokenKind::YulApplyKeyword) - } else { - None + Some('n') => { + if scan_chars!(input, 'o', 'n', 'y', 'm', 'o', 'u', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAnonymousKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('s') => match input.next() { - Some('s') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'm', 'b', 'l', 'y') - .then_some(TokenKind::YulAssemblyKeyword) + Some('p') => { + if scan_chars!(input, 'p', 'l', 'y') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulApplyKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('s') => match input.next() { + Some('s') => { + if scan_chars!(input, 'e', 'm', 'b', 'l', 'y') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAssemblyKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAsKeyword) + } else { + KeywordScan::Absent + } + } + None => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulAsKeyword) + } else { + KeywordScan::Absent + } + } + }, + Some('u') => { + if scan_chars!(input, 't', 'o') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulAutoKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulAsKeyword) + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('b') => match input.next() { + Some('o') => { + if scan_chars!(input, 'o', 'l') { + if !self.version_is_at_least_0_5_10 { + KeywordScan::Reserved(TokenKind::YulBoolKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - None => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulAsKeyword) + Some('r') => { + if scan_chars!(input, 'e', 'a', 'k') { + KeywordScan::Reserved(TokenKind::YulBreakKeyword) + } else { + KeywordScan::Absent + } + } + Some('y') => { + if scan_chars!(input, 't', 'e') { + KeywordScan::Reserved(TokenKind::YulByteKeyword) } else { - None + KeywordScan::Absent } } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, }, - Some('u') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'o').then_some(TokenKind::YulAutoKeyword) - } else { - None + Some('c') => match input.next() { + Some('a') => match input.next() { + Some('l') => { + if scan_chars!(input, 'l', 'd', 'a', 't', 'a') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulCallDataKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('s') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::YulCaseKeyword) + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'c', 'h') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulCatchKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => match input.next() { + Some('n') => match input.next() { + Some('s') => { + if scan_chars!(input, 't') { + match input.next() { + Some('a') => { + if scan_chars!(input, 'n', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulConstantKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'u', 'c', 't', 'o', 'r') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved( + TokenKind::YulConstructorKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } + } + Some('t') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n', 'u', 'e') { + KeywordScan::Reserved(TokenKind::YulContinueKeyword) + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'a', 'c', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulContractKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('p') => { + if scan_chars!(input, 'y', 'o', 'f') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulCopyOfKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('b') => match input.next() { - Some('o') => { - if !self.version_is_at_least_0_5_10 { - scan_chars!(input, 'o', 'l').then_some(TokenKind::YulBoolKeyword) - } else { - None + None => KeywordScan::Absent, + }, + Some('d') => match input.next() { + Some('a') => { + if scan_chars!(input, 'y', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulDaysKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('r') => { - scan_chars!(input, 'e', 'a', 'k').then_some(TokenKind::YulBreakKeyword) - } - Some('y') => { - scan_chars!(input, 't', 'e').then_some(TokenKind::YulByteKeyword) - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('c') => match input.next() { - Some('a') => match input.next() { + Some('e') => match input.next() { + Some('f') => match input.next() { + Some('a') => { + if scan_chars!(input, 'u', 'l', 't') { + KeywordScan::Reserved(TokenKind::YulDefaultKeyword) + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'n', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulDefineKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('l') => { + if scan_chars!(input, 'e', 't', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulDeleteKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('o') => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulDoKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('e') => match input.next() { Some('l') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'l', 'd', 'a', 't', 'a') - .then_some(TokenKind::YulCallDataKeyword) + if scan_chars!(input, 's', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulElseKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('s') => { - scan_chars!(input, 'e').then_some(TokenKind::YulCaseKeyword) + Some('m') => { + if scan_chars!(input, 'i', 't') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulEmitKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'u', 'm') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulEnumKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } Some('t') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'c', 'h') - .then_some(TokenKind::YulCatchKeyword) + if scan_chars!(input, 'h', 'e', 'r') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulEtherKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('v') => { + if scan_chars!(input, 'e', 'n', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulEventKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('x') => { + if scan_chars!(input, 't', 'e', 'r', 'n', 'a', 'l') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulExternalKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('o') => match input.next() { - Some('n') => match input.next() { - Some('s') => { - if scan_chars!(input, 't') { - match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'n', 't') - .then_some(TokenKind::YulConstantKeyword) - } else { - None - } - } - Some('r') => { - if self.version_is_at_least_0_5_0 + Some('f') => match input.next() { + Some('a') => { + if scan_chars!(input, 'l') { + match input.next() { + Some('l') => { + if scan_chars!(input, 'b', 'a', 'c', 'k') { + if self.version_is_at_least_0_6_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'u', 'c', 't', 'o', 'r') - .then_some(TokenKind::YulConstructorKeyword) + KeywordScan::Reserved( + TokenKind::YulFallbackKeyword, + ) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some(_) => { - input.undo(); - None + } + Some('s') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::YulFalseKeyword) + } else { + KeywordScan::Absent } - None => None, } - } else { - None + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, } + } else { + KeywordScan::Absent } - Some('t') => match input.next() { - Some('i') => scan_chars!(input, 'n', 'u', 'e') - .then_some(TokenKind::YulContinueKeyword), - Some('r') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'a', 'c', 't') - .then_some(TokenKind::YulContractKeyword) - } else { - None + } + Some('i') => { + if scan_chars!(input, 'n') { + match input.next() { + Some('a') => { + if scan_chars!(input, 'l') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulFinalKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } + Some('n') => { + if scan_chars!(input, 'e', 'y') { + if !self.version_is_at_least_0_7_0 { + KeywordScan::Reserved( + TokenKind::YulFinneyKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some(_) => { - input.undo(); - None + } else { + KeywordScan::Absent } - None => None, - }, - Some('p') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'y', 'o', 'f') - .then_some(TokenKind::YulCopyOfKeyword) + } + Some('o') => { + if scan_chars!(input, 'r') { + KeywordScan::Reserved(TokenKind::YulForKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'n', 'c', 't', 'i', 'o', 'n') { + KeywordScan::Reserved(TokenKind::YulFunctionKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('d') => match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'y', 's').then_some(TokenKind::YulDaysKeyword) + Some('g') => { + if scan_chars!(input, 'w', 'e', 'i') { + if self.version_is_at_least_0_7_0 && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulGweiKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('e') => match input.next() { - Some('f') => match input.next() { - Some('a') => scan_chars!(input, 'u', 'l', 't') - .then_some(TokenKind::YulDefaultKeyword), - Some('i') => { - if self.version_is_at_least_0_5_0 - && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'n', 'e') - .then_some(TokenKind::YulDefineKeyword) + Some('h') => match input.next() { + Some('e') => { + if scan_chars!(input, 'x') { + KeywordScan::Reserved(TokenKind::YulHexKeyword) + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'u', 'r', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulHoursKeyword) } else { - None + KeywordScan::Absent } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('l') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 't', 'e') - .then_some(TokenKind::YulDeleteKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('o') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulDoKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('e') => match input.next() { - Some('l') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 's', 'e').then_some(TokenKind::YulElseKeyword) - } else { - None - } - } - Some('m') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 't').then_some(TokenKind::YulEmitKeyword) - } else { - None - } - } - Some('n') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'u', 'm').then_some(TokenKind::YulEnumKeyword) - } else { - None - } - } - Some('t') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'h', 'e', 'r') - .then_some(TokenKind::YulEtherKeyword) - } else { - None - } - } - Some('v') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'n', 't') - .then_some(TokenKind::YulEventKeyword) - } else { - None - } - } - Some('x') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'e', 'r', 'n', 'a', 'l') - .then_some(TokenKind::YulExternalKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('f') => match input.next() { - Some('a') => { - if scan_chars!(input, 'l') { - match input.next() { - Some('l') => { - if self.version_is_at_least_0_6_0 + Some('i') => match input.next() { + Some('f') => KeywordScan::Reserved(TokenKind::YulIfKeyword), + Some('m') => match input.next() { + Some('m') => { + if scan_chars!(input, 'u', 't', 'a', 'b', 'l', 'e') { + if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'b', 'a', 'c', 'k') - .then_some(TokenKind::YulFallbackKeyword) + KeywordScan::Reserved(TokenKind::YulImmutableKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some('s') => scan_chars!(input, 'e') - .then_some(TokenKind::YulFalseKeyword), - Some(_) => { - input.undo(); - None - } - None => None, } - } else { - None - } - } - Some('i') => { - if scan_chars!(input, 'n') { - match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'l') - .then_some(TokenKind::YulFinalKeyword) + Some('p') => match input.next() { + Some('l') => { + if scan_chars!(input, 'e', 'm', 'e', 'n', 't', 's') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved( + TokenKind::YulImplementsKeyword, + ) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('n') => { - if !self.version_is_at_least_0_7_0 { - scan_chars!(input, 'e', 'y') - .then_some(TokenKind::YulFinneyKeyword) + Some('o') => { + if scan_chars!(input, 'r', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulImportKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent } - } else { - None - } - } - Some('o') => scan_chars!(input, 'r').then_some(TokenKind::YulForKeyword), - Some('u') => scan_chars!(input, 'n', 'c', 't', 'i', 'o', 'n') - .then_some(TokenKind::YulFunctionKeyword), - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('g') => { - if self.version_is_at_least_0_7_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'w', 'e', 'i').then_some(TokenKind::YulGweiKeyword) - } else { - None - } - } - Some('h') => match input.next() { - Some('e') => scan_chars!(input, 'x').then_some(TokenKind::YulHexKeyword), - Some('o') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'u', 'r', 's') - .then_some(TokenKind::YulHoursKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('i') => match input.next() { - Some('f') => Some(TokenKind::YulIfKeyword), - Some('m') => match input.next() { - Some('m') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'u', 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::YulImmutableKeyword) - } else { - None + None => KeywordScan::Absent, + }, + Some('n') => match input.next() { + Some('d') => { + if scan_chars!(input, 'e', 'x', 'e', 'd') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulIndexedKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('p') => match input.next() { Some('l') => { - if self.version_is_at_least_0_5_0 - && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'e', 'm', 'e', 'n', 't', 's') - .then_some(TokenKind::YulImplementsKeyword) + if scan_chars!(input, 'i', 'n', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulInlineKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('o') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'r', 't') - .then_some(TokenKind::YulImportKeyword) + Some('t') => { + if scan_chars!(input, 'e', 'r') { + match input.next() { + Some('f') => { + if scan_chars!(input, 'a', 'c', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulInterfaceKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('n') => { + if scan_chars!(input, 'a', 'l') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulInternalKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + if !self.version_is_at_least_0_6_8 { + KeywordScan::Reserved(TokenKind::YulInKeyword) + } else { + KeywordScan::Absent + } + } + None => { + if !self.version_is_at_least_0_6_8 { + KeywordScan::Reserved(TokenKind::YulInKeyword) + } else { + KeywordScan::Absent + } } - None => None, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('n') => match input.next() { - Some('d') => { + Some('s') => { if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'x', 'e', 'd') - .then_some(TokenKind::YulIndexedKeyword) + KeywordScan::Reserved(TokenKind::YulIsKeyword) } else { - None + KeywordScan::Absent } } - Some('l') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 'n', 'e') - .then_some(TokenKind::YulInlineKeyword) - } else { - None - } + Some(_) => { + input.undo(); + KeywordScan::Absent } - Some('t') => { - if scan_chars!(input, 'e', 'r') { - match input.next() { - Some('f') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'a', 'c', 'e') - .then_some(TokenKind::YulInterfaceKeyword) - } else { - None - } - } - Some('n') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'a', 'l') - .then_some(TokenKind::YulInternalKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None + None => KeywordScan::Absent, + }, + Some('l') => match input.next() { + Some('e') => match input.next() { + Some('a') => { + if scan_chars!(input, 'v', 'e') { + if self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulLeaveKeyword) + } else if self.version_is_at_least_0_6_0 { + KeywordScan::Present(TokenKind::YulLeaveKeyword) + } else { + KeywordScan::Absent } - None => None, + } else { + KeywordScan::Absent } - } else { - None - } - } - Some(_) => { - input.undo(); - if !self.version_is_at_least_0_6_8 { - Some(TokenKind::YulInKeyword) - } else { - None } - } - None => { - if !self.version_is_at_least_0_6_8 { - Some(TokenKind::YulInKeyword) - } else { - None + Some('t') => KeywordScan::Reserved(TokenKind::YulLetKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent } - } - }, - Some('s') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulIsKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('l') => match input.next() { - Some('e') => match input.next() { - Some('a') => { - if self.version_is_at_least_0_6_0 { - scan_chars!(input, 'v', 'e') - .then_some(TokenKind::YulLeaveKeyword) + None => KeywordScan::Absent, + }, + Some('i') => { + if scan_chars!(input, 'b', 'r', 'a', 'r', 'y') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulLibraryKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('t') => Some(TokenKind::YulLetKeyword), Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('i') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'b', 'r', 'a', 'r', 'y') - .then_some(TokenKind::YulLibraryKeyword) - } else { - None + Some('m') => match input.next() { + Some('a') => match input.next() { + Some('c') => { + if scan_chars!(input, 'r', 'o') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulMacroKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('p') => { + if scan_chars!(input, 'p', 'i', 'n', 'g') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulMappingKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'c', 'h') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulMatchKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('e') => { + if scan_chars!(input, 'm', 'o', 'r', 'y') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulMemoryKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('m') => match input.next() { - Some('a') => match input.next() { - Some('c') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'r', 'o') - .then_some(TokenKind::YulMacroKeyword) + Some('i') => { + if scan_chars!(input, 'n', 'u', 't', 'e', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulMinutesKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('p') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'p', 'i', 'n', 'g') - .then_some(TokenKind::YulMappingKeyword) + Some('o') => { + if scan_chars!(input, 'd', 'i', 'f', 'i', 'e', 'r') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulModifierKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('t') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'c', 'h') - .then_some(TokenKind::YulMatchKeyword) + Some('u') => { + if scan_chars!(input, 't', 'a', 'b', 'l', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulMutableKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('e') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'm', 'o', 'r', 'y') - .then_some(TokenKind::YulMemoryKeyword) - } else { - None - } - } - Some('i') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'n', 'u', 't', 'e', 's') - .then_some(TokenKind::YulMinutesKeyword) - } else { - None - } - } - Some('o') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'd', 'i', 'f', 'i', 'e', 'r') - .then_some(TokenKind::YulModifierKeyword) - } else { - None - } - } - Some('u') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::YulMutableKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('n') => match input.next() { - Some('e') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'w').then_some(TokenKind::YulNewKeyword) - } else { - None - } - } - Some('u') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'l', 'l').then_some(TokenKind::YulNullKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('o') => match input.next() { - Some('f') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulOfKeyword) - } else { - None - } - } - Some('v') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'r', 'r', 'i', 'd', 'e') - .then_some(TokenKind::YulOverrideKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('p') => match input.next() { - Some('a') => match input.next() { - Some('r') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 't', 'i', 'a', 'l') - .then_some(TokenKind::YulPartialKeyword) + Some('n') => match input.next() { + Some('e') => { + if scan_chars!(input, 'w') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulNewKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('y') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'a', 'b', 'l', 'e') - .then_some(TokenKind::YulPayableKeyword) + Some('u') => { + if scan_chars!(input, 'l', 'l') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulNullKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('r') => match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'g', 'm', 'a') - .then_some(TokenKind::YulPragmaKeyword) - } else { - None - } - } - Some('i') => { + Some('o') => match input.next() { + Some('f') => { if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'v', 'a', 't', 'e') - .then_some(TokenKind::YulPrivateKeyword) + KeywordScan::Reserved(TokenKind::YulOfKeyword) } else { - None + KeywordScan::Absent } } - Some('o') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'm', 'i', 's', 'e') - .then_some(TokenKind::YulPromiseKeyword) + Some('v') => { + if scan_chars!(input, 'e', 'r', 'r', 'i', 'd', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulOverrideKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('u') => match input.next() { - Some('b') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'l', 'i', 'c') - .then_some(TokenKind::YulPublicKeyword) - } else { - None + Some('p') => match input.next() { + Some('a') => match input.next() { + Some('r') => { + if scan_chars!(input, 't', 'i', 'a', 'l') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulPartialKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } - Some('r') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e').then_some(TokenKind::YulPureKeyword) - } else { - None + Some('y') => { + if scan_chars!(input, 'a', 'b', 'l', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPayableKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('r') => match input.next() { + Some('a') => { + if scan_chars!(input, 'g', 'm', 'a') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPragmaKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('i') => { + if scan_chars!(input, 'v', 'a', 't', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPrivateKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'm', 'i', 's', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulPromiseKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('u') => match input.next() { + Some('b') => { + if scan_chars!(input, 'l', 'i', 'c') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPublicKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('r') => { + if scan_chars!(input, 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulPureKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None + Some('r') => { + if scan_chars!(input, 'e') { + match input.next() { + Some('c') => { + if scan_chars!(input, 'e', 'i', 'v', 'e') { + if self.version_is_at_least_0_6_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulReceiveKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('f') => { + if scan_chars!(input, 'e', 'r', 'e', 'n', 'c', 'e') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved( + TokenKind::YulReferenceKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('l') => { + if scan_chars!( + input, 'o', 'c', 'a', 't', 'a', 'b', 'l', 'e' + ) { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulRelocatableKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('t') => { + if scan_chars!(input, 'u', 'r', 'n') { + match input.next() { + Some('s') => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulReturnsKeyword, + ) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Reserved( + TokenKind::YulReturnKeyword, + ) + } + None => KeywordScan::Reserved( + TokenKind::YulReturnKeyword, + ), + } + } else { + KeywordScan::Absent + } + } + Some('v') => { + if scan_chars!(input, 'e', 'r', 't') { + KeywordScan::Reserved(TokenKind::YulRevertKeyword) + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + } + } else { + KeywordScan::Absent + } } - None => None, - }, - Some('r') => { - if scan_chars!(input, 'e') { - match input.next() { + Some('s') => match input.next() { + Some('e') => match input.next() { + Some('a') => { + if scan_chars!(input, 'l', 'e', 'd') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulSealedKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } Some('c') => { - if self.version_is_at_least_0_6_0 + if scan_chars!(input, 'o', 'n', 'd', 's') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulSecondsKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('i') => { + if scan_chars!(input, 'z', 'e', 'o', 'f') { + if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'i', 'v', 'e') - .then_some(TokenKind::YulReceiveKeyword) + KeywordScan::Reserved(TokenKind::YulSizeOfKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some('f') => { - if self.version_is_at_least_0_5_0 - && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'e', 'r', 'e', 'n', 'c', 'e') - .then_some(TokenKind::YulReferenceKeyword) + } + Some('t') => match input.next() { + Some('a') => { + if scan_chars!(input, 't', 'i', 'c') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulStaticKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('l') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'o', 'c', 'a', 't', 'a', 'b', 'l', 'e') - .then_some(TokenKind::YulRelocatableKeyword) + Some('o') => { + if scan_chars!(input, 'r', 'a', 'g', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulStorageKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } - Some('t') => { - if scan_chars!(input, 'u', 'r', 'n') { - match input.next() { - Some('s') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulReturnsKeyword) - } else { - None - } + Some('r') => match input.next() { + Some('i') => { + if scan_chars!(input, 'n', 'g') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulStringKeyword) + } else { + KeywordScan::Absent } - Some(_) => { - input.undo(); - Some(TokenKind::YulReturnKeyword) + } else { + KeywordScan::Absent + } + } + Some('u') => { + if scan_chars!(input, 'c', 't') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulStructKeyword) + } else { + KeywordScan::Absent } - None => Some(TokenKind::YulReturnKeyword), + } else { + KeywordScan::Absent } - } else { - None } - } - Some('v') => scan_chars!(input, 'e', 'r', 't') - .then_some(TokenKind::YulRevertKeyword), + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, Some(_) => { input.undo(); - None + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('u') => { + if scan_chars!(input, 'p', 'p', 'o', 'r', 't', 's') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulSupportsKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent } - None => None, } - } else { - None - } - } - Some('s') => match input.next() { - Some('e') => match input.next() { - Some('a') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'l', 'e', 'd') - .then_some(TokenKind::YulSealedKeyword) + Some('w') => { + if scan_chars!(input, 'i', 't', 'c', 'h') { + KeywordScan::Reserved(TokenKind::YulSwitchKeyword) } else { - None + KeywordScan::Absent } } - Some('c') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'o', 'n', 'd', 's') - .then_some(TokenKind::YulSecondsKeyword) + Some('z') => { + if scan_chars!(input, 'a', 'b', 'o') { + if !self.version_is_at_least_0_7_0 { + KeywordScan::Reserved(TokenKind::YulSzaboKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('i') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'z', 'e', 'o', 'f') - .then_some(TokenKind::YulSizeOfKeyword) - } else { - None - } - } Some('t') => match input.next() { - Some('a') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 't', 'i', 'c') - .then_some(TokenKind::YulStaticKeyword) - } else { - None - } - } - Some('o') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'r', 'a', 'g', 'e') - .then_some(TokenKind::YulStorageKeyword) + Some('h') => { + if scan_chars!(input, 'r', 'o', 'w') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulThrowKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some('r') => match input.next() { - Some('i') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'n', 'g') - .then_some(TokenKind::YulStringKeyword) + Some('u') => { + if scan_chars!(input, 'e') { + KeywordScan::Reserved(TokenKind::YulTrueKeyword) } else { - None + KeywordScan::Absent } } - Some('u') => { + Some('y') => { if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'c', 't') - .then_some(TokenKind::YulStructKeyword) + KeywordScan::Reserved(TokenKind::YulTryKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, + Some('y') => { + if scan_chars!(input, 'p', 'e') { + match input.next() { + Some('d') => { + if scan_chars!(input, 'e', 'f') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved( + TokenKind::YulTypeDefKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some('o') => { + if scan_chars!(input, 'f') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved( + TokenKind::YulTypeOfKeyword, + ) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } + } + Some(_) => { + input.undo(); + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulTypeKeyword) + } else { + KeywordScan::Absent + } + } + None => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulTypeKeyword) + } else { + KeywordScan::Absent + } + } + } + } else { + KeywordScan::Absent + } + } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('u') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'p', 'p', 'o', 'r', 't', 's') - .then_some(TokenKind::YulSupportsKeyword) - } else { - None - } - } - Some('w') => scan_chars!(input, 'i', 't', 'c', 'h') - .then_some(TokenKind::YulSwitchKeyword), - Some('z') => { - if !self.version_is_at_least_0_7_0 { - scan_chars!(input, 'a', 'b', 'o') - .then_some(TokenKind::YulSzaboKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('t') => match input.next() { - Some('h') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'r', 'o', 'w') - .then_some(TokenKind::YulThrowKeyword) - } else { - None - } - } - Some('r') => match input.next() { - Some('u') => { - scan_chars!(input, 'e').then_some(TokenKind::YulTrueKeyword) + Some('u') => match input.next() { + Some('n') => { + if scan_chars!(input, 'c', 'h', 'e', 'c', 'k', 'e', 'd') { + if self.version_is_at_least_0_5_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulUncheckedKeyword) + } else { + KeywordScan::Absent + } + } else { + KeywordScan::Absent + } } - Some('y') => { - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulTryKeyword) + Some('s') => { + if scan_chars!(input, 'i', 'n', 'g') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulUsingKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some('y') => { - if scan_chars!(input, 'p', 'e') { - match input.next() { - Some('d') => { - if self.version_is_at_least_0_5_0 - && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 'e', 'f') - .then_some(TokenKind::YulTypeDefKeyword) - } else { - None - } + Some('v') => match input.next() { + Some('a') => { + if scan_chars!(input, 'r') { + if !self.version_is_at_least_0_6_5 { + KeywordScan::Reserved(TokenKind::YulVarKeyword) + } else { + KeywordScan::Absent } - Some('o') => { + } else { + KeywordScan::Absent + } + } + Some('i') => match input.next() { + Some('e') => { + if scan_chars!(input, 'w') { if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'f') - .then_some(TokenKind::YulTypeOfKeyword) + KeywordScan::Reserved(TokenKind::YulViewKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - Some(_) => { - input.undo(); - if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulTypeKeyword) + } + Some('r') => { + if scan_chars!(input, 't', 'u', 'a', 'l') { + if self.version_is_at_least_0_6_0 + && !self.version_is_at_least_0_7_1 + { + KeywordScan::Reserved(TokenKind::YulVirtualKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } - None => { + } + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('w') => match input.next() { + Some('e') => match input.next() { + Some('e') => { + if scan_chars!(input, 'k', 's') { if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulTypeKeyword) + KeywordScan::Reserved(TokenKind::YulWeeksKeyword) } else { - None + KeywordScan::Absent } + } else { + KeywordScan::Absent } } - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('u') => match input.next() { - Some('n') => { - if self.version_is_at_least_0_5_0 && !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'c', 'h', 'e', 'c', 'k', 'e', 'd') - .then_some(TokenKind::YulUncheckedKeyword) - } else { - None - } - } - Some('s') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 'n', 'g') - .then_some(TokenKind::YulUsingKeyword) - } else { - None - } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('v') => match input.next() { - Some('a') => { - if !self.version_is_at_least_0_6_5 { - scan_chars!(input, 'r').then_some(TokenKind::YulVarKeyword) - } else { - None - } - } - Some('i') => match input.next() { - Some('e') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'w').then_some(TokenKind::YulViewKeyword) - } else { - None + Some('i') => { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulWeiKeyword) + } else { + KeywordScan::Absent + } } - } - Some('r') => { - if self.version_is_at_least_0_6_0 && !self.version_is_at_least_0_7_1 - { - scan_chars!(input, 't', 'u', 'a', 'l') - .then_some(TokenKind::YulVirtualKeyword) + Some(_) => { + input.undo(); + KeywordScan::Absent + } + None => KeywordScan::Absent, + }, + Some('h') => { + if scan_chars!(input, 'i', 'l', 'e') { + if !self.version_is_at_least_0_7_1 { + KeywordScan::Reserved(TokenKind::YulWhileKeyword) + } else { + KeywordScan::Absent + } } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, + None => KeywordScan::Absent, }, - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('w') => match input.next() { - Some('e') => match input.next() { - Some('e') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'k', 's') - .then_some(TokenKind::YulWeeksKeyword) - } else { - None - } - } - Some('i') => { + Some('y') => { + if scan_chars!(input, 'e', 'a', 'r', 's') { if !self.version_is_at_least_0_7_1 { - Some(TokenKind::YulWeiKeyword) + KeywordScan::Reserved(TokenKind::YulYearsKeyword) } else { - None + KeywordScan::Absent } - } - Some(_) => { - input.undo(); - None - } - None => None, - }, - Some('h') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'i', 'l', 'e') - .then_some(TokenKind::YulWhileKeyword) } else { - None + KeywordScan::Absent } } Some(_) => { input.undo(); - None + KeywordScan::Absent } - None => None, - }, - Some('y') => { - if !self.version_is_at_least_0_7_1 { - scan_chars!(input, 'e', 'a', 'r', 's') - .then_some(TokenKind::YulYearsKeyword) - } else { - None + None => KeywordScan::Absent, + }; + let kw_scan = match kw_scan { + // Strict prefix; we need to match the whole identifier to promote + _ if input.position() < furthest_position => KeywordScan::Absent, + value => value, + }; + + // Perf: only scan for a compound keyword if we didn't already find one + let mut kw_scan = kw_scan; + if kw_scan == KeywordScan::Absent { + input.set_position(save); + + // TODO: Don't allocate a string here + let ident_value = input.content(save.utf8..furthest_position.utf8); + + for keyword_compound_scanner in [ + Self::yul_bytes_keyword, + Self::yul_fixed_keyword, + Self::yul_int_keyword, + Self::yul_ufixed_keyword, + Self::yul_uint_keyword, + ] { + match keyword_compound_scanner(self, input, &ident_value) { + _ if input.position() < furthest_position => { /* Strict prefix */ } + KeywordScan::Absent => {} + value => kw_scan = value, + } + input.set_position(save); } } - Some(_) => { - input.undo(); - None - } - None => None, - } { - // Make sure that this is not the start of an identifier - if !self.identifier_part(input) { - furthest_position = input.position(); - longest_token = Some(kind); - } - } - input.set_position(save); - - if let Some(kind) = match input.next() { - Some('(') => Some(TokenKind::OpenParen), - Some(')') => Some(TokenKind::CloseParen), - Some(',') => Some(TokenKind::Comma), - Some('-') => scan_chars!(input, '>').then_some(TokenKind::MinusGreaterThan), - Some('.') => Some(TokenKind::Period), - Some(':') => scan_chars!(input, '=').then_some(TokenKind::ColonEqual), - Some('{') => Some(TokenKind::OpenBrace), - Some('}') => Some(TokenKind::CloseBrace), - Some(_) => { - input.undo(); - None - } - None => None, - } { - furthest_position = input.position(); - longest_token = Some(kind); - } - input.set_position(save); - longest_match! { - { AsciiStringLiteral = ascii_string_literal } - { HexStringLiteral = hex_string_literal } - { YulBytesKeyword = yul_bytes_keyword } - { YulDecimalLiteral = yul_decimal_literal } - { YulFixedKeyword = yul_fixed_keyword } - { YulHexLiteral = yul_hex_literal } - { YulIdentifier = yul_identifier } - { YulIntKeyword = yul_int_keyword } - { YulUfixedKeyword = yul_ufixed_keyword } - { YulUintKeyword = yul_uint_keyword } + input.set_position(furthest_position); + return Some(ScannedToken::IdentifierOrKeyword { + identifier, + kw: kw_scan, + }); } } } match longest_token { - Some(..) => { + Some(token) => { input.set_position(furthest_position); - longest_token + Some(ScannedToken::Single(token)) } // Skip a character if possible and if we didn't recognize a token None if input.peek().is_some() => { let _ = input.next(); - Some(TokenKind::SKIPPED) + Some(ScannedToken::Single(TokenKind::SKIPPED)) } - // EOF None => None, } } diff --git a/crates/solidity/outputs/npm/crate/src/generated/lexer.rs b/crates/solidity/outputs/npm/crate/src/generated/lexer.rs index 24d119f45c..4cece5532e 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/lexer.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/lexer.rs @@ -4,13 +4,63 @@ use crate::cst::{self, NamedNode}; use crate::kinds::{IsLexicalContext, TokenKind}; use crate::support::{ParserContext, ParserResult}; +/// Whether a keyword has been scanned and if so, whether it is reserved (unusable as an identifier) +/// or not. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum KeywordScan { + /// The keyword is not present. + Absent, + /// The keyword is present, but is not reserved. + Present(TokenKind), + /// The keyword is present and is reserved. + Reserved(TokenKind), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ScannedToken { + Single(TokenKind), + IdentifierOrKeyword { + identifier: TokenKind, + kw: KeywordScan, + }, +} + +impl ScannedToken { + pub fn accepted_as(self, expected: TokenKind) -> bool { + match self { + Self::Single(kind) => kind == expected, + Self::IdentifierOrKeyword { identifier, kw } => match kw { + KeywordScan::Reserved(kind) => kind == expected, + KeywordScan::Present(kind) => kind == expected || identifier == expected, + KeywordScan::Absent => identifier == expected, + }, + } + } + + /// Returns the most general token kind that can be accepted for the scanned token. + /// + /// If the scanned token is an identifier, returns the specific keyword kind if the keyword is reserved, + /// otherwise returns the general identifier kind. For other tokens, returns the token kind itself. + pub fn unambiguous(self) -> TokenKind { + match self { + Self::Single(kind) => kind, + Self::IdentifierOrKeyword { identifier, kw } => match kw { + KeywordScan::Reserved(kind) => kind, + // Ambiguous; prefer using the more general identifier + KeywordScan::Present(..) => identifier, + KeywordScan::Absent => identifier, + }, + } + } +} + pub(crate) trait Lexer { // Generated by the templating engine #[doc(hidden)] fn next_token( &self, input: &mut ParserContext<'_>, - ) -> Option; + ) -> Option; // NOTE: These are context-insensitive #[doc(hidden)] fn leading_trivia(&self, input: &mut ParserContext<'_>) -> ParserResult; @@ -24,7 +74,7 @@ pub(crate) trait Lexer { fn peek_token( &self, input: &mut ParserContext<'_>, - ) -> Option { + ) -> Option { let start = input.position(); let token = self.next_token::(input); input.set_position(start); @@ -35,7 +85,7 @@ pub(crate) trait Lexer { fn peek_token_with_trivia( &self, input: &mut ParserContext<'_>, - ) -> Option { + ) -> Option { let start = input.position(); let _ = self.leading_trivia(input); @@ -52,7 +102,10 @@ pub(crate) trait Lexer { kind: TokenKind, ) -> ParserResult { let start = input.position(); - if self.next_token::(input) != Some(kind) { + if !self + .next_token::(input) + .is_some_and(|t| t.accepted_as(kind)) + { input.set_position(start); return ParserResult::no_match(vec![kind]); } @@ -84,7 +137,10 @@ pub(crate) trait Lexer { } let start = input.position(); - if self.next_token::(input) != Some(kind) { + if !self + .next_token::(input) + .is_some_and(|t| t.accepted_as(kind)) + { input.set_position(restore); return ParserResult::no_match(vec![kind]); } diff --git a/crates/solidity/outputs/npm/crate/src/generated/support/recovery.rs b/crates/solidity/outputs/npm/crate/src/generated/support/recovery.rs index d1f92a193a..d5976fff49 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/support/recovery.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/support/recovery.rs @@ -2,7 +2,7 @@ use crate::cst; use crate::kinds::{IsLexicalContext, TokenKind}; -use crate::lexer::Lexer; +use crate::lexer::{Lexer, ScannedToken}; use crate::parse_error::ParseError; use crate::support::context::ParserContext; use crate::support::parser_result::SkippedUntil; @@ -65,7 +65,10 @@ impl ParserResult { ParseResultKind::Incomplete, ), ParserResult::Match(result) - if lexer.peek_token_with_trivia::(input) != Some(expected) => + if lexer + .peek_token_with_trivia::(input) + .map(ScannedToken::unambiguous) + != Some(expected) => { (result.nodes, result.expected_tokens, ParseResultKind::Match) } @@ -131,7 +134,10 @@ pub(crate) fn skip_until_with_nested_delims( let mut local_delims = vec![]; loop { let save = input.position(); - match lexer.next_token::(input) { + match lexer + .next_token::(input) + .map(ScannedToken::unambiguous) + { // If we're not skipping past a local delimited group (delimiter stack is empty), // we can unwind on a token that's expected by us or by our ancestor. Some(token) diff --git a/crates/solidity/outputs/npm/crate/src/generated/support/scanner_macros.rs b/crates/solidity/outputs/npm/crate/src/generated/support/scanner_macros.rs index 03d7df5919..acc51fb266 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/support/scanner_macros.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/support/scanner_macros.rs @@ -68,6 +68,26 @@ macro_rules! scan_choice { }; } +#[allow(unused_macros)] +macro_rules! scan_keyword_choice { + ($stream:ident, $ident:ident, $($scanner:expr),*) => { + loop { + let save = $stream.position(); + $( + { + if let result @ (KeywordScan::Present(..) | KeywordScan::Reserved(..)) = ($scanner) { + if $ident.len() == $stream.position().utf8 - save.utf8 { + break result; + } + } + } + $stream.set_position(save); + )* + break KeywordScan::Absent; + } + }; +} + #[allow(unused_macros)] macro_rules! scan_zero_or_more { ($stream:ident, $scanner:expr) => { diff --git a/crates/solidity/outputs/npm/crate/src/generated/support/separated_helper.rs b/crates/solidity/outputs/npm/crate/src/generated/support/separated_helper.rs index b5c07d9c52..43b00a078c 100644 --- a/crates/solidity/outputs/npm/crate/src/generated/support/separated_helper.rs +++ b/crates/solidity/outputs/npm/crate/src/generated/support/separated_helper.rs @@ -26,7 +26,7 @@ impl SeparatedHelper { accum.extend(r#match.nodes); match lexer.peek_token_with_trivia::(input) { - Some(token) if token == separator => { + Some(scanned) if scanned.accepted_as(separator) => { match lexer .parse_token_with_trivia::(input, separator) .with_name(separator_field_name) diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..63872fd6c7 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.4.11-failure.yml @@ -0,0 +1,39 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Constructors introduced in 0.4.22 but `constructor` was usable as identifier until 0.5.0 │ 0..91 + 2 │ │ 92..92 + 3 │ contract Contract { │ 93..112 + 4 │ constructor() {} │ 113..130 + 5 │ function func() public { │ 131..159 + 6 │ uint256 constructor; │ 160..182 + 7 │ } │ 183..188 + 8 │ } │ 189..190 + +Errors: # 1 total + - > + Error: Expected ConstantKeyword or Identifier or InternalKeyword or OverrideKeyword or PrivateKeyword or PublicKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/input.sol:4:13] + │ + 4 │ ╭─▶ constructor() {} + ┆ ┆ + 7 │ ├─▶ } + │ │ + │ ╰─────────── Error occurred here. + ───╯ + +Tree: + - ContractDefinition: # 0..191 "// Constructors introduced in 0.4.22 but `construc..." + - LeadingTrivia: # 0..93 "// Constructors introduced in 0.4.22 but `construc..." + - SingleLineComment: "// Constructors introduced in 0.4.22 but `construc..." # 0..91 + - (contract_keyword) ContractKeyword: "contract" # 93..101 + - (name) Identifier: "Contract" # 102..110 + - (open_brace) OpenBrace: "{" # 111..112 + - (members) ContractMembers: # 113..125 "\tconstructor" + - (item) ContractMember: # 113..125 "\tconstructor" + - (variant) StateVariableDefinition: # 113..125 "\tconstructor" + - (type_name) TypeName: # 113..125 "\tconstructor" + - (variant) IdentifierPath: # 113..125 "\tconstructor" + - (item) Identifier: "constructor" # 114..125 + - SKIPPED: "() {}\n function func() public {\n\t\tuint256 const..." # 125..189 + - (close_brace) CloseBrace: "}" # 189..190 diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.4.22-success.yml b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.4.22-success.yml new file mode 100644 index 0000000000..4e506a1b6a --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.4.22-success.yml @@ -0,0 +1,56 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Constructors introduced in 0.4.22 but `constructor` was usable as identifier until 0.5.0 │ 0..91 + 2 │ │ 92..92 + 3 │ contract Contract { │ 93..112 + 4 │ constructor() {} │ 113..130 + 5 │ function func() public { │ 131..159 + 6 │ uint256 constructor; │ 160..182 + 7 │ } │ 183..188 + 8 │ } │ 189..190 + +Errors: [] + +Tree: + - ContractDefinition: # 0..191 "// Constructors introduced in 0.4.22 but `construc..." + - LeadingTrivia: # 0..93 "// Constructors introduced in 0.4.22 but `construc..." + - SingleLineComment: "// Constructors introduced in 0.4.22 but `construc..." # 0..91 + - (contract_keyword) ContractKeyword: "contract" # 93..101 + - (name) Identifier: "Contract" # 102..110 + - (open_brace) OpenBrace: "{" # 111..112 + - (members) ContractMembers: # 113..189 "\tconstructor() {}\n function func() public {\n\t\tu..." + - (item) ContractMember: # 113..131 "\tconstructor() {}\n" + - (variant) ConstructorDefinition: # 113..131 "\tconstructor() {}\n" + - (constructor_keyword) ConstructorKeyword: "constructor" # 114..125 + - (parameters) ParametersDeclaration: # 125..127 "()" + - (open_paren) OpenParen: "(" # 125..126 + - (close_paren) CloseParen: ")" # 126..127 + - (body) Block: # 127..131 " {}\n" + - (open_brace) OpenBrace: "{" # 128..129 + - (close_brace) CloseBrace: "}" # 129..130 + - (item) ContractMember: # 131..189 " function func() public {\n\t\tuint256 constructor..." + - (variant) FunctionDefinition: # 131..189 " function func() public {\n\t\tuint256 constructor..." + - (function_keyword) FunctionKeyword: "function" # 135..143 + - (name) FunctionName: # 143..148 " func" + - (variant) Identifier: "func" # 144..148 + - (parameters) ParametersDeclaration: # 148..150 "()" + - (open_paren) OpenParen: "(" # 148..149 + - (close_paren) CloseParen: ")" # 149..150 + - (attributes) FunctionAttributes: # 150..157 " public" + - (item) FunctionAttribute: # 150..157 " public" + - (variant) PublicKeyword: "public" # 151..157 + - (body) FunctionBody: # 157..189 " {\n\t\tuint256 constructor;\n }\n" + - (variant) Block: # 157..189 " {\n\t\tuint256 constructor;\n }\n" + - (open_brace) OpenBrace: "{" # 158..159 + - (statements) Statements: # 160..183 "\t\tuint256 constructor;\n" + - (item) Statement: # 160..183 "\t\tuint256 constructor;\n" + - (variant) VariableDeclarationStatement: # 160..183 "\t\tuint256 constructor;\n" + - (variable_type) VariableDeclarationType: # 160..169 "\t\tuint256" + - (variant) TypeName: # 160..169 "\t\tuint256" + - (variant) ElementaryType: # 160..169 "\t\tuint256" + - (variant) UintKeyword: "uint256" # 162..169 + - (name) Identifier: "constructor" # 170..181 + - (semicolon) Semicolon: ";" # 181..182 + - (close_brace) CloseBrace: "}" # 187..188 + - (close_brace) CloseBrace: "}" # 189..190 diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..16ff02bf71 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/generated/0.5.0-failure.yml @@ -0,0 +1,63 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Constructors introduced in 0.4.22 but `constructor` was usable as identifier until 0.5.0 │ 0..91 + 2 │ │ 92..92 + 3 │ contract Contract { │ 93..112 + 4 │ constructor() {} │ 113..130 + 5 │ function func() public { │ 131..159 + 6 │ uint256 constructor; │ 160..182 + 7 │ } │ 183..188 + 8 │ } │ 189..190 + +Errors: # 1 total + - > + Error: Expected Ampersand or AmpersandAmpersand or AmpersandEqual or Asterisk or AsteriskAsterisk or AsteriskEqual or BangEqual or Bar or BarBar or BarEqual or Caret or CaretEqual or Equal or EqualEqual or GreaterThan or GreaterThanEqual or GreaterThanGreaterThan or GreaterThanGreaterThanEqual or GreaterThanGreaterThanGreaterThan or GreaterThanGreaterThanGreaterThanEqual or LessThan or LessThanEqual or LessThanLessThan or LessThanLessThanEqual or Minus or MinusEqual or Percent or PercentEqual or Plus or PlusEqual or Semicolon or Slash or SlashEqual. + ╭─[crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/input.sol:6:11] + │ + 6 │ uint256 constructor; + │ ─────┬───── + │ ╰─────── Error occurred here. + ───╯ + +Tree: + - ContractDefinition: # 0..191 "// Constructors introduced in 0.4.22 but `construc..." + - LeadingTrivia: # 0..93 "// Constructors introduced in 0.4.22 but `construc..." + - SingleLineComment: "// Constructors introduced in 0.4.22 but `construc..." # 0..91 + - (contract_keyword) ContractKeyword: "contract" # 93..101 + - (name) Identifier: "Contract" # 102..110 + - (open_brace) OpenBrace: "{" # 111..112 + - (members) ContractMembers: # 113..189 "\tconstructor() {}\n function func() public {\n\t\tu..." + - (item) ContractMember: # 113..131 "\tconstructor() {}\n" + - (variant) ConstructorDefinition: # 113..131 "\tconstructor() {}\n" + - (constructor_keyword) ConstructorKeyword: "constructor" # 114..125 + - (parameters) ParametersDeclaration: # 125..127 "()" + - (open_paren) OpenParen: "(" # 125..126 + - (close_paren) CloseParen: ")" # 126..127 + - (body) Block: # 127..131 " {}\n" + - (open_brace) OpenBrace: "{" # 128..129 + - (close_brace) CloseBrace: "}" # 129..130 + - (item) ContractMember: # 131..189 " function func() public {\n\t\tuint256 constructor..." + - (variant) FunctionDefinition: # 131..189 " function func() public {\n\t\tuint256 constructor..." + - (function_keyword) FunctionKeyword: "function" # 135..143 + - (name) FunctionName: # 143..148 " func" + - (variant) Identifier: "func" # 144..148 + - (parameters) ParametersDeclaration: # 148..150 "()" + - (open_paren) OpenParen: "(" # 148..149 + - (close_paren) CloseParen: ")" # 149..150 + - (attributes) FunctionAttributes: # 150..157 " public" + - (item) FunctionAttribute: # 150..157 " public" + - (variant) PublicKeyword: "public" # 151..157 + - (body) FunctionBody: # 157..189 " {\n\t\tuint256 constructor;\n }\n" + - (variant) Block: # 157..189 " {\n\t\tuint256 constructor;\n }\n" + - (open_brace) OpenBrace: "{" # 158..159 + - (statements) Statements: # 160..183 "\t\tuint256 constructor;\n" + - (item) Statement: # 160..183 "\t\tuint256 constructor;\n" + - (variant) ExpressionStatement: # 160..183 "\t\tuint256 constructor;\n" + - (expression) Expression: # 160..169 "\t\tuint256" + - (variant) ElementaryType: # 160..169 "\t\tuint256" + - (variant) UintKeyword: "uint256" # 162..169 + - SKIPPED: "constructor" # 170..181 + - (semicolon) Semicolon: ";" # 181..182 + - (close_brace) CloseBrace: "}" # 187..188 + - (close_brace) CloseBrace: "}" # 189..190 diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/input.sol b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/input.sol new file mode 100644 index 0000000000..fdb562b6a8 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/constructor_contextual/input.sol @@ -0,0 +1,8 @@ +// Constructors introduced in 0.4.22 but `constructor` was usable as identifier until 0.5.0 + +contract Contract { + constructor() {} + function func() public { + uint256 constructor; + } +} diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..6bdeed23ef --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.4.11-failure.yml @@ -0,0 +1,75 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Emitting events introduced syntactically in 0.4.21 but `emit` was usable as identifier until 0.5.0 │ 0..101 + 2 │ │ 102..102 + 3 │ contract ClientReceipt { │ 103..127 + 4 │ event Deposit(); │ 128..148 + 5 │ function deposit() public payable { │ 149..188 + 6 │ uint256 emit; │ 189..210 + 7 │ emit Deposit(); │ 211..234 + 8 │ } │ 235..240 + 9 │ } │ 241..242 + +Errors: # 1 total + - > + Error: Expected Equal or Semicolon. + ╭─[crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/input.sol:7:21] + │ + 7 │ emit Deposit(); + │ ─┬ + │ ╰── Error occurred here. + ───╯ + +Tree: + - ContractDefinition: # 0..243 "// Emitting events introduced syntactically in 0.4..." + - LeadingTrivia: # 0..103 "// Emitting events introduced syntactically in 0.4..." + - SingleLineComment: "// Emitting events introduced syntactically in 0.4..." # 0..101 + - (contract_keyword) ContractKeyword: "contract" # 103..111 + - (name) Identifier: "ClientReceipt" # 112..125 + - (open_brace) OpenBrace: "{" # 126..127 + - (members) ContractMembers: # 128..241 " event Deposit();\n function deposit() public..." + - (item) ContractMember: # 128..149 " event Deposit();\n" + - (variant) EventDefinition: # 128..149 " event Deposit();\n" + - (event_keyword) EventKeyword: "event" # 132..137 + - (name) Identifier: "Deposit" # 138..145 + - (parameters) EventParametersDeclaration: # 145..147 "()" + - (open_paren) OpenParen: "(" # 145..146 + - (close_paren) CloseParen: ")" # 146..147 + - (semicolon) Semicolon: ";" # 147..148 + - (item) ContractMember: # 149..241 " function deposit() public payable {\n ui..." + - (variant) FunctionDefinition: # 149..241 " function deposit() public payable {\n ui..." + - (function_keyword) FunctionKeyword: "function" # 153..161 + - (name) FunctionName: # 161..169 " deposit" + - (variant) Identifier: "deposit" # 162..169 + - (parameters) ParametersDeclaration: # 169..171 "()" + - (open_paren) OpenParen: "(" # 169..170 + - (close_paren) CloseParen: ")" # 170..171 + - (attributes) FunctionAttributes: # 171..186 " public payable" + - (item) FunctionAttribute: # 171..178 " public" + - (variant) PublicKeyword: "public" # 172..178 + - (item) FunctionAttribute: # 178..186 " payable" + - (variant) PayableKeyword: "payable" # 179..186 + - (body) FunctionBody: # 186..241 " {\n uint256 emit;\n emit Deposit();\n ..." + - (variant) Block: # 186..241 " {\n uint256 emit;\n emit Deposit();\n ..." + - (open_brace) OpenBrace: "{" # 187..188 + - (statements) Statements: # 189..235 " uint256 emit;\n emit Deposit();\n" + - (item) Statement: # 189..211 " uint256 emit;\n" + - (variant) VariableDeclarationStatement: # 189..211 " uint256 emit;\n" + - (variable_type) VariableDeclarationType: # 189..204 " uint256" + - (variant) TypeName: # 189..204 " uint256" + - (variant) ElementaryType: # 189..204 " uint256" + - (variant) UintKeyword: "uint256" # 197..204 + - (name) Identifier: "emit" # 205..209 + - (semicolon) Semicolon: ";" # 209..210 + - (item) Statement: # 211..235 " emit Deposit();\n" + - (variant) VariableDeclarationStatement: # 211..235 " emit Deposit();\n" + - (variable_type) VariableDeclarationType: # 211..223 " emit" + - (variant) TypeName: # 211..223 " emit" + - (variant) IdentifierPath: # 211..223 " emit" + - (item) Identifier: "emit" # 219..223 + - (name) Identifier: "Deposit" # 224..231 + - SKIPPED: "()" # 231..233 + - (semicolon) Semicolon: ";" # 233..234 + - (close_brace) CloseBrace: "}" # 239..240 + - (close_brace) CloseBrace: "}" # 241..242 diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.4.21-success.yml b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.4.21-success.yml new file mode 100644 index 0000000000..a12dbd8c28 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.4.21-success.yml @@ -0,0 +1,68 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Emitting events introduced syntactically in 0.4.21 but `emit` was usable as identifier until 0.5.0 │ 0..101 + 2 │ │ 102..102 + 3 │ contract ClientReceipt { │ 103..127 + 4 │ event Deposit(); │ 128..148 + 5 │ function deposit() public payable { │ 149..188 + 6 │ uint256 emit; │ 189..210 + 7 │ emit Deposit(); │ 211..234 + 8 │ } │ 235..240 + 9 │ } │ 241..242 + +Errors: [] + +Tree: + - ContractDefinition: # 0..243 "// Emitting events introduced syntactically in 0.4..." + - LeadingTrivia: # 0..103 "// Emitting events introduced syntactically in 0.4..." + - SingleLineComment: "// Emitting events introduced syntactically in 0.4..." # 0..101 + - (contract_keyword) ContractKeyword: "contract" # 103..111 + - (name) Identifier: "ClientReceipt" # 112..125 + - (open_brace) OpenBrace: "{" # 126..127 + - (members) ContractMembers: # 128..241 " event Deposit();\n function deposit() public..." + - (item) ContractMember: # 128..149 " event Deposit();\n" + - (variant) EventDefinition: # 128..149 " event Deposit();\n" + - (event_keyword) EventKeyword: "event" # 132..137 + - (name) Identifier: "Deposit" # 138..145 + - (parameters) EventParametersDeclaration: # 145..147 "()" + - (open_paren) OpenParen: "(" # 145..146 + - (close_paren) CloseParen: ")" # 146..147 + - (semicolon) Semicolon: ";" # 147..148 + - (item) ContractMember: # 149..241 " function deposit() public payable {\n ui..." + - (variant) FunctionDefinition: # 149..241 " function deposit() public payable {\n ui..." + - (function_keyword) FunctionKeyword: "function" # 153..161 + - (name) FunctionName: # 161..169 " deposit" + - (variant) Identifier: "deposit" # 162..169 + - (parameters) ParametersDeclaration: # 169..171 "()" + - (open_paren) OpenParen: "(" # 169..170 + - (close_paren) CloseParen: ")" # 170..171 + - (attributes) FunctionAttributes: # 171..186 " public payable" + - (item) FunctionAttribute: # 171..178 " public" + - (variant) PublicKeyword: "public" # 172..178 + - (item) FunctionAttribute: # 178..186 " payable" + - (variant) PayableKeyword: "payable" # 179..186 + - (body) FunctionBody: # 186..241 " {\n uint256 emit;\n emit Deposit();\n ..." + - (variant) Block: # 186..241 " {\n uint256 emit;\n emit Deposit();\n ..." + - (open_brace) OpenBrace: "{" # 187..188 + - (statements) Statements: # 189..235 " uint256 emit;\n emit Deposit();\n" + - (item) Statement: # 189..211 " uint256 emit;\n" + - (variant) VariableDeclarationStatement: # 189..211 " uint256 emit;\n" + - (variable_type) VariableDeclarationType: # 189..204 " uint256" + - (variant) TypeName: # 189..204 " uint256" + - (variant) ElementaryType: # 189..204 " uint256" + - (variant) UintKeyword: "uint256" # 197..204 + - (name) Identifier: "emit" # 205..209 + - (semicolon) Semicolon: ";" # 209..210 + - (item) Statement: # 211..235 " emit Deposit();\n" + - (variant) EmitStatement: # 211..235 " emit Deposit();\n" + - (emit_keyword) EmitKeyword: "emit" # 219..223 + - (event) IdentifierPath: # 223..231 " Deposit" + - (item) Identifier: "Deposit" # 224..231 + - (arguments) ArgumentsDeclaration: # 231..233 "()" + - (variant) PositionalArgumentsDeclaration: # 231..233 "()" + - (open_paren) OpenParen: "(" # 231..232 + - (close_paren) CloseParen: ")" # 232..233 + - (semicolon) Semicolon: ";" # 233..234 + - (close_brace) CloseBrace: "}" # 239..240 + - (close_brace) CloseBrace: "}" # 241..242 diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..45c987e350 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/generated/0.5.0-failure.yml @@ -0,0 +1,75 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Emitting events introduced syntactically in 0.4.21 but `emit` was usable as identifier until 0.5.0 │ 0..101 + 2 │ │ 102..102 + 3 │ contract ClientReceipt { │ 103..127 + 4 │ event Deposit(); │ 128..148 + 5 │ function deposit() public payable { │ 149..188 + 6 │ uint256 emit; │ 189..210 + 7 │ emit Deposit(); │ 211..234 + 8 │ } │ 235..240 + 9 │ } │ 241..242 + +Errors: # 1 total + - > + Error: Expected Ampersand or AmpersandAmpersand or AmpersandEqual or Asterisk or AsteriskAsterisk or AsteriskEqual or BangEqual or Bar or BarBar or BarEqual or Caret or CaretEqual or Equal or EqualEqual or GreaterThan or GreaterThanEqual or GreaterThanGreaterThan or GreaterThanGreaterThanEqual or GreaterThanGreaterThanGreaterThan or GreaterThanGreaterThanGreaterThanEqual or LessThan or LessThanEqual or LessThanLessThan or LessThanLessThanEqual or Minus or MinusEqual or Percent or PercentEqual or Plus or PlusEqual or Semicolon or Slash or SlashEqual. + ╭─[crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/input.sol:6:17] + │ + 6 │ uint256 emit; + │ ──┬─ + │ ╰─── Error occurred here. + ───╯ + +Tree: + - ContractDefinition: # 0..243 "// Emitting events introduced syntactically in 0.4..." + - LeadingTrivia: # 0..103 "// Emitting events introduced syntactically in 0.4..." + - SingleLineComment: "// Emitting events introduced syntactically in 0.4..." # 0..101 + - (contract_keyword) ContractKeyword: "contract" # 103..111 + - (name) Identifier: "ClientReceipt" # 112..125 + - (open_brace) OpenBrace: "{" # 126..127 + - (members) ContractMembers: # 128..241 " event Deposit();\n function deposit() public..." + - (item) ContractMember: # 128..149 " event Deposit();\n" + - (variant) EventDefinition: # 128..149 " event Deposit();\n" + - (event_keyword) EventKeyword: "event" # 132..137 + - (name) Identifier: "Deposit" # 138..145 + - (parameters) EventParametersDeclaration: # 145..147 "()" + - (open_paren) OpenParen: "(" # 145..146 + - (close_paren) CloseParen: ")" # 146..147 + - (semicolon) Semicolon: ";" # 147..148 + - (item) ContractMember: # 149..241 " function deposit() public payable {\n ui..." + - (variant) FunctionDefinition: # 149..241 " function deposit() public payable {\n ui..." + - (function_keyword) FunctionKeyword: "function" # 153..161 + - (name) FunctionName: # 161..169 " deposit" + - (variant) Identifier: "deposit" # 162..169 + - (parameters) ParametersDeclaration: # 169..171 "()" + - (open_paren) OpenParen: "(" # 169..170 + - (close_paren) CloseParen: ")" # 170..171 + - (attributes) FunctionAttributes: # 171..186 " public payable" + - (item) FunctionAttribute: # 171..178 " public" + - (variant) PublicKeyword: "public" # 172..178 + - (item) FunctionAttribute: # 178..186 " payable" + - (variant) PayableKeyword: "payable" # 179..186 + - (body) FunctionBody: # 186..241 " {\n uint256 emit;\n emit Deposit();\n ..." + - (variant) Block: # 186..241 " {\n uint256 emit;\n emit Deposit();\n ..." + - (open_brace) OpenBrace: "{" # 187..188 + - (statements) Statements: # 189..235 " uint256 emit;\n emit Deposit();\n" + - (item) Statement: # 189..211 " uint256 emit;\n" + - (variant) ExpressionStatement: # 189..211 " uint256 emit;\n" + - (expression) Expression: # 189..204 " uint256" + - (variant) ElementaryType: # 189..204 " uint256" + - (variant) UintKeyword: "uint256" # 197..204 + - SKIPPED: "emit" # 205..209 + - (semicolon) Semicolon: ";" # 209..210 + - (item) Statement: # 211..235 " emit Deposit();\n" + - (variant) EmitStatement: # 211..235 " emit Deposit();\n" + - (emit_keyword) EmitKeyword: "emit" # 219..223 + - (event) IdentifierPath: # 223..231 " Deposit" + - (item) Identifier: "Deposit" # 224..231 + - (arguments) ArgumentsDeclaration: # 231..233 "()" + - (variant) PositionalArgumentsDeclaration: # 231..233 "()" + - (open_paren) OpenParen: "(" # 231..232 + - (close_paren) CloseParen: ")" # 232..233 + - (semicolon) Semicolon: ";" # 233..234 + - (close_brace) CloseBrace: "}" # 239..240 + - (close_brace) CloseBrace: "}" # 241..242 diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/input.sol b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/input.sol new file mode 100644 index 0000000000..20cee2e9e4 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/emit_contextual/input.sol @@ -0,0 +1,9 @@ +// Emitting events introduced syntactically in 0.4.21 but `emit` was usable as identifier until 0.5.0 + +contract ClientReceipt { + event Deposit(); + function deposit() public payable { + uint256 emit; + emit Deposit(); + } +} diff --git a/crates/solidity/testing/snapshots/cst_output/EventDefinition/transfer/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/EventDefinition/transfer/generated/0.4.11-failure.yml deleted file mode 100644 index 869dd0819a..0000000000 --- a/crates/solidity/testing/snapshots/cst_output/EventDefinition/transfer/generated/0.4.11-failure.yml +++ /dev/null @@ -1,31 +0,0 @@ -# This file is generated automatically by infrastructure scripts. Please don't edit by hand. - -Source: > - 1 │ event Transfer(address indexed from, address indexed to, uint256 value); │ 0..72 - -Errors: # 1 total - - > - Error: Expected CloseParen or Comma. - ╭─[crates/solidity/testing/snapshots/cst_output/EventDefinition/transfer/input.sol:1:32] - │ - 1 │ event Transfer(address indexed from, address indexed to, uint256 value); - │ ───────────────────┬─────────────────── - │ ╰───────────────────── Error occurred here. - ───╯ - -Tree: - - EventDefinition: # 0..73 "event Transfer(address indexed from, address index..." - - (event_keyword) EventKeyword: "event" # 0..5 - - (name) Identifier: "Transfer" # 6..14 - - (parameters) EventParametersDeclaration: # 14..71 "(address indexed from, address indexed to, uint256..." - - (open_paren) OpenParen: "(" # 14..15 - - (parameters) EventParameters: # 15..30 "address indexed" - - (item) EventParameter: # 15..30 "address indexed" - - (type_name) TypeName: # 15..22 "address" - - (variant) ElementaryType: # 15..22 "address" - - (variant) AddressType: # 15..22 "address" - - (address_keyword) AddressKeyword: "address" # 15..22 - - (indexed_keyword) IndexedKeyword: "indexed" # 23..30 - - SKIPPED: "from, address indexed to, uint256 value" # 31..70 - - (close_paren) CloseParen: ")" # 70..71 - - (semicolon) Semicolon: ";" # 71..72 diff --git a/crates/solidity/testing/snapshots/cst_output/EventDefinition/transfer/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/EventDefinition/transfer/generated/0.4.11-success.yml new file mode 100644 index 0000000000..a86081f031 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/EventDefinition/transfer/generated/0.4.11-success.yml @@ -0,0 +1,37 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ event Transfer(address indexed from, address indexed to, uint256 value); │ 0..72 + +Errors: [] + +Tree: + - EventDefinition: # 0..73 "event Transfer(address indexed from, address index..." + - (event_keyword) EventKeyword: "event" # 0..5 + - (name) Identifier: "Transfer" # 6..14 + - (parameters) EventParametersDeclaration: # 14..71 "(address indexed from, address indexed to, uint256..." + - (open_paren) OpenParen: "(" # 14..15 + - (parameters) EventParameters: # 15..70 "address indexed from, address indexed to, uint256 ..." + - (item) EventParameter: # 15..35 "address indexed from" + - (type_name) TypeName: # 15..22 "address" + - (variant) ElementaryType: # 15..22 "address" + - (variant) AddressType: # 15..22 "address" + - (address_keyword) AddressKeyword: "address" # 15..22 + - (indexed_keyword) IndexedKeyword: "indexed" # 23..30 + - (name) Identifier: "from" # 31..35 + - (separator) Comma: "," # 35..36 + - (item) EventParameter: # 36..55 " address indexed to" + - (type_name) TypeName: # 36..44 " address" + - (variant) ElementaryType: # 36..44 " address" + - (variant) AddressType: # 36..44 " address" + - (address_keyword) AddressKeyword: "address" # 37..44 + - (indexed_keyword) IndexedKeyword: "indexed" # 45..52 + - (name) Identifier: "to" # 53..55 + - (separator) Comma: "," # 55..56 + - (item) EventParameter: # 56..70 " uint256 value" + - (type_name) TypeName: # 56..64 " uint256" + - (variant) ElementaryType: # 56..64 " uint256" + - (variant) UintKeyword: "uint256" # 57..64 + - (name) Identifier: "value" # 65..70 + - (close_paren) CloseParen: ")" # 70..71 + - (semicolon) Semicolon: ";" # 71..72 diff --git a/crates/solidity/testing/snapshots/cst_output/Expression/keyword_constructor/generated/0.4.22-failure.yml b/crates/solidity/testing/snapshots/cst_output/Expression/keyword_constructor/generated/0.5.0-failure.yml similarity index 100% rename from crates/solidity/testing/snapshots/cst_output/Expression/keyword_constructor/generated/0.4.22-failure.yml rename to crates/solidity/testing/snapshots/cst_output/Expression/keyword_constructor/generated/0.5.0-failure.yml diff --git a/crates/solidity/testing/snapshots/cst_output/Expression/keyword_emit/generated/0.4.21-failure.yml b/crates/solidity/testing/snapshots/cst_output/Expression/keyword_emit/generated/0.5.0-failure.yml similarity index 100% rename from crates/solidity/testing/snapshots/cst_output/Expression/keyword_emit/generated/0.4.21-failure.yml rename to crates/solidity/testing/snapshots/cst_output/Expression/keyword_emit/generated/0.5.0-failure.yml diff --git a/crates/solidity/testing/snapshots/cst_output/Expression/keyword_ufixed/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/Expression/keyword_ufixed/generated/0.4.11-success.yml new file mode 100644 index 0000000000..2fa102cd8b --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/Expression/keyword_ufixed/generated/0.4.11-success.yml @@ -0,0 +1,11 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ ufixed │ 0..6 + +Errors: [] + +Tree: + - Expression: # 0..7 "ufixed\n" + - (variant) ElementaryType: # 0..7 "ufixed\n" + - (variant) UfixedKeyword: "ufixed" # 0..6 diff --git a/crates/solidity/testing/snapshots/cst_output/Expression/keyword_ufixed/input.sol b/crates/solidity/testing/snapshots/cst_output/Expression/keyword_ufixed/input.sol new file mode 100644 index 0000000000..26a87344ae --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/Expression/keyword_ufixed/input.sol @@ -0,0 +1 @@ +ufixed diff --git a/crates/solidity/testing/snapshots/cst_output/FunctionDefinition/from_contextual_keyword/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/FunctionDefinition/from_contextual_keyword/generated/0.4.11-success.yml similarity index 64% rename from crates/solidity/testing/snapshots/cst_output/FunctionDefinition/from_contextual_keyword/generated/0.4.11-failure.yml rename to crates/solidity/testing/snapshots/cst_output/FunctionDefinition/from_contextual_keyword/generated/0.4.11-success.yml index fce5c3f24b..21a0fd1d74 100644 --- a/crates/solidity/testing/snapshots/cst_output/FunctionDefinition/from_contextual_keyword/generated/0.4.11-failure.yml +++ b/crates/solidity/testing/snapshots/cst_output/FunctionDefinition/from_contextual_keyword/generated/0.4.11-success.yml @@ -3,15 +3,7 @@ Source: > 1 │ function transferFrom(address from, address to, uint256 amount) external returns (bool); │ 0..88 -Errors: # 1 total - - > - Error: Expected CloseParen or Comma. - ╭─[crates/solidity/testing/snapshots/cst_output/FunctionDefinition/from_contextual_keyword/input.sol:1:31] - │ - 1 │ function transferFrom(address from, address to, uint256 amount) external returns (bool); - │ ────────────────┬─────────────── - │ ╰───────────────── Error occurred here. - ───╯ +Errors: [] Tree: - FunctionDefinition: # 0..89 "function transferFrom(address from, address to, ui..." @@ -20,13 +12,26 @@ Tree: - (variant) Identifier: "transferFrom" # 9..21 - (parameters) ParametersDeclaration: # 21..63 "(address from, address to, uint256 amount)" - (open_paren) OpenParen: "(" # 21..22 - - (parameters) Parameters: # 22..29 "address" - - (item) Parameter: # 22..29 "address" + - (parameters) Parameters: # 22..62 "address from, address to, uint256 amount" + - (item) Parameter: # 22..34 "address from" - (type_name) TypeName: # 22..29 "address" - (variant) ElementaryType: # 22..29 "address" - (variant) AddressType: # 22..29 "address" - (address_keyword) AddressKeyword: "address" # 22..29 - - SKIPPED: "from, address to, uint256 amount" # 30..62 + - (name) Identifier: "from" # 30..34 + - (separator) Comma: "," # 34..35 + - (item) Parameter: # 35..46 " address to" + - (type_name) TypeName: # 35..43 " address" + - (variant) ElementaryType: # 35..43 " address" + - (variant) AddressType: # 35..43 " address" + - (address_keyword) AddressKeyword: "address" # 36..43 + - (name) Identifier: "to" # 44..46 + - (separator) Comma: "," # 46..47 + - (item) Parameter: # 47..62 " uint256 amount" + - (type_name) TypeName: # 47..55 " uint256" + - (variant) ElementaryType: # 47..55 " uint256" + - (variant) UintKeyword: "uint256" # 48..55 + - (name) Identifier: "amount" # 56..62 - (close_paren) CloseParen: ")" # 62..63 - (attributes) FunctionAttributes: # 63..72 " external" - (item) FunctionAttribute: # 63..72 " external" diff --git a/crates/solidity/testing/snapshots/cst_output/Statements/contextual_keywords/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/Statements/contextual_keywords/generated/0.4.11-success.yml new file mode 100644 index 0000000000..e475faa573 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/Statements/contextual_keywords/generated/0.4.11-success.yml @@ -0,0 +1,44 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint256 error; │ 0..14 + 2 │ uint256 from; │ 15..28 + 3 │ uint256 revert; │ 29..44 + 4 │ uint256 global; │ 45..60 + +Errors: [] + +Tree: + - Statements: # 0..61 "uint256 error;\nuint256 from;\nuint256 revert;\nuint2..." + - (item) Statement: # 0..15 "uint256 error;\n" + - (variant) VariableDeclarationStatement: # 0..15 "uint256 error;\n" + - (variable_type) VariableDeclarationType: # 0..7 "uint256" + - (variant) TypeName: # 0..7 "uint256" + - (variant) ElementaryType: # 0..7 "uint256" + - (variant) UintKeyword: "uint256" # 0..7 + - (name) Identifier: "error" # 8..13 + - (semicolon) Semicolon: ";" # 13..14 + - (item) Statement: # 15..29 "uint256 from;\n" + - (variant) VariableDeclarationStatement: # 15..29 "uint256 from;\n" + - (variable_type) VariableDeclarationType: # 15..22 "uint256" + - (variant) TypeName: # 15..22 "uint256" + - (variant) ElementaryType: # 15..22 "uint256" + - (variant) UintKeyword: "uint256" # 15..22 + - (name) Identifier: "from" # 23..27 + - (semicolon) Semicolon: ";" # 27..28 + - (item) Statement: # 29..45 "uint256 revert;\n" + - (variant) VariableDeclarationStatement: # 29..45 "uint256 revert;\n" + - (variable_type) VariableDeclarationType: # 29..36 "uint256" + - (variant) TypeName: # 29..36 "uint256" + - (variant) ElementaryType: # 29..36 "uint256" + - (variant) UintKeyword: "uint256" # 29..36 + - (name) Identifier: "revert" # 37..43 + - (semicolon) Semicolon: ";" # 43..44 + - (item) Statement: # 45..61 "uint256 global;\n" + - (variant) VariableDeclarationStatement: # 45..61 "uint256 global;\n" + - (variable_type) VariableDeclarationType: # 45..52 "uint256" + - (variant) TypeName: # 45..52 "uint256" + - (variant) ElementaryType: # 45..52 "uint256" + - (variant) UintKeyword: "uint256" # 45..52 + - (name) Identifier: "global" # 53..59 + - (semicolon) Semicolon: ";" # 59..60 diff --git a/crates/solidity/testing/snapshots/cst_output/Statements/contextual_keywords/input.sol b/crates/solidity/testing/snapshots/cst_output/Statements/contextual_keywords/input.sol new file mode 100644 index 0000000000..a2e00bad60 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/Statements/contextual_keywords/input.sol @@ -0,0 +1,4 @@ +uint256 error; +uint256 from; +uint256 revert; +uint256 global; diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..7511b84a16 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/generated/0.4.11-failure.yml @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint bytes; │ 0..11 + +Errors: # 1 total + - > + Error: Expected Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/input.sol:1:6] + │ + 1 │ uint bytes; + │ ──┬── + │ ╰──── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..12 "uint bytes;\n" + - (variable_type) VariableDeclarationType: # 0..4 "uint" + - (variant) TypeName: # 0..4 "uint" + - (variant) ElementaryType: # 0..4 "uint" + - (variant) UintKeyword: "uint" # 0..4 + - SKIPPED: "bytes" # 5..10 + - (semicolon) Semicolon: ";" # 10..11 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..b854173800 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/generated/0.5.0-failure.yml @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint bytes; │ 0..11 + +Errors: # 1 total + - > + Error: Expected CallDataKeyword or Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/input.sol:1:6] + │ + 1 │ uint bytes; + │ ──┬── + │ ╰──── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..12 "uint bytes;\n" + - (variable_type) VariableDeclarationType: # 0..4 "uint" + - (variant) TypeName: # 0..4 "uint" + - (variant) ElementaryType: # 0..4 "uint" + - (variant) UintKeyword: "uint" # 0..4 + - SKIPPED: "bytes" # 5..10 + - (semicolon) Semicolon: ";" # 10..11 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/input.sol b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/input.sol new file mode 100644 index 0000000000..2823fbe3e8 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes/input.sol @@ -0,0 +1 @@ +uint bytes; diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..551aa9718e --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/generated/0.4.11-failure.yml @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint bytes1; │ 0..12 + +Errors: # 1 total + - > + Error: Expected Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/input.sol:1:6] + │ + 1 │ uint bytes1; + │ ───┬── + │ ╰──── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..13 "uint bytes1;\n" + - (variable_type) VariableDeclarationType: # 0..4 "uint" + - (variant) TypeName: # 0..4 "uint" + - (variant) ElementaryType: # 0..4 "uint" + - (variant) UintKeyword: "uint" # 0..4 + - SKIPPED: "bytes1" # 5..11 + - (semicolon) Semicolon: ";" # 11..12 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..4ff55f5118 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/generated/0.5.0-failure.yml @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint bytes1; │ 0..12 + +Errors: # 1 total + - > + Error: Expected CallDataKeyword or Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/input.sol:1:6] + │ + 1 │ uint bytes1; + │ ───┬── + │ ╰──── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..13 "uint bytes1;\n" + - (variable_type) VariableDeclarationType: # 0..4 "uint" + - (variant) TypeName: # 0..4 "uint" + - (variant) ElementaryType: # 0..4 "uint" + - (variant) UintKeyword: "uint" # 0..4 + - SKIPPED: "bytes1" # 5..11 + - (semicolon) Semicolon: ";" # 11..12 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/input.sol b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/input.sol new file mode 100644 index 0000000000..c2c1cfc72f --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes1/input.sol @@ -0,0 +1 @@ +uint bytes1; diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..9fe2dcdc4b --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/generated/0.4.11-failure.yml @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint bytes11; │ 0..13 + +Errors: # 1 total + - > + Error: Expected Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/input.sol:1:6] + │ + 1 │ uint bytes11; + │ ───┬─── + │ ╰───── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..14 "uint bytes11;\n" + - (variable_type) VariableDeclarationType: # 0..4 "uint" + - (variant) TypeName: # 0..4 "uint" + - (variant) ElementaryType: # 0..4 "uint" + - (variant) UintKeyword: "uint" # 0..4 + - SKIPPED: "bytes11" # 5..12 + - (semicolon) Semicolon: ";" # 12..13 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..5fa50d4b4b --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/generated/0.5.0-failure.yml @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint bytes11; │ 0..13 + +Errors: # 1 total + - > + Error: Expected CallDataKeyword or Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/input.sol:1:6] + │ + 1 │ uint bytes11; + │ ───┬─── + │ ╰───── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..14 "uint bytes11;\n" + - (variable_type) VariableDeclarationType: # 0..4 "uint" + - (variant) TypeName: # 0..4 "uint" + - (variant) ElementaryType: # 0..4 "uint" + - (variant) UintKeyword: "uint" # 0..4 + - SKIPPED: "bytes11" # 5..12 + - (semicolon) Semicolon: ";" # 12..13 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/input.sol b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/input.sol new file mode 100644 index 0000000000..3bc796b553 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_bytes11/input.sol @@ -0,0 +1 @@ +uint bytes11; diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..bc251090c4 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/generated/0.4.11-failure.yml @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint ufixed; │ 0..12 + +Errors: # 1 total + - > + Error: Expected Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/input.sol:1:6] + │ + 1 │ uint ufixed; + │ ───┬── + │ ╰──── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..13 "uint ufixed;\n" + - (variable_type) VariableDeclarationType: # 0..4 "uint" + - (variant) TypeName: # 0..4 "uint" + - (variant) ElementaryType: # 0..4 "uint" + - (variant) UintKeyword: "uint" # 0..4 + - SKIPPED: "ufixed" # 5..11 + - (semicolon) Semicolon: ";" # 11..12 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..5c92d2d849 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/generated/0.5.0-failure.yml @@ -0,0 +1,23 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ uint ufixed; │ 0..12 + +Errors: # 1 total + - > + Error: Expected CallDataKeyword or Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/input.sol:1:6] + │ + 1 │ uint ufixed; + │ ───┬── + │ ╰──── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..13 "uint ufixed;\n" + - (variable_type) VariableDeclarationType: # 0..4 "uint" + - (variant) TypeName: # 0..4 "uint" + - (variant) ElementaryType: # 0..4 "uint" + - (variant) UintKeyword: "uint" # 0..4 + - SKIPPED: "ufixed" # 5..11 + - (semicolon) Semicolon: ";" # 11..12 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/input.sol b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/input.sol new file mode 100644 index 0000000000..d24828ea4d --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed/input.sol @@ -0,0 +1 @@ +uint ufixed; diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.11-success.yml new file mode 100644 index 0000000000..d7ca136499 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.11-success.yml @@ -0,0 +1,18 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is only reserved since 0.4.14: │ 0..43 + 2 │ uint ufixed184x80; │ 44..62 + +Errors: [] + +Tree: + - VariableDeclarationStatement: # 0..63 "// This form is only reserved since 0.4.14:\nuint u..." + - (variable_type) VariableDeclarationType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) TypeName: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) ElementaryType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - LeadingTrivia: # 0..44 "// This form is only reserved since 0.4.14:\n" + - SingleLineComment: "// This form is only reserved since 0.4.14:" # 0..43 + - (variant) UintKeyword: "uint" # 44..48 + - (name) Identifier: "ufixed184x80" # 49..61 + - (semicolon) Semicolon: ";" # 61..62 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.14-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.14-failure.yml new file mode 100644 index 0000000000..6d9f7b890e --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.14-failure.yml @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is only reserved since 0.4.14: │ 0..43 + 2 │ uint ufixed184x80; │ 44..62 + +Errors: # 1 total + - > + Error: Expected Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/input.sol:2:6] + │ + 2 │ uint ufixed184x80; + │ ──────┬───── + │ ╰─────── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..63 "// This form is only reserved since 0.4.14:\nuint u..." + - (variable_type) VariableDeclarationType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) TypeName: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) ElementaryType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - LeadingTrivia: # 0..44 "// This form is only reserved since 0.4.14:\n" + - SingleLineComment: "// This form is only reserved since 0.4.14:" # 0..43 + - (variant) UintKeyword: "uint" # 44..48 + - SKIPPED: "ufixed184x80" # 49..61 + - (semicolon) Semicolon: ";" # 61..62 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..589bd7f397 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/generated/0.5.0-failure.yml @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is only reserved since 0.4.14: │ 0..43 + 2 │ uint ufixed184x80; │ 44..62 + +Errors: # 1 total + - > + Error: Expected CallDataKeyword or Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/input.sol:2:6] + │ + 2 │ uint ufixed184x80; + │ ──────┬───── + │ ╰─────── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..63 "// This form is only reserved since 0.4.14:\nuint u..." + - (variable_type) VariableDeclarationType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) TypeName: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) ElementaryType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - LeadingTrivia: # 0..44 "// This form is only reserved since 0.4.14:\n" + - SingleLineComment: "// This form is only reserved since 0.4.14:" # 0..43 + - (variant) UintKeyword: "uint" # 44..48 + - SKIPPED: "ufixed184x80" # 49..61 + - (semicolon) Semicolon: ";" # 61..62 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/input.sol b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/input.sol new file mode 100644 index 0000000000..41f366ffe7 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed184x80/input.sol @@ -0,0 +1,2 @@ +// This form is only reserved since 0.4.14: +uint ufixed184x80; diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.11-success.yml new file mode 100644 index 0000000000..959a444188 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.11-success.yml @@ -0,0 +1,18 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is only reserved since 0.4.14: │ 0..43 + 2 │ uint ufixed8x0; │ 44..59 + +Errors: [] + +Tree: + - VariableDeclarationStatement: # 0..60 "// This form is only reserved since 0.4.14:\nuint u..." + - (variable_type) VariableDeclarationType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) TypeName: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) ElementaryType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - LeadingTrivia: # 0..44 "// This form is only reserved since 0.4.14:\n" + - SingleLineComment: "// This form is only reserved since 0.4.14:" # 0..43 + - (variant) UintKeyword: "uint" # 44..48 + - (name) Identifier: "ufixed8x0" # 49..58 + - (semicolon) Semicolon: ";" # 58..59 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.14-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.14-failure.yml new file mode 100644 index 0000000000..eecdc12ae1 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.14-failure.yml @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is only reserved since 0.4.14: │ 0..43 + 2 │ uint ufixed8x0; │ 44..59 + +Errors: # 1 total + - > + Error: Expected Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/input.sol:2:6] + │ + 2 │ uint ufixed8x0; + │ ────┬──── + │ ╰────── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..60 "// This form is only reserved since 0.4.14:\nuint u..." + - (variable_type) VariableDeclarationType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) TypeName: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) ElementaryType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - LeadingTrivia: # 0..44 "// This form is only reserved since 0.4.14:\n" + - SingleLineComment: "// This form is only reserved since 0.4.14:" # 0..43 + - (variant) UintKeyword: "uint" # 44..48 + - SKIPPED: "ufixed8x0" # 49..58 + - (semicolon) Semicolon: ";" # 58..59 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..e5c8fbf8a7 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/generated/0.5.0-failure.yml @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is only reserved since 0.4.14: │ 0..43 + 2 │ uint ufixed8x0; │ 44..59 + +Errors: # 1 total + - > + Error: Expected CallDataKeyword or Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/input.sol:2:6] + │ + 2 │ uint ufixed8x0; + │ ────┬──── + │ ╰────── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..60 "// This form is only reserved since 0.4.14:\nuint u..." + - (variable_type) VariableDeclarationType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) TypeName: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - (variant) ElementaryType: # 0..48 "// This form is only reserved since 0.4.14:\nuint" + - LeadingTrivia: # 0..44 "// This form is only reserved since 0.4.14:\n" + - SingleLineComment: "// This form is only reserved since 0.4.14:" # 0..43 + - (variant) UintKeyword: "uint" # 44..48 + - SKIPPED: "ufixed8x0" # 49..58 + - (semicolon) Semicolon: ";" # 58..59 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/input.sol b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/input.sol new file mode 100644 index 0000000000..1945914947 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x0/input.sol @@ -0,0 +1,2 @@ +// This form is only reserved since 0.4.14: +uint ufixed8x0; diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..cb83f6429a --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/generated/0.4.11-failure.yml @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is always reserved: │ 0..32 + 2 │ uint ufixed8x8; │ 33..48 + +Errors: # 1 total + - > + Error: Expected Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/input.sol:2:6] + │ + 2 │ uint ufixed8x8; + │ ────┬──── + │ ╰────── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..49 "// This form is always reserved:\nuint ufixed8x8;\n" + - (variable_type) VariableDeclarationType: # 0..37 "// This form is always reserved:\nuint" + - (variant) TypeName: # 0..37 "// This form is always reserved:\nuint" + - (variant) ElementaryType: # 0..37 "// This form is always reserved:\nuint" + - LeadingTrivia: # 0..33 "// This form is always reserved:\n" + - SingleLineComment: "// This form is always reserved:" # 0..32 + - (variant) UintKeyword: "uint" # 33..37 + - SKIPPED: "ufixed8x8" # 38..47 + - (semicolon) Semicolon: ";" # 47..48 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/generated/0.5.0-failure.yml b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/generated/0.5.0-failure.yml new file mode 100644 index 0000000000..a58eaaf28a --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/generated/0.5.0-failure.yml @@ -0,0 +1,26 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is always reserved: │ 0..32 + 2 │ uint ufixed8x8; │ 33..48 + +Errors: # 1 total + - > + Error: Expected CallDataKeyword or Identifier or MemoryKeyword or StorageKeyword. + ╭─[crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/input.sol:2:6] + │ + 2 │ uint ufixed8x8; + │ ────┬──── + │ ╰────── Error occurred here. + ───╯ + +Tree: + - VariableDeclarationStatement: # 0..49 "// This form is always reserved:\nuint ufixed8x8;\n" + - (variable_type) VariableDeclarationType: # 0..37 "// This form is always reserved:\nuint" + - (variant) TypeName: # 0..37 "// This form is always reserved:\nuint" + - (variant) ElementaryType: # 0..37 "// This form is always reserved:\nuint" + - LeadingTrivia: # 0..33 "// This form is always reserved:\n" + - SingleLineComment: "// This form is always reserved:" # 0..32 + - (variant) UintKeyword: "uint" # 33..37 + - SKIPPED: "ufixed8x8" # 38..47 + - (semicolon) Semicolon: ";" # 47..48 diff --git a/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/input.sol b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/input.sol new file mode 100644 index 0000000000..84036c0c47 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/VariableDeclarationStatement/keyword_ufixed8x8/input.sol @@ -0,0 +1,2 @@ +// This form is always reserved: +uint ufixed8x8; diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..eb1cf6adde --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/generated/0.4.11-failure.yml @@ -0,0 +1,22 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Unreserved in Yul specifically since 0.7.1: │ 0..46 + 2 │ let bytes │ 47..56 + +Errors: # 1 total + - > + Error: Expected YulIdentifier. + ╭─[crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/input.sol:2:4] + │ + 2 │ let bytes + │ ───┬─── + │ ╰───── Error occurred here. + ───╯ + +Tree: + - YulVariableDeclarationStatement: # 0..57 "// Unreserved in Yul specifically since 0.7.1:\nlet..." + - LeadingTrivia: # 0..47 "// Unreserved in Yul specifically since 0.7.1:\n" + - SingleLineComment: "// Unreserved in Yul specifically since 0.7.1:" # 0..46 + - (let_keyword) YulLetKeyword: "let" # 47..50 + - SKIPPED: " bytes\n" # 50..57 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/generated/0.7.1-success.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/generated/0.7.1-success.yml new file mode 100644 index 0000000000..5add6e9e18 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/generated/0.7.1-success.yml @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Unreserved in Yul specifically since 0.7.1: │ 0..46 + 2 │ let bytes │ 47..56 + +Errors: [] + +Tree: + - YulVariableDeclarationStatement: # 0..57 "// Unreserved in Yul specifically since 0.7.1:\nlet..." + - LeadingTrivia: # 0..47 "// Unreserved in Yul specifically since 0.7.1:\n" + - SingleLineComment: "// Unreserved in Yul specifically since 0.7.1:" # 0..46 + - (let_keyword) YulLetKeyword: "let" # 47..50 + - (names) YulIdentifierPaths: # 50..57 " bytes\n" + - (item) YulIdentifierPath: # 50..57 " bytes\n" + - (item) YulIdentifier: "bytes" # 51..56 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/input.sol b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/input.sol new file mode 100644 index 0000000000..e0f82f6550 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes/input.sol @@ -0,0 +1,2 @@ +// Unreserved in Yul specifically since 0.7.1: +let bytes diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..7d0bf9cacb --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/generated/0.4.11-failure.yml @@ -0,0 +1,22 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Unreserved in Yul specifically since 0.7.1: │ 0..46 + 2 │ let bytes1 │ 47..57 + +Errors: # 1 total + - > + Error: Expected YulIdentifier. + ╭─[crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/input.sol:2:4] + │ + 2 │ let bytes1 + │ ────┬─── + │ ╰───── Error occurred here. + ───╯ + +Tree: + - YulVariableDeclarationStatement: # 0..58 "// Unreserved in Yul specifically since 0.7.1:\nlet..." + - LeadingTrivia: # 0..47 "// Unreserved in Yul specifically since 0.7.1:\n" + - SingleLineComment: "// Unreserved in Yul specifically since 0.7.1:" # 0..46 + - (let_keyword) YulLetKeyword: "let" # 47..50 + - SKIPPED: " bytes1\n" # 50..58 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/generated/0.7.1-success.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/generated/0.7.1-success.yml new file mode 100644 index 0000000000..bf78805eaa --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/generated/0.7.1-success.yml @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Unreserved in Yul specifically since 0.7.1: │ 0..46 + 2 │ let bytes1 │ 47..57 + +Errors: [] + +Tree: + - YulVariableDeclarationStatement: # 0..58 "// Unreserved in Yul specifically since 0.7.1:\nlet..." + - LeadingTrivia: # 0..47 "// Unreserved in Yul specifically since 0.7.1:\n" + - SingleLineComment: "// Unreserved in Yul specifically since 0.7.1:" # 0..46 + - (let_keyword) YulLetKeyword: "let" # 47..50 + - (names) YulIdentifierPaths: # 50..58 " bytes1\n" + - (item) YulIdentifierPath: # 50..58 " bytes1\n" + - (item) YulIdentifier: "bytes1" # 51..57 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/input.sol b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/input.sol new file mode 100644 index 0000000000..ab75db587f --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes1/input.sol @@ -0,0 +1,2 @@ +// Unreserved in Yul specifically since 0.7.1: +let bytes1 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..a72ea5a1c1 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/generated/0.4.11-failure.yml @@ -0,0 +1,22 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Unreserved in Yul specifically since 0.7.1: │ 0..46 + 2 │ let bytes11 │ 47..58 + +Errors: # 1 total + - > + Error: Expected YulIdentifier. + ╭─[crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/input.sol:2:4] + │ + 2 │ let bytes11 + │ ────┬──── + │ ╰────── Error occurred here. + ───╯ + +Tree: + - YulVariableDeclarationStatement: # 0..59 "// Unreserved in Yul specifically since 0.7.1:\nlet..." + - LeadingTrivia: # 0..47 "// Unreserved in Yul specifically since 0.7.1:\n" + - SingleLineComment: "// Unreserved in Yul specifically since 0.7.1:" # 0..46 + - (let_keyword) YulLetKeyword: "let" # 47..50 + - SKIPPED: " bytes11\n" # 50..59 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/generated/0.7.1-success.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/generated/0.7.1-success.yml new file mode 100644 index 0000000000..f4d8b84993 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/generated/0.7.1-success.yml @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // Unreserved in Yul specifically since 0.7.1: │ 0..46 + 2 │ let bytes11 │ 47..58 + +Errors: [] + +Tree: + - YulVariableDeclarationStatement: # 0..59 "// Unreserved in Yul specifically since 0.7.1:\nlet..." + - LeadingTrivia: # 0..47 "// Unreserved in Yul specifically since 0.7.1:\n" + - SingleLineComment: "// Unreserved in Yul specifically since 0.7.1:" # 0..46 + - (let_keyword) YulLetKeyword: "let" # 47..50 + - (names) YulIdentifierPaths: # 50..59 " bytes11\n" + - (item) YulIdentifierPath: # 50..59 " bytes11\n" + - (item) YulIdentifier: "bytes11" # 51..58 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/input.sol b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/input.sol new file mode 100644 index 0000000000..547ee4bda7 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_bytes11/input.sol @@ -0,0 +1,2 @@ +// Unreserved in Yul specifically since 0.7.1: +let bytes11 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.11-success.yml new file mode 100644 index 0000000000..fe70a7664f --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.11-success.yml @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is reserved only since 0.4.14 until 0.7.1 in Yul: │ 0..62 + 2 │ let ufixed184x80 │ 63..79 + +Errors: [] + +Tree: + - YulVariableDeclarationStatement: # 0..80 "// This form is reserved only since 0.4.14 until 0..." + - LeadingTrivia: # 0..63 "// This form is reserved only since 0.4.14 until 0..." + - SingleLineComment: "// This form is reserved only since 0.4.14 until 0..." # 0..62 + - (let_keyword) YulLetKeyword: "let" # 63..66 + - (names) YulIdentifierPaths: # 66..80 " ufixed184x80\n" + - (item) YulIdentifierPath: # 66..80 " ufixed184x80\n" + - (item) YulIdentifier: "ufixed184x80" # 67..79 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.14-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.14-failure.yml new file mode 100644 index 0000000000..d7ad02983c --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.4.14-failure.yml @@ -0,0 +1,22 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is reserved only since 0.4.14 until 0.7.1 in Yul: │ 0..62 + 2 │ let ufixed184x80 │ 63..79 + +Errors: # 1 total + - > + Error: Expected YulIdentifier. + ╭─[crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/input.sol:2:4] + │ + 2 │ let ufixed184x80 + │ ───────┬────── + │ ╰──────── Error occurred here. + ───╯ + +Tree: + - YulVariableDeclarationStatement: # 0..80 "// This form is reserved only since 0.4.14 until 0..." + - LeadingTrivia: # 0..63 "// This form is reserved only since 0.4.14 until 0..." + - SingleLineComment: "// This form is reserved only since 0.4.14 until 0..." # 0..62 + - (let_keyword) YulLetKeyword: "let" # 63..66 + - SKIPPED: " ufixed184x80\n" # 66..80 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.7.1-success.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.7.1-success.yml new file mode 100644 index 0000000000..fe70a7664f --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/generated/0.7.1-success.yml @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is reserved only since 0.4.14 until 0.7.1 in Yul: │ 0..62 + 2 │ let ufixed184x80 │ 63..79 + +Errors: [] + +Tree: + - YulVariableDeclarationStatement: # 0..80 "// This form is reserved only since 0.4.14 until 0..." + - LeadingTrivia: # 0..63 "// This form is reserved only since 0.4.14 until 0..." + - SingleLineComment: "// This form is reserved only since 0.4.14 until 0..." # 0..62 + - (let_keyword) YulLetKeyword: "let" # 63..66 + - (names) YulIdentifierPaths: # 66..80 " ufixed184x80\n" + - (item) YulIdentifierPath: # 66..80 " ufixed184x80\n" + - (item) YulIdentifier: "ufixed184x80" # 67..79 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/input.sol b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/input.sol new file mode 100644 index 0000000000..dc162b1c21 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed184x80/input.sol @@ -0,0 +1,2 @@ +// This form is reserved only since 0.4.14 until 0.7.1 in Yul: +let ufixed184x80 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.11-success.yml new file mode 100644 index 0000000000..7cde4d6cf9 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.11-success.yml @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is reserved only since 0.4.14 until 0.7.1 in Yul: │ 0..62 + 2 │ let ufixed8x0 │ 63..76 + +Errors: [] + +Tree: + - YulVariableDeclarationStatement: # 0..77 "// This form is reserved only since 0.4.14 until 0..." + - LeadingTrivia: # 0..63 "// This form is reserved only since 0.4.14 until 0..." + - SingleLineComment: "// This form is reserved only since 0.4.14 until 0..." # 0..62 + - (let_keyword) YulLetKeyword: "let" # 63..66 + - (names) YulIdentifierPaths: # 66..77 " ufixed8x0\n" + - (item) YulIdentifierPath: # 66..77 " ufixed8x0\n" + - (item) YulIdentifier: "ufixed8x0" # 67..76 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.14-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.14-failure.yml new file mode 100644 index 0000000000..ec37963869 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.4.14-failure.yml @@ -0,0 +1,22 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is reserved only since 0.4.14 until 0.7.1 in Yul: │ 0..62 + 2 │ let ufixed8x0 │ 63..76 + +Errors: # 1 total + - > + Error: Expected YulIdentifier. + ╭─[crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/input.sol:2:4] + │ + 2 │ let ufixed8x0 + │ ─────┬───── + │ ╰─────── Error occurred here. + ───╯ + +Tree: + - YulVariableDeclarationStatement: # 0..77 "// This form is reserved only since 0.4.14 until 0..." + - LeadingTrivia: # 0..63 "// This form is reserved only since 0.4.14 until 0..." + - SingleLineComment: "// This form is reserved only since 0.4.14 until 0..." # 0..62 + - (let_keyword) YulLetKeyword: "let" # 63..66 + - SKIPPED: " ufixed8x0\n" # 66..77 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.7.1-success.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.7.1-success.yml new file mode 100644 index 0000000000..7cde4d6cf9 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/generated/0.7.1-success.yml @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is reserved only since 0.4.14 until 0.7.1 in Yul: │ 0..62 + 2 │ let ufixed8x0 │ 63..76 + +Errors: [] + +Tree: + - YulVariableDeclarationStatement: # 0..77 "// This form is reserved only since 0.4.14 until 0..." + - LeadingTrivia: # 0..63 "// This form is reserved only since 0.4.14 until 0..." + - SingleLineComment: "// This form is reserved only since 0.4.14 until 0..." # 0..62 + - (let_keyword) YulLetKeyword: "let" # 63..66 + - (names) YulIdentifierPaths: # 66..77 " ufixed8x0\n" + - (item) YulIdentifierPath: # 66..77 " ufixed8x0\n" + - (item) YulIdentifier: "ufixed8x0" # 67..76 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/input.sol b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/input.sol new file mode 100644 index 0000000000..5be376934c --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x0/input.sol @@ -0,0 +1,2 @@ +// This form is reserved only since 0.4.14 until 0.7.1 in Yul: +let ufixed8x0 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/generated/0.4.11-failure.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/generated/0.4.11-failure.yml new file mode 100644 index 0000000000..b5b3d3ee8c --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/generated/0.4.11-failure.yml @@ -0,0 +1,22 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is always reserved until 0.7.1 in Yul: │ 0..51 + 2 │ let ufixed8x8 │ 52..65 + +Errors: # 1 total + - > + Error: Expected YulIdentifier. + ╭─[crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/input.sol:2:4] + │ + 2 │ let ufixed8x8 + │ ─────┬───── + │ ╰─────── Error occurred here. + ───╯ + +Tree: + - YulVariableDeclarationStatement: # 0..66 "// This form is always reserved until 0.7.1 in Yul..." + - LeadingTrivia: # 0..52 "// This form is always reserved until 0.7.1 in Yul..." + - SingleLineComment: "// This form is always reserved until 0.7.1 in Yul..." # 0..51 + - (let_keyword) YulLetKeyword: "let" # 52..55 + - SKIPPED: " ufixed8x8\n" # 55..66 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/generated/0.7.1-success.yml b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/generated/0.7.1-success.yml new file mode 100644 index 0000000000..1ab357c8a9 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/generated/0.7.1-success.yml @@ -0,0 +1,16 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This form is always reserved until 0.7.1 in Yul: │ 0..51 + 2 │ let ufixed8x8 │ 52..65 + +Errors: [] + +Tree: + - YulVariableDeclarationStatement: # 0..66 "// This form is always reserved until 0.7.1 in Yul..." + - LeadingTrivia: # 0..52 "// This form is always reserved until 0.7.1 in Yul..." + - SingleLineComment: "// This form is always reserved until 0.7.1 in Yul..." # 0..51 + - (let_keyword) YulLetKeyword: "let" # 52..55 + - (names) YulIdentifierPaths: # 55..66 " ufixed8x8\n" + - (item) YulIdentifierPath: # 55..66 " ufixed8x8\n" + - (item) YulIdentifier: "ufixed8x8" # 56..65 diff --git a/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/input.sol b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/input.sol new file mode 100644 index 0000000000..f575d5dece --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/YulVariableDeclarationStatement/keyword_ufixed8x8/input.sol @@ -0,0 +1,2 @@ +// This form is always reserved until 0.7.1 in Yul: +let ufixed8x8