From bc2a1211cf09660e437050a5a21f31191ae2276f Mon Sep 17 00:00:00 2001 From: OmarTawfik <15987992+OmarTawfik@users.noreply.github.com> Date: Tue, 9 Jan 2024 08:51:03 -0800 Subject: [PATCH] migrate EBNF codegen to DSL v2 --- Cargo.lock | 15 + Cargo.toml | 1 + crates/codegen/ebnf/Cargo.toml | 2 + crates/codegen/ebnf/src/builder.rs | 432 +++++ crates/codegen/ebnf/src/legacy/mod.rs | 7 + crates/codegen/ebnf/src/{ => legacy}/nodes.rs | 0 .../codegen/ebnf/src/{ => legacy}/parser.rs | 2 +- .../src/{ => legacy}/precedence_parser.rs | 4 +- .../codegen/ebnf/src/{ => legacy}/scanner.rs | 2 +- .../ebnf/src/{ => legacy}/serialization.rs | 2 +- crates/codegen/ebnf/src/lib.rs | 53 +- crates/codegen/ebnf/src/model.rs | 110 ++ crates/codegen/ebnf/src/serializer.rs | 192 ++ crates/codegen/spec/src/lib.rs | 14 +- crates/codegen/spec/src/snippets.rs | 2 +- .../utils/src/codegen/common/formatting.rs | 3 +- crates/solidity/outputs/spec/Cargo.toml | 2 + crates/solidity/outputs/spec/build.rs | 84 +- .../outputs/spec/generated/solidity.ebnf | 1727 +++++++++++++++++ 19 files changed, 2624 insertions(+), 30 deletions(-) create mode 100644 crates/codegen/ebnf/src/builder.rs create mode 100644 crates/codegen/ebnf/src/legacy/mod.rs rename crates/codegen/ebnf/src/{ => legacy}/nodes.rs (100%) rename crates/codegen/ebnf/src/{ => legacy}/parser.rs (97%) rename crates/codegen/ebnf/src/{ => legacy}/precedence_parser.rs (97%) rename crates/codegen/ebnf/src/{ => legacy}/scanner.rs (97%) rename crates/codegen/ebnf/src/{ => legacy}/serialization.rs (99%) create mode 100644 crates/codegen/ebnf/src/model.rs create mode 100644 crates/codegen/ebnf/src/serializer.rs create mode 100644 crates/solidity/outputs/spec/generated/solidity.ebnf diff --git a/Cargo.lock b/Cargo.lock index 2041a04124..62efbd6759 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -381,7 +381,9 @@ name = "codegen_ebnf" version = "0.12.0" dependencies = [ "Inflector", + "codegen_language_definition", "codegen_schema", + "derive-new", "indexmap 1.9.3", "semver", ] @@ -629,6 +631,17 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" +[[package]] +name = "derive-new" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "deunicode" version = "0.4.4" @@ -2120,6 +2133,8 @@ name = "solidity_spec" version = "0.12.0" dependencies = [ "anyhow", + "codegen_ebnf", + "codegen_language_definition", "codegen_schema", "codegen_spec", "infra_utils", diff --git a/Cargo.toml b/Cargo.toml index 29c990bf80..24914d4fe6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,6 +73,7 @@ cargo-emit = { version = "0.2.1" } cargo-xwin = { version = "0.14.2" } clap = { version = "4.1.13", features = ["derive", "wrap_help"] } clap_complete = { version = "4.3.2" } +derive-new = { version = "0.6.0" } ignore = { version = "0.4.20" } indexmap = { version = "1.9.2", features = ["serde"] } indicatif = { version = "0.17.3" } diff --git a/crates/codegen/ebnf/Cargo.toml b/crates/codegen/ebnf/Cargo.toml index ff4445db3e..ac3acff99a 100644 --- a/crates/codegen/ebnf/Cargo.toml +++ b/crates/codegen/ebnf/Cargo.toml @@ -8,6 +8,8 @@ publish = false [dependencies] codegen_schema = { workspace = true } +codegen_language_definition = { workspace = true } +derive-new = { workspace = true } indexmap = { workspace = true } Inflector = { workspace = true } semver = { workspace = true } diff --git a/crates/codegen/ebnf/src/builder.rs b/crates/codegen/ebnf/src/builder.rs new file mode 100644 index 0000000000..fd5148927b --- /dev/null +++ b/crates/codegen/ebnf/src/builder.rs @@ -0,0 +1,432 @@ +use std::collections::HashMap; + +use codegen_language_definition::model::{ + EnumItem, EnumVariant, Field, FragmentItem, Identifier, Item, KeywordDefinition, KeywordItem, + KeywordValue, Language, OperatorModel, PrecedenceExpression, PrecedenceItem, + PrecedenceOperator, PrimaryExpression, RepeatedItem, Scanner, SeparatedItem, StructItem, + TokenDefinition, TokenItem, TriviaItem, VersionSpecifier, +}; +use indexmap::IndexMap; +use inflector::Inflector; + +use crate::model::{Definition, DefinitionKind, Entry, Expression, Value}; + +pub struct Builder { + entries: HashMap, +} + +impl Builder { + pub fn build(language: &Language) -> HashMap { + let mut builder = Self { + entries: HashMap::new(), + }; + + for item in language.items() { + match item { + Item::Struct { item } => builder.build_struct_item(item), + Item::Enum { item } => builder.build_enum_item(item), + Item::Repeated { item } => builder.build_repeated_item(item), + Item::Separated { item } => builder.build_separated_item(item), + Item::Precedence { item } => builder.build_precedence_item(item), + Item::Trivia { item } => builder.build_trivia_item(item), + Item::Keyword { item } => builder.build_keyword_item(item), + Item::Token { item } => builder.build_token_item(item), + Item::Fragment { item } => builder.build_fragment_item(item), + }; + } + + builder.entries + } + + fn add_entry(&mut self, name: &Identifier, is_terminal: bool, is_inlined: bool) { + let mut ebnf_id = name.to_string(); + + if is_terminal { + ebnf_id = ebnf_id.to_screaming_snake_case(); + } + + if is_inlined { + ebnf_id = format!("«{ebnf_id}»"); + } + + let existing_entry = self.entries.insert( + name.to_string(), + Entry::new(name.to_string(), ebnf_id, vec![]), + ); + + assert!( + existing_entry.is_none(), + "Entry '{name}' is already defined." + ); + } + + fn add_definition( + &mut self, + name: &Identifier, + leading_comments: impl IntoIterator, + values: impl IntoIterator, + kind: DefinitionKind, + ) { + let definition = Definition::new( + leading_comments.into_iter().collect(), + values.into_iter().collect(), + kind, + ); + + self.entries + .get_mut(name.as_str()) + .unwrap_or_else(|| panic!("Entry '{name}' is not defined.")) + .definitions + .push(definition); + } + + fn build_struct_item(&mut self, struct_item: &StructItem) { + let StructItem { + name, + enabled, + error_recovery: _, + fields, + } = struct_item; + + self.add_entry(name, false, false); + + self.add_definition( + name, + Self::build_enabled(enabled), + Self::build_fields(fields), + DefinitionKind::Sequence, + ); + } + + fn build_enum_item(&mut self, enum_item: &EnumItem) { + let EnumItem { + name, + enabled, + variants, + } = enum_item; + + self.add_entry(name, false, false); + + let variants = variants.iter().map(|EnumVariant { reference, enabled }| { + Value::new(Self::build_ref(reference), Self::build_enabled(enabled)) + }); + + self.add_definition( + name, + Self::build_enabled(enabled), + variants, + DefinitionKind::Choice, + ); + } + + fn build_repeated_item(&mut self, repeated_item: &RepeatedItem) { + let RepeatedItem { + name, + reference, + enabled, + } = repeated_item; + + self.add_entry(name, false, false); + + let expression = Expression::new_one_or_more(Self::build_ref(reference).into()); + + self.add_definition( + name, + Self::build_enabled(enabled), + Some(Value::new(expression, None)), + DefinitionKind::Sequence, + ); + } + + fn build_separated_item(&mut self, separated_item: &SeparatedItem) { + let SeparatedItem { + name, + reference, + separator, + enabled, + } = separated_item; + + self.add_entry(name, false, false); + + let expression = Expression::new_sequence(vec![ + Self::build_ref(reference), + Expression::new_zero_or_more( + Expression::new_sequence(vec![ + Self::build_ref(separator), + Self::build_ref(reference), + ]) + .into(), + ), + ]); + + self.add_definition( + name, + Self::build_enabled(enabled), + Some(Value::new(expression, None)), + DefinitionKind::Sequence, + ); + } + + fn build_precedence_item(&mut self, precedence_item: &PrecedenceItem) { + let PrecedenceItem { + name: base_name, + enabled, + precedence_expressions, + primary_expressions, + } = precedence_item; + + self.add_entry(base_name, false, false); + + let mut values = vec![]; + + for precedence_expression in precedence_expressions { + let PrecedenceExpression { name, operators } = precedence_expression.as_ref(); + + values.push(Value::new(Self::build_ref(name), None)); + + self.add_entry(name, false, false); + + for operator in operators { + self.build_precedence_operator(base_name, name, operator); + } + } + + for primary_expression in primary_expressions { + let PrimaryExpression { reference, enabled } = primary_expression; + + values.push(Value::new( + Self::build_ref(reference), + Self::build_enabled(enabled), + )); + } + + self.add_definition( + base_name, + Self::build_enabled(enabled), + values, + DefinitionKind::Choice, + ); + } + + fn build_precedence_operator( + &mut self, + base_name: &Identifier, + name: &Identifier, + precedence_operator: &PrecedenceOperator, + ) { + let PrecedenceOperator { + model: operator_model, + enabled, + error_recovery: _, + fields, + } = precedence_operator; + + let mut leading_comments = vec![]; + let mut values = Self::build_fields(fields); + + match operator_model { + OperatorModel::Prefix => { + leading_comments.push("Prefix unary operator".to_string()); + + values.push(Value::new(Self::build_ref(base_name), None)); + } + OperatorModel::Postfix => { + leading_comments.push("Postfix unary operator".to_string()); + + values.insert(0, Value::new(Self::build_ref(base_name), None)); + } + OperatorModel::BinaryLeftAssociative => { + leading_comments.push("Left-associative binary operator".to_string()); + + values.insert(0, Value::new(Self::build_ref(base_name), None)); + values.push(Value::new(Self::build_ref(base_name), None)); + } + OperatorModel::BinaryRightAssociative => { + leading_comments.push("Right-associative binary operator".to_string()); + + values.insert(0, Value::new(Self::build_ref(base_name), None)); + values.push(Value::new(Self::build_ref(base_name), None)); + } + }; + + leading_comments.extend(Self::build_enabled(enabled)); + + self.add_definition(name, leading_comments, values, DefinitionKind::Sequence); + } + + fn build_fields(fields: &IndexMap) -> Vec { + fields + .values() + .map(|field| match field { + Field::Required { reference } => Value::new(Self::build_ref(reference), None), + Field::Optional { reference, enabled } => Value::new( + Expression::new_optional(Self::build_ref(reference).into()), + Self::build_enabled(enabled), + ), + }) + .collect() + } + + fn build_trivia_item(&mut self, trivia_item: &TriviaItem) { + let TriviaItem { name, scanner } = trivia_item; + + self.add_entry(name, true, false); + + self.add_definition( + name, + None, + Some(Value::new(Self::build_scanner(scanner), None)), + DefinitionKind::Sequence, + ); + } + + fn build_keyword_item(&mut self, keyword_item: &KeywordItem) { + let KeywordItem { + name, + identifier: _, + definitions, + } = keyword_item; + + self.add_entry(name, true, false); + + for KeywordDefinition { + enabled, + reserved, + value, + } in definitions + { + let mut leading_comments = vec![]; + + leading_comments.extend(Self::build_enabled(enabled)); + leading_comments.extend(Self::build_reserved(reserved)); + + self.add_definition( + name, + leading_comments, + Some(Value::new(Self::build_keyword_value(value), None)), + DefinitionKind::Sequence, + ); + } + } + + fn build_token_item(&mut self, token_item: &TokenItem) { + let TokenItem { name, definitions } = token_item; + + self.add_entry(name, true, false); + + for TokenDefinition { enabled, scanner } in definitions { + self.add_definition( + name, + Self::build_enabled(enabled), + Some(Value::new(Self::build_scanner(scanner), None)), + DefinitionKind::Sequence, + ); + } + } + + fn build_fragment_item(&mut self, fragment_item: &FragmentItem) { + let FragmentItem { + name, + enabled, + scanner, + } = fragment_item; + + self.add_entry(name, true, true); + + self.add_definition( + name, + Self::build_enabled(enabled), + Some(Value::new(Self::build_scanner(scanner), None)), + DefinitionKind::Sequence, + ); + } + + fn build_keyword_value(keyword_value: &KeywordValue) -> Expression { + match keyword_value { + KeywordValue::Sequence { values } => { + Expression::new_sequence(values.iter().map(Self::build_keyword_value).collect()) + } + KeywordValue::Optional { value } => { + Expression::new_optional(Self::build_keyword_value(value).into()) + } + KeywordValue::Choice { values } => { + Expression::new_choice(values.iter().map(Self::build_keyword_value).collect()) + } + KeywordValue::Atom { atom } => Expression::new_atom(atom.clone()), + } + } + + fn build_reserved(reserved: &Option) -> Option { + match reserved { + None => None, + Some(VersionSpecifier::Never) => Some("Never reserved".to_string()), + Some(VersionSpecifier::From { from }) => Some(format!("Reserved in {from}")), + Some(VersionSpecifier::Till { till }) => Some(format!("Reserved until {till}")), + Some(VersionSpecifier::Range { from, till }) => { + Some(format!("Reserved from {from} until {till}")) + } + } + } + + fn build_enabled(enabled: &Option) -> Option { + match enabled { + None => None, + Some(VersionSpecifier::Never) => None, + Some(VersionSpecifier::From { from }) => Some(format!("Introduced in {from}")), + Some(VersionSpecifier::Till { till }) => Some(format!("Deprecated in {till}")), + Some(VersionSpecifier::Range { from, till }) => { + Some(format!("Introduced in {from} and deprecated in {till}.")) + } + } + } + + fn build_scanner(scanner: &Scanner) -> Expression { + match scanner { + Scanner::Sequence { scanners } => { + Expression::new_sequence(scanners.iter().map(Self::build_scanner).collect()) + } + Scanner::Choice { scanners } => { + Expression::new_choice(scanners.iter().map(Self::build_scanner).collect()) + } + Scanner::Optional { scanner } => { + Expression::new_optional(Self::build_scanner(scanner).into()) + } + Scanner::ZeroOrMore { scanner } => { + Expression::new_zero_or_more(Self::build_scanner(scanner).into()) + } + Scanner::OneOrMore { scanner } => { + Expression::new_one_or_more(Self::build_scanner(scanner).into()) + } + Scanner::Not { chars } => { + let expression = if chars.len() == 1 { + Expression::new_atom(chars[0].to_string()) + } else { + Expression::new_sequence( + chars + .iter() + .map(|ch| Expression::new_atom(ch.to_string())) + .collect(), + ) + }; + Expression::new_not(expression.into()) + } + Scanner::Range { + inclusive_start, + inclusive_end, + } => Expression::new_range( + Expression::new_atom(inclusive_start.to_string()).into(), + Expression::new_atom(inclusive_end.to_string()).into(), + ), + Scanner::Atom { atom } => Expression::new_atom(atom.clone()), + Scanner::TrailingContext { + scanner, + not_followed_by: _, + } => Self::build_scanner(scanner), + Scanner::Fragment { reference } => Self::build_ref(reference), + } + } + + fn build_ref(reference: &Identifier) -> Expression { + Expression::new_reference(reference.to_string()) + } +} diff --git a/crates/codegen/ebnf/src/legacy/mod.rs b/crates/codegen/ebnf/src/legacy/mod.rs new file mode 100644 index 0000000000..4aef2f5e8a --- /dev/null +++ b/crates/codegen/ebnf/src/legacy/mod.rs @@ -0,0 +1,7 @@ +mod nodes; +mod parser; +mod precedence_parser; +mod scanner; +mod serialization; + +pub use serialization::EbnfSerializer; diff --git a/crates/codegen/ebnf/src/nodes.rs b/crates/codegen/ebnf/src/legacy/nodes.rs similarity index 100% rename from crates/codegen/ebnf/src/nodes.rs rename to crates/codegen/ebnf/src/legacy/nodes.rs diff --git a/crates/codegen/ebnf/src/parser.rs b/crates/codegen/ebnf/src/legacy/parser.rs similarity index 97% rename from crates/codegen/ebnf/src/parser.rs rename to crates/codegen/ebnf/src/legacy/parser.rs index ccc1587be2..a02d303873 100644 --- a/crates/codegen/ebnf/src/parser.rs +++ b/crates/codegen/ebnf/src/legacy/parser.rs @@ -1,6 +1,6 @@ use codegen_schema::types::{ParserDefinition, ParserRef}; -use crate::nodes::EbnfNode; +use crate::legacy::nodes::EbnfNode; impl EbnfNode { pub fn from_parser(parser: &ParserRef) -> Self { diff --git a/crates/codegen/ebnf/src/precedence_parser.rs b/crates/codegen/ebnf/src/legacy/precedence_parser.rs similarity index 97% rename from crates/codegen/ebnf/src/precedence_parser.rs rename to crates/codegen/ebnf/src/legacy/precedence_parser.rs index 587f9289e8..e7fa740745 100644 --- a/crates/codegen/ebnf/src/precedence_parser.rs +++ b/crates/codegen/ebnf/src/legacy/precedence_parser.rs @@ -1,7 +1,7 @@ use codegen_schema::types::{OperatorModel, PrecedenceParserRef}; -use crate::nodes::EbnfNode; -use crate::EbnfSerializer; +use crate::legacy::nodes::EbnfNode; +use crate::legacy::EbnfSerializer; impl EbnfNode { pub fn from_precedence_parser( diff --git a/crates/codegen/ebnf/src/scanner.rs b/crates/codegen/ebnf/src/legacy/scanner.rs similarity index 97% rename from crates/codegen/ebnf/src/scanner.rs rename to crates/codegen/ebnf/src/legacy/scanner.rs index 14caa6661f..4edead0fc9 100644 --- a/crates/codegen/ebnf/src/scanner.rs +++ b/crates/codegen/ebnf/src/legacy/scanner.rs @@ -1,6 +1,6 @@ use codegen_schema::types::{ScannerDefinition, ScannerRef}; -use crate::nodes::EbnfNode; +use crate::legacy::nodes::EbnfNode; impl EbnfNode { pub fn from_scanner(scanner: &ScannerRef) -> Self { diff --git a/crates/codegen/ebnf/src/serialization.rs b/crates/codegen/ebnf/src/legacy/serialization.rs similarity index 99% rename from crates/codegen/ebnf/src/serialization.rs rename to crates/codegen/ebnf/src/legacy/serialization.rs index c3b9f477ab..93024a7d18 100644 --- a/crates/codegen/ebnf/src/serialization.rs +++ b/crates/codegen/ebnf/src/legacy/serialization.rs @@ -5,7 +5,7 @@ use indexmap::IndexMap; use inflector::Inflector; use semver::Version; -use crate::nodes::EbnfNode; +use crate::legacy::nodes::EbnfNode; const MAX_LINE_WIDTH: usize = 80; diff --git a/crates/codegen/ebnf/src/lib.rs b/crates/codegen/ebnf/src/lib.rs index ca4a803402..adf4418f85 100644 --- a/crates/codegen/ebnf/src/lib.rs +++ b/crates/codegen/ebnf/src/lib.rs @@ -1,11 +1,42 @@ -//! Provides an [`EbnfSerializer`], which allows to serialize a [`LanguageDefinition`](`codegen_schema::types::LanguageDefinition`) -//! into EBNF snippets. -//! -//! Used for documentation and for comments in the generated parser code. -mod nodes; -mod parser; -mod precedence_parser; -mod scanner; -mod serialization; - -pub use serialization::EbnfSerializer; +//! Provides an [`legacy::EbnfSerializer`] type that converts [`codegen_language_definition`] items into EBNF blocks of tokens +//! that can be serialized into strings (for doc comments) or HTML (for the human readable spec). + +mod builder; +mod model; +mod serializer; + +pub mod legacy; + +use std::collections::HashMap; + +use codegen_language_definition::model::Language; + +use crate::builder::Builder; +use crate::model::Entry; +use crate::serializer::Serializer; + +pub struct EbnfModel { + entries: HashMap, +} + +pub trait EbnfWriter { + fn start_line(&mut self); + fn end_line(&mut self); + + fn write_comment(&mut self, value: String); + fn write_identifier(&mut self, value: &str, name: &str); + fn write_punctuation(&mut self, value: &str); + fn write_string_literal(&mut self, value: String); +} + +impl EbnfModel { + pub fn build(language: &Language) -> Self { + Self { + entries: Builder::build(language), + } + } + + pub fn serialize(&self, name: &str, writer: &mut impl EbnfWriter) { + Serializer::serialize(self, name, writer); + } +} diff --git a/crates/codegen/ebnf/src/model.rs b/crates/codegen/ebnf/src/model.rs new file mode 100644 index 0000000000..6c89881750 --- /dev/null +++ b/crates/codegen/ebnf/src/model.rs @@ -0,0 +1,110 @@ +/// A [`Entry`] holds all definitions under the same name. +/// Some grammar items can produce more than one definition each (tokens, keywords, operators). +/// +/// Additionally, it computes the EBNF ID from the name, accourding to the following rules: +/// +/// - For non-terminals, we use the original name in `PascalCase`. +/// - For terminals, we use the name in `SCREAMING_SNAKE_CASE`. +/// - For fragments, we add `«guillemets»` around the name. +#[derive(derive_new::new)] +pub struct Entry { + pub name: String, + pub ebnf_id: String, + + pub definitions: Vec, +} + +/// Each EBNF [`Definition`] starts with zero or more lines of doc comments, +/// then its name, an equal `=` sign, and a value, which is one of two kinds: +/// +/// ```ebnf +/// (* A sequence of values, split into multiple lines: *) +/// Name = Value1 +/// Value2 +/// Value3; +/// +/// (* A choice of values, split into multiple lines, and separated by a bar `|`: *) +/// Name = Value1 +/// | Value2 +/// | Value3; +/// ``` +#[derive(derive_new::new)] +pub struct Definition { + pub leading_comments: Vec, + pub values: Vec, + pub kind: DefinitionKind, +} + +pub enum DefinitionKind { + Sequence, + Choice, +} + +/// A [`Value`] is a single EBNF [`Expression`], followed by an optional trailing comment (at the end of the line). +/// +/// ```ebnf +/// Name = Value; (* optional trailing comment for Value *) +/// ``` +#[derive(derive_new::new)] +pub struct Value { + pub expression: Expression, + pub trailing_comment: Option, +} + +/// An [`Expression`] is a recursive structure that serializes to a single EBNF snippet without any comments. +/// +/// ```ebnf +/// Foo = Bar (Baz | "c")+; +/// ^^^^^^^^^^^^^^^^ +/// ``` +#[derive(derive_new::new)] +pub enum Expression { + Sequence { + expressions: Vec, + }, + Choice { + expressions: Vec, + }, + Optional { + expression: Box, + }, + ZeroOrMore { + expression: Box, + }, + OneOrMore { + expression: Box, + }, + Not { + expression: Box, + }, + Range { + inclusive_start: Box, + inclusive_end: Box, + }, + Atom { + atom: String, + }, + Reference { + reference: String, + }, +} + +impl Expression { + pub fn precedence(&self) -> u8 { + // We are specifying precedence "groups" instead of a flat list. + // This separates members of the same precedence, like both "a b (c | d)" and "a | b | (c d)". + match self { + // Binary + Self::Choice { .. } | Self::Range { .. } | Self::Sequence { .. } => 1, + + // Prefix + Self::Not { .. } => 2, + + // Postfix + Self::OneOrMore { .. } | Self::Optional { .. } | Self::ZeroOrMore { .. } => 3, + + // Primary + Self::Atom { .. } | Self::Reference { .. } => 4, + } + } +} diff --git a/crates/codegen/ebnf/src/serializer.rs b/crates/codegen/ebnf/src/serializer.rs new file mode 100644 index 0000000000..5c1f1bec21 --- /dev/null +++ b/crates/codegen/ebnf/src/serializer.rs @@ -0,0 +1,192 @@ +use std::mem::discriminant; + +use crate::model::{Definition, DefinitionKind, Entry, Expression, Value}; +use crate::{EbnfModel, EbnfWriter}; + +pub struct Serializer<'t, W: EbnfWriter> { + model: &'t EbnfModel, + writer: &'t mut W, +} + +impl<'t, W: EbnfWriter> Serializer<'t, W> { + pub fn serialize<'m: 't>(model: &'m EbnfModel, name: &str, writer: &'m mut W) { + let entry = model + .entries + .get(name) + .unwrap_or_else(|| panic!("Entry not defined: '{name}'.")); + + Self { model, writer }.serialize_entry(entry); + } + + fn serialize_entry(&mut self, entry: &Entry) { + let Entry { + name, + ebnf_id: _, + definitions, + } = entry; + + for (index, definition) in definitions.iter().enumerate() { + if index > 0 { + // Insert a blank line between definitions: + self.writer.start_line(); + self.writer.end_line(); + } + + let Definition { + leading_comments, + values, + kind, + } = definition; + + for comment in leading_comments { + self.writer.start_line(); + self.serialize_comment(comment); + self.writer.end_line(); + } + + self.serialize_definition(name, values, kind); + } + } + + fn serialize_definition(&mut self, name: &str, values: &Vec, kind: &DefinitionKind) { + let separator = match kind { + DefinitionKind::Sequence => ' ', + DefinitionKind::Choice => '|', + }; + + for (index, value) in values.iter().enumerate() { + let Value { + expression, + trailing_comment, + } = value; + + self.writer.start_line(); + + if index == 0 { + self.serialize_identifier(name); + self.serialize_punctuation(" = "); + } else { + self.serialize_punctuation(&format!( + "{padding} {separator} ", + padding = " ".repeat(name.len()), + )); + } + + self.serialize_expr(expression); + + if index + 1 == values.len() { + self.serialize_punctuation(";"); + } + + if let Some(comment) = trailing_comment { + self.serialize_punctuation(" "); + self.serialize_comment(comment); + } + + self.writer.end_line(); + } + } + + fn serialize_expr(&mut self, parent: &Expression) { + match parent { + Expression::Sequence { expressions } => { + self.serialize_child_expr(parent, &expressions[0]); + + for expression in expressions.iter().skip(1) { + self.serialize_punctuation(" "); + self.serialize_child_expr(parent, expression); + } + } + Expression::Choice { expressions } => { + self.serialize_child_expr(parent, &expressions[0]); + + for expression in expressions.iter().skip(1) { + self.serialize_punctuation(" | "); + self.serialize_child_expr(parent, expression); + } + } + Expression::Optional { expression } => { + self.serialize_child_expr(parent, expression); + self.serialize_punctuation("?"); + } + Expression::ZeroOrMore { expression } => { + self.serialize_child_expr(parent, expression); + self.serialize_punctuation("*"); + } + Expression::OneOrMore { expression } => { + self.serialize_child_expr(parent, expression); + self.serialize_punctuation("+"); + } + Expression::Not { expression } => { + self.serialize_punctuation("!"); + self.serialize_child_expr(parent, expression); + } + Expression::Range { + inclusive_start, + inclusive_end, + } => { + self.serialize_child_expr(parent, inclusive_start); + self.serialize_punctuation("…"); + self.serialize_child_expr(parent, inclusive_end); + } + Expression::Atom { atom } => { + self.serialize_string_literal(atom); + } + Expression::Reference { reference } => { + self.serialize_identifier(reference); + } + }; + } + + fn serialize_child_expr(&mut self, parent: &Expression, child: &Expression) { + if discriminant(parent) != discriminant(child) && child.precedence() <= parent.precedence() + { + self.serialize_punctuation("("); + self.serialize_expr(child); + self.serialize_punctuation(")"); + } else { + self.serialize_expr(child); + } + } + + fn serialize_comment(&mut self, value: &String) { + self.writer.write_comment(format!("(* {value} *)")); + } + + fn serialize_identifier(&mut self, name: &str) { + let value = &self.model.entries[name].ebnf_id; + self.writer.write_identifier(value, name); + } + + fn serialize_punctuation(&mut self, value: &str) { + self.writer.write_punctuation(value); + } + + fn serialize_string_literal(&mut self, value: &str) { + let delimiter = if value.contains('"') && !value.contains('\'') { + '\'' + } else { + '"' + }; + + let formatted: String = value + .chars() + .map(|c| match c { + c if c == '\\' || c == delimiter => format!("\\{c}"), + c if c == ' ' || c.is_ascii_graphic() => c.to_string(), + '\t' => "\\t".to_string(), + '\r' => "\\r".to_string(), + '\n' => "\\n".to_string(), + _ => { + panic!( + "Unexpected character in string literal: '{c}'", + c = c.escape_unicode() + ); + } + }) + .collect(); + + self.writer + .write_string_literal(format!("{delimiter}{formatted}{delimiter}")); + } +} diff --git a/crates/codegen/spec/src/lib.rs b/crates/codegen/spec/src/lib.rs index 8218dbea76..2e33ce2fdb 100644 --- a/crates/codegen/spec/src/lib.rs +++ b/crates/codegen/spec/src/lib.rs @@ -7,7 +7,7 @@ //! //! and the auxiliary snippet files included by the grammar mkdocs pages. //! -//! Exposes a [`SpecGeneratorExtensions`] trait that generates all the pages in a given [`Codegen`] context. +//! Exposes a [`SpecGeneratorExtensions`] trait that generates all the specification pages for a given language. mod grammar; mod markdown; mod navigation; @@ -18,7 +18,7 @@ use std::path::Path; use anyhow::Result; use codegen_schema::types::LanguageDefinitionRef; -use infra_utils::codegen::Codegen; +use infra_utils::codegen::CodegenWriteOnly; use crate::grammar::{generate_grammar_dir, generate_supported_versions_page}; use crate::navigation::NavigationEntry; @@ -28,15 +28,13 @@ use crate::snippets::Snippets; /// Extension trait for [`LanguageDefinitionRef`] that generates the specification files. pub trait SpecGeneratorExtensions { /// Generates the specification files in `output_dir`. - fn generate_spec(&self, output_dir: &Path) -> Result<()>; + fn generate_spec(&self, codegen: &mut CodegenWriteOnly, output_dir: &Path) -> Result<()>; } impl SpecGeneratorExtensions for LanguageDefinitionRef { - fn generate_spec(&self, output_dir: &Path) -> Result<()> { - let mut codegen = Codegen::write_only()?; - + fn generate_spec(&self, codegen: &mut CodegenWriteOnly, output_dir: &Path) -> Result<()> { let snippets = Snippets::new(self, output_dir); - snippets.write_files(&mut codegen)?; + snippets.write_files(codegen)?; let root_entry = NavigationEntry::Directory { title: format!("{title} Specification", title = self.title), @@ -48,6 +46,6 @@ impl SpecGeneratorExtensions for LanguageDefinitionRef { ], }; - root_entry.write_files(&mut codegen, output_dir) + root_entry.write_files(codegen, output_dir) } } diff --git a/crates/codegen/spec/src/snippets.rs b/crates/codegen/spec/src/snippets.rs index 28958c8c1f..46f2d788dd 100644 --- a/crates/codegen/spec/src/snippets.rs +++ b/crates/codegen/spec/src/snippets.rs @@ -1,7 +1,7 @@ use std::path::{Path, PathBuf}; use anyhow::Result; -use codegen_ebnf::EbnfSerializer; +use codegen_ebnf::legacy::EbnfSerializer; use codegen_schema::types::{ LanguageDefinitionRef, LanguageSection, LanguageTopic, ProductionDefinition, ProductionRef, VersionMap, diff --git a/crates/infra/utils/src/codegen/common/formatting.rs b/crates/infra/utils/src/codegen/common/formatting.rs index 0122018d66..0909a816f5 100644 --- a/crates/infra/utils/src/codegen/common/formatting.rs +++ b/crates/infra/utils/src/codegen/common/formatting.rs @@ -25,6 +25,7 @@ fn generate_header(file_path: &Path) -> String { "This file is generated automatically by infrastructure scripts. Please don't edit by hand."; return match get_extension(file_path) { + "ebnf" => format!("(* {warning_line} *)"), "json" => String::new(), "html" | "md" => format!(""), "js" | "rs" | "ts" => format!("// {warning_line}"), @@ -51,7 +52,7 @@ fn run_formatter(file_path: &Path, contents: &str) -> Result { // We already generate formatted content for these, so no need to run expensive formatting. Ok(contents.to_owned()) } - "zsh-completions" => { + "ebnf" | "zsh-completions" => { // No formatters available for these (yet). Ok(contents.to_owned()) } diff --git a/crates/solidity/outputs/spec/Cargo.toml b/crates/solidity/outputs/spec/Cargo.toml index f5e9d06d4e..815d868d23 100644 --- a/crates/solidity/outputs/spec/Cargo.toml +++ b/crates/solidity/outputs/spec/Cargo.toml @@ -8,6 +8,8 @@ publish = false [build-dependencies] anyhow = { workspace = true } +codegen_ebnf = { workspace = true } +codegen_language_definition = { workspace = true } codegen_schema = { workspace = true } codegen_spec = { workspace = true } infra_utils = { workspace = true } diff --git a/crates/solidity/outputs/spec/build.rs b/crates/solidity/outputs/spec/build.rs index c4338f7c3b..30c20610ca 100644 --- a/crates/solidity/outputs/spec/build.rs +++ b/crates/solidity/outputs/spec/build.rs @@ -1,12 +1,88 @@ +use std::path::Path; + use anyhow::Result; -use codegen_schema::types::LanguageDefinition; +use codegen_ebnf::{EbnfModel, EbnfWriter}; +use codegen_language_definition::model::Language; use codegen_spec::SpecGeneratorExtensions; use infra_utils::cargo::CargoWorkspace; -use solidity_language::SolidityLanguageExtensions; +use infra_utils::codegen::{Codegen, CodegenWriteOnly}; +use solidity_language::{SolidityDefinition, SolidityLanguageExtensions}; fn main() -> Result<()> { - let language = LanguageDefinition::load_solidity()?; + let mut codegen = Codegen::write_only()?; let output_dir = CargoWorkspace::locate_source_crate("solidity_spec")?.join("generated"); - language.generate_spec(&output_dir) + // TODO: combine both ebnf and spec codegen into 'codegen_spec' crate: + let language_v0 = codegen_schema::types::LanguageDefinition::load_solidity()?; + language_v0.generate_spec(&mut codegen, &output_dir)?; + + let language_v2 = SolidityDefinition::create(); + generate_language_ebnf(&mut codegen, &language_v2, &output_dir)?; + + Ok(()) +} + +fn generate_language_ebnf( + codegen: &mut CodegenWriteOnly, + language: &Language, + output_dir: &Path, +) -> Result<()> { + let mut writer = SimpleEbnfWriter { + buffer: String::new(), + }; + let ebnf_model = EbnfModel::build(language); + + for (section_index, section) in language.sections.iter().enumerate() { + writer.buffer.push_str(&format!( + "(*\n * {section_index}. {section_title}:\n *)\n\n", + section_index = section_index + 1, + section_title = section.title, + )); + + for (topic_index, topic) in section.topics.iter().enumerate() { + writer.buffer.push_str(&format!( + "(* {section_index}.{topic_index}. {topic_title}: *)\n\n", + section_index = section_index + 1, + topic_index = topic_index + 1, + topic_title = topic.title, + )); + + for item in &topic.items { + ebnf_model.serialize(item.name(), &mut writer); + writer.buffer.push('\n'); + } + } + } + + codegen.write_file(output_dir.join("solidity.ebnf"), writer.buffer) +} + +struct SimpleEbnfWriter { + buffer: String, +} + +impl EbnfWriter for SimpleEbnfWriter { + fn start_line(&mut self) { + // No-op + } + + fn end_line(&mut self) { + self.buffer.push('\n'); + } + + fn write_comment(&mut self, value: String) { + self.buffer.push_str(&value); + } + + fn write_identifier(&mut self, value: &str, _name: &str) { + self.buffer.push_str(value); + } + + fn write_punctuation(&mut self, value: &str) { + self.buffer.push_str(value); + } + + fn write_string_literal(&mut self, value: String) { + self.buffer.push_str(&value); + } } diff --git a/crates/solidity/outputs/spec/generated/solidity.ebnf b/crates/solidity/outputs/spec/generated/solidity.ebnf new file mode 100644 index 0000000000..b67bf665e8 --- /dev/null +++ b/crates/solidity/outputs/spec/generated/solidity.ebnf @@ -0,0 +1,1727 @@ +(* This file is generated automatically by infrastructure scripts. Please don't edit by hand. *) + +(* + * 1. File Structure: + *) + +(* 1.1. Source Unit: *) + +SourceUnit = SourceUnitMembers?; + +SourceUnitMembers = SourceUnitMember+; + +SourceUnitMember = PragmaDirective + | ImportDirective + | ContractDefinition + | InterfaceDefinition + | LibraryDefinition + | StructDefinition (* Introduced in 0.6.0 *) + | EnumDefinition (* Introduced in 0.6.0 *) + | FunctionDefinition (* Introduced in 0.7.1 *) + | ConstantDefinition (* Introduced in 0.7.4 *) + | ErrorDefinition (* Introduced in 0.8.4 *) + | UserDefinedValueTypeDefinition (* Introduced in 0.8.8 *) + | UsingDirective (* Introduced in 0.8.13 *) + | EventDefinition; (* Introduced in 0.8.22 *) + +(* 1.2. Pragma Directives: *) + +PragmaDirective = PRAGMA_KEYWORD + Pragma + SEMICOLON; + +Pragma = ABICoderPragma + | ExperimentalPragma + | VersionPragma; + +ABICoderPragma = ABICODER_KEYWORD + IDENTIFIER; + +ExperimentalPragma = EXPERIMENTAL_KEYWORD + ExperimentalFeature; + +ExperimentalFeature = IDENTIFIER + | ASCII_STRING_LITERAL; + +VersionPragma = SOLIDITY_KEYWORD + VersionPragmaExpressions; + +VersionPragmaExpressions = VersionPragmaExpression+; + +VersionPragmaExpression = VersionPragmaOrExpression + | VersionPragmaRangeExpression + | VersionPragmaPrefixExpression + | VersionPragmaSpecifier; + +VersionPragmaSpecifier = VERSION_PRAGMA_VALUE (PERIOD VERSION_PRAGMA_VALUE)*; + +VERSION_PRAGMA_VALUE = (("0"…"9") | "x" | "X" | "*")+; + +SOLIDITY_KEYWORD = "solidity"; + +EXPERIMENTAL_KEYWORD = "experimental"; + +ABICODER_KEYWORD = "abicoder"; + +(* 1.3. Import Directives: *) + +ImportDirective = IMPORT_KEYWORD + ImportClause + SEMICOLON; + +ImportClause = PathImport + | NamedImport + | ImportDeconstruction; + +PathImport = ASCII_STRING_LITERAL + ImportAlias?; + +NamedImport = ASTERISK + ImportAlias + FROM_KEYWORD + ASCII_STRING_LITERAL; + +ImportDeconstruction = OPEN_BRACE + ImportDeconstructionSymbols + CLOSE_BRACE + FROM_KEYWORD + ASCII_STRING_LITERAL; + +ImportDeconstructionSymbols = ImportDeconstructionSymbol (COMMA ImportDeconstructionSymbol)*; + +ImportDeconstructionSymbol = IDENTIFIER + ImportAlias?; + +ImportAlias = AS_KEYWORD + IDENTIFIER; + +(* 1.4. Using Directives: *) + +UsingDirective = USING_KEYWORD + UsingClause + FOR_KEYWORD + UsingTarget + GLOBAL_KEYWORD? (* Introduced in 0.8.13 *) + SEMICOLON; + +UsingClause = IdentifierPath + | UsingDeconstruction; (* Introduced in 0.8.13 *) + +(* Introduced in 0.8.13 *) +UsingDeconstruction = OPEN_BRACE + UsingDeconstructionSymbols + CLOSE_BRACE; + +(* Introduced in 0.8.13 *) +UsingDeconstructionSymbols = UsingDeconstructionSymbol (COMMA UsingDeconstructionSymbol)*; + +(* Introduced in 0.8.13 *) +UsingDeconstructionSymbol = IdentifierPath + UsingAlias?; (* Introduced in 0.8.19 *) + +(* Introduced in 0.8.19 *) +UsingAlias = AS_KEYWORD + UsingOperator; + +(* Introduced in 0.8.19 *) +UsingOperator = AMPERSAND + | ASTERISK + | BANG_EQUAL + | BAR + | CARET + | EQUAL_EQUAL + | GREATER_THAN + | GREATER_THAN_EQUAL + | LESS_THAN + | LESS_THAN_EQUAL + | MINUS + | PERCENT + | PLUS + | SLASH + | TILDE; + +UsingTarget = TypeName + | ASTERISK; + +(* 1.5. Trivia: *) + +WHITESPACE = (" " | "\t")+; + +END_OF_LINE = "\r"? "\n"; + +MULTILINE_COMMENT = "/" "*" (!"*" | "*")* "*" "/"; + +SINGLE_LINE_COMMENT = "//" (!("\r" "\n"))*; + +(* 1.6. Keywords: *) + +(* Introduced in 0.6.0 *) +ABSTRACT_KEYWORD = "abstract"; + +ADDRESS_KEYWORD = "address"; + +AFTER_KEYWORD = "after"; + +(* Reserved in 0.5.0 *) +ALIAS_KEYWORD = "alias"; + +ANONYMOUS_KEYWORD = "anonymous"; + +(* Reserved in 0.5.0 *) +APPLY_KEYWORD = "apply"; + +AS_KEYWORD = "as"; + +ASSEMBLY_KEYWORD = "assembly"; + +(* Reserved in 0.5.0 *) +AUTO_KEYWORD = "auto"; + +BOOL_KEYWORD = "bool"; + +BREAK_KEYWORD = "break"; + +(* Deprecated in 0.8.0 *) +BYTE_KEYWORD = "byte"; + +BYTES_KEYWORD = "bytes" ("1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "32")?; + +(* Introduced in 0.5.0 *) +(* Reserved in 0.5.0 *) +CALL_DATA_KEYWORD = "calldata"; + +CASE_KEYWORD = "case"; + +(* Introduced in 0.6.0 *) +CATCH_KEYWORD = "catch"; + +CONSTANT_KEYWORD = "constant"; + +(* Introduced in 0.4.22 *) +(* Reserved in 0.5.0 *) +CONSTRUCTOR_KEYWORD = "constructor"; + +CONTINUE_KEYWORD = "continue"; + +CONTRACT_KEYWORD = "contract"; + +(* Reserved in 0.5.0 *) +COPY_OF_KEYWORD = "copyof"; + +DAYS_KEYWORD = "days"; + +DEFAULT_KEYWORD = "default"; + +(* Reserved in 0.5.0 *) +DEFINE_KEYWORD = "define"; + +DELETE_KEYWORD = "delete"; + +DO_KEYWORD = "do"; + +ELSE_KEYWORD = "else"; + +(* Introduced in 0.4.21 *) +(* Reserved in 0.5.0 *) +EMIT_KEYWORD = "emit"; + +ENUM_KEYWORD = "enum"; + +(* Introduced in 0.8.4 *) +(* Never reserved *) +ERROR_KEYWORD = "error"; + +ETHER_KEYWORD = "ether"; + +EVENT_KEYWORD = "event"; + +EXTERNAL_KEYWORD = "external"; + +(* Reserved in 0.6.0 *) +FALLBACK_KEYWORD = "fallback"; + +FALSE_KEYWORD = "false"; + +FINAL_KEYWORD = "final"; + +(* Deprecated in 0.7.0 *) +(* Reserved until 0.7.0 *) +FINNEY_KEYWORD = "finney"; + +FIXED_KEYWORD = "fixed"; + +FIXED_KEYWORD = "fixed" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176") "x" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80"); + +FIXED_KEYWORD = "fixed" ("184x8" | "184x16" | "184x24" | "184x32" | "184x40" | "184x48" | "184x56" | "184x64" | "184x72" | "192x8" | "192x16" | "192x24" | "192x32" | "192x40" | "192x48" | "192x56" | "192x64" | "200x8" | "200x16" | "200x24" | "200x32" | "200x40" | "200x48" | "200x56" | "208x8" | "208x16" | "208x24" | "208x32" | "208x40" | "208x48" | "216x8" | "216x16" | "216x24" | "216x32" | "216x40" | "224x8" | "224x16" | "224x24" | "224x32" | "232x8" | "232x16" | "232x24" | "240x8" | "240x16" | "248x8"); + +(* Reserved in 0.4.14 *) +FIXED_KEYWORD = "fixed" ("184x80" | "192x72" | "192x80" | "200x64" | "200x72" | "200x80" | "208x56" | "208x64" | "208x72" | "208x80" | "216x48" | "216x56" | "216x64" | "216x72" | "216x80" | "224x40" | "224x48" | "224x56" | "224x64" | "224x72" | "224x80" | "232x32" | "232x40" | "232x48" | "232x56" | "232x64" | "232x72" | "232x80" | "240x24" | "240x32" | "240x40" | "240x48" | "240x56" | "240x64" | "240x72" | "240x80" | "248x16" | "248x24" | "248x32" | "248x40" | "248x48" | "248x56" | "248x64" | "248x72" | "248x80" | "256x8" | "256x16" | "256x24" | "256x32" | "256x40" | "256x48" | "256x56" | "256x64" | "256x72" | "256x80"); + +(* Reserved in 0.4.14 *) +FIXED_KEYWORD = "fixed" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176" | "184" | "192" | "200" | "208" | "216" | "224" | "232" | "240" | "248" | "256") "x" ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "49" | "50" | "51" | "52" | "53" | "54" | "55" | "57" | "58" | "59" | "60" | "61" | "62" | "63" | "65" | "66" | "67" | "68" | "69" | "70" | "71" | "73" | "74" | "75" | "76" | "77" | "78" | "79"); + +FOR_KEYWORD = "for"; + +(* Never reserved *) +FROM_KEYWORD = "from"; + +FUNCTION_KEYWORD = "function"; + +(* Introduced in 0.8.13 *) +(* Never reserved *) +GLOBAL_KEYWORD = "global"; + +(* Introduced in 0.6.11 *) +(* Reserved in 0.7.0 *) +GWEI_KEYWORD = "gwei"; + +HEX_KEYWORD = "hex"; + +HOURS_KEYWORD = "hours"; + +IF_KEYWORD = "if"; + +(* Introduced in 0.6.5 *) +(* Reserved in 0.5.0 *) +IMMUTABLE_KEYWORD = "immutable"; + +(* Reserved in 0.5.0 *) +IMPLEMENTS_KEYWORD = "implements"; + +IMPORT_KEYWORD = "import"; + +INDEXED_KEYWORD = "indexed"; + +IN_KEYWORD = "in"; + +INLINE_KEYWORD = "inline"; + +INTERFACE_KEYWORD = "interface"; + +INTERNAL_KEYWORD = "internal"; + +INT_KEYWORD = "int" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176" | "184" | "192" | "200" | "208" | "216" | "224" | "232" | "240" | "248" | "256")?; + +IS_KEYWORD = "is"; + +LET_KEYWORD = "let"; + +LIBRARY_KEYWORD = "library"; + +(* Reserved in 0.5.0 *) +MACRO_KEYWORD = "macro"; + +MAPPING_KEYWORD = "mapping"; + +MATCH_KEYWORD = "match"; + +MEMORY_KEYWORD = "memory"; + +MINUTES_KEYWORD = "minutes"; + +MODIFIER_KEYWORD = "modifier"; + +(* Reserved in 0.5.0 *) +MUTABLE_KEYWORD = "mutable"; + +NEW_KEYWORD = "new"; + +NULL_KEYWORD = "null"; + +OF_KEYWORD = "of"; + +(* Reserved in 0.5.0 *) +OVERRIDE_KEYWORD = "override"; + +(* Reserved in 0.5.0 *) +PARTIAL_KEYWORD = "partial"; + +PAYABLE_KEYWORD = "payable"; + +PRAGMA_KEYWORD = "pragma"; + +PRIVATE_KEYWORD = "private"; + +(* Reserved in 0.5.0 *) +PROMISE_KEYWORD = "promise"; + +PUBLIC_KEYWORD = "public"; + +PURE_KEYWORD = "pure"; + +(* Reserved in 0.6.0 *) +RECEIVE_KEYWORD = "receive"; + +(* Reserved in 0.5.0 *) +REFERENCE_KEYWORD = "reference"; + +RELOCATABLE_KEYWORD = "relocatable"; + +RETURN_KEYWORD = "return"; + +RETURNS_KEYWORD = "returns"; + +(* Introduced in 0.8.4 *) +(* Never reserved *) +REVERT_KEYWORD = "revert"; + +(* Reserved in 0.5.0 *) +SEALED_KEYWORD = "sealed"; + +SECONDS_KEYWORD = "seconds"; + +(* Reserved in 0.5.0 *) +SIZE_OF_KEYWORD = "sizeof"; + +STATIC_KEYWORD = "static"; + +STORAGE_KEYWORD = "storage"; + +STRING_KEYWORD = "string"; + +STRUCT_KEYWORD = "struct"; + +(* Reserved in 0.5.0 *) +SUPPORTS_KEYWORD = "supports"; + +SWITCH_KEYWORD = "switch"; + +(* Deprecated in 0.7.0 *) +(* Reserved until 0.7.0 *) +SZABO_KEYWORD = "szabo"; + +(* Deprecated in 0.5.0 *) +THROW_KEYWORD = "throw"; + +TRUE_KEYWORD = "true"; + +(* Introduced in 0.6.0 *) +TRY_KEYWORD = "try"; + +(* Reserved in 0.5.0 *) +TYPE_DEF_KEYWORD = "typedef"; + +(* Introduced in 0.5.3 *) +TYPE_KEYWORD = "type"; + +TYPE_OF_KEYWORD = "typeof"; + +UFIXED_KEYWORD = "ufixed"; + +UFIXED_KEYWORD = "ufixed" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176") "x" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80"); + +UFIXED_KEYWORD = "ufixed" ("184x8" | "184x16" | "184x24" | "184x32" | "184x40" | "184x48" | "184x56" | "184x64" | "184x72" | "192x8" | "192x16" | "192x24" | "192x32" | "192x40" | "192x48" | "192x56" | "192x64" | "200x8" | "200x16" | "200x24" | "200x32" | "200x40" | "200x48" | "200x56" | "208x8" | "208x16" | "208x24" | "208x32" | "208x40" | "208x48" | "216x8" | "216x16" | "216x24" | "216x32" | "216x40" | "224x8" | "224x16" | "224x24" | "224x32" | "232x8" | "232x16" | "232x24" | "240x8" | "240x16" | "248x8"); + +(* Reserved in 0.4.14 *) +UFIXED_KEYWORD = "ufixed" ("184x80" | "192x72" | "192x80" | "200x64" | "200x72" | "200x80" | "208x56" | "208x64" | "208x72" | "208x80" | "216x48" | "216x56" | "216x64" | "216x72" | "216x80" | "224x40" | "224x48" | "224x56" | "224x64" | "224x72" | "224x80" | "232x32" | "232x40" | "232x48" | "232x56" | "232x64" | "232x72" | "232x80" | "240x24" | "240x32" | "240x40" | "240x48" | "240x56" | "240x64" | "240x72" | "240x80" | "248x16" | "248x24" | "248x32" | "248x40" | "248x48" | "248x56" | "248x64" | "248x72" | "248x80" | "256x8" | "256x16" | "256x24" | "256x32" | "256x40" | "256x48" | "256x56" | "256x64" | "256x72" | "256x80"); + +(* Reserved in 0.4.14 *) +UFIXED_KEYWORD = "ufixed" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176" | "184" | "192" | "200" | "208" | "216" | "224" | "232" | "240" | "248" | "256") "x" ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "49" | "50" | "51" | "52" | "53" | "54" | "55" | "57" | "58" | "59" | "60" | "61" | "62" | "63" | "65" | "66" | "67" | "68" | "69" | "70" | "71" | "73" | "74" | "75" | "76" | "77" | "78" | "79"); + +UINT_KEYWORD = "uint" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176" | "184" | "192" | "200" | "208" | "216" | "224" | "232" | "240" | "248" | "256")?; + +(* Introduced in 0.8.0 *) +(* Reserved in 0.5.0 *) +UNCHECKED_KEYWORD = "unchecked"; + +USING_KEYWORD = "using"; + +(* Deprecated in 0.5.0 *) +VAR_KEYWORD = "var"; + +VIEW_KEYWORD = "view"; + +(* Introduced in 0.6.0 *) +(* Reserved in 0.6.0 *) +VIRTUAL_KEYWORD = "virtual"; + +WEEKS_KEYWORD = "weeks"; + +WEI_KEYWORD = "wei"; + +WHILE_KEYWORD = "while"; + +(* Deprecated in 0.5.0 *) +YEARS_KEYWORD = "years"; + +(* 1.7. Punctuation: *) + +OPEN_PAREN = "("; + +CLOSE_PAREN = ")"; + +OPEN_BRACKET = "["; + +CLOSE_BRACKET = "]"; + +OPEN_BRACE = "{"; + +CLOSE_BRACE = "}"; + +COMMA = ","; + +PERIOD = "."; + +QUESTION_MARK = "?"; + +SEMICOLON = ";"; + +COLON = ":"; + +COLON_EQUAL = ":="; + +EQUAL = "="; + +EQUAL_EQUAL = "=="; + +EQUAL_GREATER_THAN = "=>"; + +ASTERISK = "*"; + +ASTERISK_EQUAL = "*="; + +ASTERISK_ASTERISK = "**"; + +BAR = "|"; + +BAR_EQUAL = "|="; + +BAR_BAR = "||"; + +AMPERSAND = "&"; + +AMPERSAND_EQUAL = "&="; + +AMPERSAND_AMPERSAND = "&&"; + +LESS_THAN = "<"; + +LESS_THAN_EQUAL = "<="; + +LESS_THAN_LESS_THAN = "<<"; + +LESS_THAN_LESS_THAN_EQUAL = "<<="; + +GREATER_THAN = ">"; + +GREATER_THAN_EQUAL = ">="; + +GREATER_THAN_GREATER_THAN = ">>"; + +GREATER_THAN_GREATER_THAN_EQUAL = ">>="; + +GREATER_THAN_GREATER_THAN_GREATER_THAN = ">>>"; + +GREATER_THAN_GREATER_THAN_GREATER_THAN_EQUAL = ">>>="; + +PLUS = "+"; + +PLUS_EQUAL = "+="; + +PLUS_PLUS = "++"; + +MINUS = "-"; + +MINUS_EQUAL = "-="; + +MINUS_MINUS = "--"; + +MINUS_GREATER_THAN = "->"; + +SLASH = "/"; + +SLASH_EQUAL = "/="; + +PERCENT = "%"; + +PERCENT_EQUAL = "%="; + +BANG = "!"; + +BANG_EQUAL = "!="; + +CARET = "^"; + +CARET_EQUAL = "^="; + +TILDE = "~"; + +(* + * 2. Definitions: + *) + +(* 2.1. Contracts: *) + +ContractDefinition = ABSTRACT_KEYWORD? (* Introduced in 0.6.0 *) + CONTRACT_KEYWORD + IDENTIFIER + InheritanceSpecifier? + OPEN_BRACE + ContractMembers? + CLOSE_BRACE; + +InheritanceSpecifier = IS_KEYWORD + InheritanceTypes; + +InheritanceTypes = InheritanceType (COMMA InheritanceType)*; + +InheritanceType = IdentifierPath + ArgumentsDeclaration?; + +ContractMembers = ContractMember+; + +ContractMember = UsingDirective + | FunctionDefinition + | ConstructorDefinition (* Introduced in 0.4.22 *) + | ReceiveFunctionDefinition (* Introduced in 0.6.0 *) + | FallbackFunctionDefinition (* Introduced in 0.6.0 *) + | UnnamedFunctionDefinition (* Deprecated in 0.6.0 *) + | ModifierDefinition + | StructDefinition + | EnumDefinition + | EventDefinition + | StateVariableDefinition + | ErrorDefinition (* Introduced in 0.8.4 *) + | UserDefinedValueTypeDefinition; (* Introduced in 0.8.8 *) + +(* 2.2. Interfaces: *) + +InterfaceDefinition = INTERFACE_KEYWORD + IDENTIFIER + InheritanceSpecifier? + OPEN_BRACE + InterfaceMembers? + CLOSE_BRACE; + +InterfaceMembers = ContractMember+; + +(* 2.3. Libraries: *) + +LibraryDefinition = LIBRARY_KEYWORD + IDENTIFIER + OPEN_BRACE + LibraryMembers? + CLOSE_BRACE; + +LibraryMembers = ContractMember+; + +(* 2.4. Structs: *) + +StructDefinition = STRUCT_KEYWORD + IDENTIFIER + OPEN_BRACE + StructMembers? + CLOSE_BRACE; + +StructMembers = StructMember+; + +StructMember = TypeName + IDENTIFIER + SEMICOLON; + +(* 2.5. Enums: *) + +EnumDefinition = ENUM_KEYWORD + IDENTIFIER + OPEN_BRACE + EnumMembers? + CLOSE_BRACE; + +EnumMembers = IDENTIFIER (COMMA IDENTIFIER)*; + +(* 2.6. Constants: *) + +(* Introduced in 0.7.4 *) +ConstantDefinition = TypeName + CONSTANT_KEYWORD + IDENTIFIER + EQUAL + Expression + SEMICOLON; + +(* 2.7. State Variables: *) + +StateVariableDefinition = TypeName + StateVariableAttributes? + IDENTIFIER + StateVariableDefinitionValue? + SEMICOLON; + +StateVariableDefinitionValue = EQUAL + Expression; + +StateVariableAttributes = StateVariableAttribute+; + +StateVariableAttribute = OverrideSpecifier + | CONSTANT_KEYWORD + | INTERNAL_KEYWORD + | PRIVATE_KEYWORD + | PUBLIC_KEYWORD + | IMMUTABLE_KEYWORD; (* Introduced in 0.6.5 *) + +(* 2.8. Functions: *) + +FunctionDefinition = FUNCTION_KEYWORD + FunctionName + ParametersDeclaration + FunctionAttributes? + ReturnsDeclaration? + FunctionBody; + +FunctionName = IDENTIFIER + | FALLBACK_KEYWORD + | RECEIVE_KEYWORD; + +ParametersDeclaration = OPEN_PAREN + Parameters? + CLOSE_PAREN; + +Parameters = Parameter (COMMA Parameter)*; + +Parameter = TypeName + StorageLocation? + IDENTIFIER?; + +FunctionAttributes = FunctionAttribute+; + +FunctionAttribute = ModifierInvocation + | OverrideSpecifier + | CONSTANT_KEYWORD (* Deprecated in 0.5.0 *) + | EXTERNAL_KEYWORD + | INTERNAL_KEYWORD + | PAYABLE_KEYWORD + | PRIVATE_KEYWORD + | PUBLIC_KEYWORD + | PURE_KEYWORD + | VIEW_KEYWORD + | VIRTUAL_KEYWORD; (* Introduced in 0.6.0 *) + +OverrideSpecifier = OVERRIDE_KEYWORD + OverridePathsDeclaration?; + +OverridePathsDeclaration = OPEN_PAREN + OverridePaths + CLOSE_PAREN; + +OverridePaths = IdentifierPath (COMMA IdentifierPath)*; + +ReturnsDeclaration = RETURNS_KEYWORD + ParametersDeclaration; + +FunctionBody = Block + | SEMICOLON; + +(* Introduced in 0.4.22 *) +ConstructorDefinition = CONSTRUCTOR_KEYWORD + ParametersDeclaration + ConstructorAttributes? + Block; + +(* Introduced in 0.4.22 *) +ConstructorAttributes = ConstructorAttribute+; + +(* Introduced in 0.4.22 *) +ConstructorAttribute = ModifierInvocation + | INTERNAL_KEYWORD + | PAYABLE_KEYWORD + | PUBLIC_KEYWORD; + +(* Deprecated in 0.6.0 *) +UnnamedFunctionDefinition = FUNCTION_KEYWORD + ParametersDeclaration + UnnamedFunctionAttributes? + FunctionBody; + +(* Deprecated in 0.6.0 *) +UnnamedFunctionAttributes = UnnamedFunctionAttribute+; + +(* Deprecated in 0.6.0 *) +UnnamedFunctionAttribute = ModifierInvocation + | OverrideSpecifier + | EXTERNAL_KEYWORD + | PAYABLE_KEYWORD + | PURE_KEYWORD + | VIEW_KEYWORD; + +(* Introduced in 0.6.0 *) +FallbackFunctionDefinition = FALLBACK_KEYWORD + ParametersDeclaration + FallbackFunctionAttributes? + ReturnsDeclaration? + FunctionBody; + +(* Introduced in 0.6.0 *) +FallbackFunctionAttributes = FallbackFunctionAttribute+; + +(* Introduced in 0.6.0 *) +FallbackFunctionAttribute = ModifierInvocation + | OverrideSpecifier + | EXTERNAL_KEYWORD + | PAYABLE_KEYWORD + | PURE_KEYWORD + | VIEW_KEYWORD + | VIRTUAL_KEYWORD; + +(* Introduced in 0.6.0 *) +ReceiveFunctionDefinition = RECEIVE_KEYWORD + ParametersDeclaration + ReceiveFunctionAttributes? + FunctionBody; + +(* Introduced in 0.6.0 *) +ReceiveFunctionAttributes = ReceiveFunctionAttribute+; + +(* Introduced in 0.6.0 *) +ReceiveFunctionAttribute = ModifierInvocation + | OverrideSpecifier + | EXTERNAL_KEYWORD + | PAYABLE_KEYWORD + | VIRTUAL_KEYWORD; + +(* 2.9. Modifiers: *) + +ModifierDefinition = MODIFIER_KEYWORD + IDENTIFIER + ParametersDeclaration? + ModifierAttributes? + FunctionBody; + +ModifierAttributes = ModifierAttribute+; + +ModifierAttribute = OverrideSpecifier + | VIRTUAL_KEYWORD; (* Introduced in 0.6.0 *) + +ModifierInvocation = IdentifierPath + ArgumentsDeclaration?; + +(* 2.10. Events: *) + +EventDefinition = EVENT_KEYWORD + IDENTIFIER + EventParametersDeclaration + ANONYMOUS_KEYWORD? + SEMICOLON; + +EventParametersDeclaration = OPEN_PAREN + EventParameters? + CLOSE_PAREN; + +EventParameters = EventParameter (COMMA EventParameter)*; + +EventParameter = TypeName + INDEXED_KEYWORD? + IDENTIFIER?; + +(* 2.11. User Defined Value Types: *) + +(* Introduced in 0.8.8 *) +UserDefinedValueTypeDefinition = TYPE_KEYWORD + IDENTIFIER + IS_KEYWORD + ElementaryType + SEMICOLON; + +(* 2.12. Errors: *) + +(* Introduced in 0.8.4 *) +ErrorDefinition = ERROR_KEYWORD + IDENTIFIER + ErrorParametersDeclaration + SEMICOLON; + +(* Introduced in 0.8.4 *) +ErrorParametersDeclaration = OPEN_PAREN + ErrorParameters? + CLOSE_PAREN; + +(* Introduced in 0.8.4 *) +ErrorParameters = ErrorParameter (COMMA ErrorParameter)*; + +(* Introduced in 0.8.4 *) +ErrorParameter = TypeName + IDENTIFIER?; + +(* + * 3. Types: + *) + +(* 3.1. Advanced Types: *) + +TypeName = ArrayTypeName + | FunctionType + | MappingType + | ElementaryType + | IdentifierPath; + +FunctionType = FUNCTION_KEYWORD + ParametersDeclaration + FunctionTypeAttributes? + ReturnsDeclaration?; + +FunctionTypeAttributes = FunctionTypeAttribute+; + +FunctionTypeAttribute = INTERNAL_KEYWORD + | EXTERNAL_KEYWORD + | PRIVATE_KEYWORD + | PUBLIC_KEYWORD + | PURE_KEYWORD + | VIEW_KEYWORD + | PAYABLE_KEYWORD; + +MappingType = MAPPING_KEYWORD + OPEN_PAREN + MappingKey + EQUAL_GREATER_THAN + MappingValue + CLOSE_PAREN; + +MappingKey = MappingKeyType + IDENTIFIER?; (* Introduced in 0.8.18 *) + +MappingKeyType = ElementaryType + | IdentifierPath; + +MappingValue = TypeName + IDENTIFIER?; (* Introduced in 0.8.18 *) + +(* 3.2. Elementary Types: *) + +ElementaryType = BOOL_KEYWORD + | BYTE_KEYWORD (* Deprecated in 0.8.0 *) + | STRING_KEYWORD + | AddressType + | PAYABLE_KEYWORD + | BYTES_KEYWORD + | INT_KEYWORD + | UINT_KEYWORD + | FIXED_KEYWORD + | UFIXED_KEYWORD; + +AddressType = ADDRESS_KEYWORD + PAYABLE_KEYWORD?; + +(* + * 4. Statements: + *) + +(* 4.1. Blocks: *) + +Block = OPEN_BRACE + Statements? + CLOSE_BRACE; + +Statements = Statement+; + +Statement = ExpressionStatement + | VariableDeclarationStatement + | TupleDeconstructionStatement + | IfStatement + | ForStatement + | WhileStatement + | DoWhileStatement + | ContinueStatement + | BreakStatement + | DeleteStatement + | ReturnStatement + | ThrowStatement (* Deprecated in 0.5.0 *) + | EmitStatement (* Introduced in 0.4.21 *) + | TryStatement (* Introduced in 0.6.0 *) + | RevertStatement (* Introduced in 0.8.4 *) + | AssemblyStatement + | Block + | UncheckedBlock; (* Introduced in 0.8.0 *) + +(* Introduced in 0.8.0 *) +UncheckedBlock = UNCHECKED_KEYWORD + Block; + +ExpressionStatement = Expression + SEMICOLON; + +AssemblyStatement = ASSEMBLY_KEYWORD + ASCII_STRING_LITERAL? + AssemblyFlagsDeclaration? + YulBlock; + +AssemblyFlagsDeclaration = OPEN_PAREN + AssemblyFlags + CLOSE_PAREN; + +AssemblyFlags = ASCII_STRING_LITERAL (COMMA ASCII_STRING_LITERAL)*; + +(* 4.2. Declaration Statements: *) + +TupleDeconstructionStatement = OPEN_PAREN + TupleDeconstructionElements + CLOSE_PAREN + EQUAL + Expression + SEMICOLON; + +TupleDeconstructionElements = TupleDeconstructionElement (COMMA TupleDeconstructionElement)*; + +TupleDeconstructionElement = TupleMember?; + +TupleMember = TypedTupleMember + | UntypedTupleMember; + +TypedTupleMember = TypeName + StorageLocation? + IDENTIFIER; + +UntypedTupleMember = StorageLocation? + IDENTIFIER; + +VariableDeclarationStatement = VariableDeclarationType + StorageLocation? + IDENTIFIER + VariableDeclarationValue? + SEMICOLON; + +VariableDeclarationType = TypeName + | VAR_KEYWORD; (* Deprecated in 0.5.0 *) + +VariableDeclarationValue = EQUAL + Expression; + +StorageLocation = MEMORY_KEYWORD + | STORAGE_KEYWORD + | CALL_DATA_KEYWORD; (* Introduced in 0.5.0 *) + +(* 4.3. Control Statements: *) + +IfStatement = IF_KEYWORD + OPEN_PAREN + Expression + CLOSE_PAREN + Statement + ElseBranch?; + +ElseBranch = ELSE_KEYWORD + Statement; + +ForStatement = FOR_KEYWORD + OPEN_PAREN + ForStatementInitialization + ForStatementCondition + Expression? + CLOSE_PAREN + Statement; + +ForStatementInitialization = ExpressionStatement + | VariableDeclarationStatement + | TupleDeconstructionStatement + | SEMICOLON; + +ForStatementCondition = ExpressionStatement + | SEMICOLON; + +WhileStatement = WHILE_KEYWORD + OPEN_PAREN + Expression + CLOSE_PAREN + Statement; + +DoWhileStatement = DO_KEYWORD + Statement + WHILE_KEYWORD + OPEN_PAREN + Expression + CLOSE_PAREN + SEMICOLON; + +ContinueStatement = CONTINUE_KEYWORD + SEMICOLON; + +BreakStatement = BREAK_KEYWORD + SEMICOLON; + +ReturnStatement = RETURN_KEYWORD + Expression? + SEMICOLON; + +(* Introduced in 0.4.21 *) +EmitStatement = EMIT_KEYWORD + IdentifierPath + ArgumentsDeclaration + SEMICOLON; + +DeleteStatement = DELETE_KEYWORD + Expression + SEMICOLON; + +(* 4.4. Error Handling: *) + +(* Introduced in 0.6.0 *) +TryStatement = TRY_KEYWORD + Expression + ReturnsDeclaration? + Block + CatchClauses; + +(* Introduced in 0.6.0 *) +CatchClauses = CatchClause+; + +(* Introduced in 0.6.0 *) +CatchClause = CATCH_KEYWORD + CatchClauseError? + Block; + +(* Introduced in 0.6.0 *) +CatchClauseError = IDENTIFIER? + ParametersDeclaration; + +(* Introduced in 0.8.4 *) +RevertStatement = REVERT_KEYWORD + IdentifierPath? + ArgumentsDeclaration + SEMICOLON; + +(* Deprecated in 0.5.0 *) +ThrowStatement = THROW_KEYWORD + SEMICOLON; + +(* + * 5. Expressions: + *) + +(* 5.1. Base Expressions: *) + +Expression = AssignmentExpression + | ConditionalExpression + | OrExpression + | AndExpression + | EqualityExpression + | ComparisonExpression + | BitwiseOrExpression + | BitwiseXorExpression + | BitwiseAndExpression + | ShiftExpression + | AdditiveExpression + | MultiplicativeExpression + | ExponentiationExpression + | PostfixExpression + | PrefixExpression + | FunctionCallExpression + | MemberAccessExpression + | IndexAccessExpression + | NewExpression + | TupleExpression + | TypeExpression (* Introduced in 0.5.3 *) + | ArrayExpression + | HexNumberExpression + | DecimalNumberExpression + | StringExpression + | ElementaryType + | TRUE_KEYWORD + | FALSE_KEYWORD + | IDENTIFIER; + +MemberAccess = IDENTIFIER + | ADDRESS_KEYWORD; + +IndexAccessEnd = COLON + Expression?; + +(* 5.2. Function Calls: *) + +(* Introduced in 0.6.2 *) +FunctionCallOptions = NamedArgumentGroups (* Introduced in 0.6.2 and deprecated in 0.8.0. *) + | NamedArgumentGroup; (* Introduced in 0.8.0 *) + +ArgumentsDeclaration = PositionalArgumentsDeclaration + | NamedArgumentsDeclaration; + +PositionalArgumentsDeclaration = OPEN_PAREN + PositionalArguments? + CLOSE_PAREN; + +PositionalArguments = Expression (COMMA Expression)*; + +NamedArgumentsDeclaration = OPEN_PAREN + NamedArgumentGroup? + CLOSE_PAREN; + +(* Introduced in 0.6.2 and deprecated in 0.8.0. *) +NamedArgumentGroups = NamedArgumentGroup+; + +NamedArgumentGroup = OPEN_BRACE + NamedArguments? + CLOSE_BRACE; + +NamedArguments = NamedArgument (COMMA NamedArgument)*; + +NamedArgument = IDENTIFIER + COLON + Expression; + +(* 5.3. Primary Expressions: *) + +(* Introduced in 0.5.3 *) +TypeExpression = TYPE_KEYWORD + OPEN_PAREN + TypeName + CLOSE_PAREN; + +NewExpression = NEW_KEYWORD + TypeName; + +TupleExpression = OPEN_PAREN + TupleValues + CLOSE_PAREN; + +TupleValues = TupleValue (COMMA TupleValue)*; + +TupleValue = Expression?; + +ArrayExpression = OPEN_BRACKET + ArrayValues + CLOSE_BRACKET; + +ArrayValues = Expression (COMMA Expression)*; + +(* 5.4. Numbers: *) + +HexNumberExpression = HEX_LITERAL + NumberUnit?; (* Deprecated in 0.5.0 *) + +DecimalNumberExpression = DECIMAL_LITERAL + NumberUnit?; + +HEX_LITERAL = "0x" «HEX_CHARACTER»+ ("_" «HEX_CHARACTER»+)*; + +(* Deprecated in 0.5.0 *) +HEX_LITERAL = "0X" «HEX_CHARACTER»+ ("_" «HEX_CHARACTER»+)*; + +DECIMAL_LITERAL = «DECIMAL_DIGITS» «DECIMAL_EXPONENT»?; + +(* Deprecated in 0.5.0 *) +DECIMAL_LITERAL = «DECIMAL_DIGITS» "." «DECIMAL_EXPONENT»?; + +DECIMAL_LITERAL = "." «DECIMAL_DIGITS» «DECIMAL_EXPONENT»?; + +DECIMAL_LITERAL = «DECIMAL_DIGITS» "." «DECIMAL_DIGITS» «DECIMAL_EXPONENT»?; + +«DECIMAL_DIGITS» = ("0"…"9")+ ("_" ("0"…"9")+)*; + +«DECIMAL_EXPONENT» = ("e" | "E") "-"? «DECIMAL_DIGITS»; + +NumberUnit = WEI_KEYWORD + | GWEI_KEYWORD (* Introduced in 0.6.11 *) + | SZABO_KEYWORD (* Deprecated in 0.7.0 *) + | FINNEY_KEYWORD (* Deprecated in 0.7.0 *) + | ETHER_KEYWORD + | SECONDS_KEYWORD + | MINUTES_KEYWORD + | HOURS_KEYWORD + | DAYS_KEYWORD + | WEEKS_KEYWORD + | YEARS_KEYWORD; (* Deprecated in 0.5.0 *) + +(* 5.5. Strings: *) + +StringExpression = HexStringLiterals + | AsciiStringLiterals + | UnicodeStringLiterals; (* Introduced in 0.7.0 *) + +HexStringLiterals = HEX_STRING_LITERAL+; + +HEX_STRING_LITERAL = «SINGLE_QUOTED_HEX_STRING_LITERAL»; + +HEX_STRING_LITERAL = «DOUBLE_QUOTED_HEX_STRING_LITERAL»; + +«SINGLE_QUOTED_HEX_STRING_LITERAL» = "hex'" «HEX_STRING_CONTENTS»? "'"; + +«DOUBLE_QUOTED_HEX_STRING_LITERAL» = 'hex"' «HEX_STRING_CONTENTS»? '"'; + +«HEX_STRING_CONTENTS» = «HEX_CHARACTER» «HEX_CHARACTER» ("_"? «HEX_CHARACTER» «HEX_CHARACTER»)*; + +«HEX_CHARACTER» = ("0"…"9") | ("a"…"f") | ("A"…"F"); + +AsciiStringLiterals = ASCII_STRING_LITERAL+; + +ASCII_STRING_LITERAL = «SINGLE_QUOTED_ASCII_STRING_LITERAL»; + +ASCII_STRING_LITERAL = «DOUBLE_QUOTED_ASCII_STRING_LITERAL»; + +«SINGLE_QUOTED_ASCII_STRING_LITERAL» = "'" («ESCAPE_SEQUENCE» | (" "…"&") | ("("…"[") | ("]"…"~"))* "'"; + +«DOUBLE_QUOTED_ASCII_STRING_LITERAL» = '"' («ESCAPE_SEQUENCE» | (" "…"!") | ("#"…"[") | ("]"…"~"))* '"'; + +(* Introduced in 0.7.0 *) +UnicodeStringLiterals = UNICODE_STRING_LITERAL+; + +(* Introduced in 0.7.0 *) +UNICODE_STRING_LITERAL = «SINGLE_QUOTED_UNICODE_STRING_LITERAL»; + +(* Introduced in 0.7.0 *) +UNICODE_STRING_LITERAL = «DOUBLE_QUOTED_UNICODE_STRING_LITERAL»; + +(* Introduced in 0.7.0 *) +«SINGLE_QUOTED_UNICODE_STRING_LITERAL» = "unicode'" («ESCAPE_SEQUENCE» | !("'" "\\" "\r" "\n"))* "'"; + +(* Introduced in 0.7.0 *) +«DOUBLE_QUOTED_UNICODE_STRING_LITERAL» = 'unicode"' («ESCAPE_SEQUENCE» | !('"' "\\" "\r" "\n"))* '"'; + +«ESCAPE_SEQUENCE» = "\\" («ASCII_ESCAPE» | «HEX_BYTE_ESCAPE» | «UNICODE_ESCAPE»); + +«ASCII_ESCAPE» = "n" | "r" | "t" | "'" | '"' | "\\" | "\n" | "\r"; + +«HEX_BYTE_ESCAPE» = "x" «HEX_CHARACTER» «HEX_CHARACTER»; + +«UNICODE_ESCAPE» = "u" «HEX_CHARACTER» «HEX_CHARACTER» «HEX_CHARACTER» «HEX_CHARACTER»; + +(* 5.6. Identifiers: *) + +IdentifierPath = IDENTIFIER (PERIOD IDENTIFIER)*; + +IDENTIFIER = «RAW_IDENTIFIER»; + +«RAW_IDENTIFIER» = «IDENTIFIER_START» «IDENTIFIER_PART»*; + +«IDENTIFIER_START» = "_" | "$" | ("a"…"z") | ("A"…"Z"); + +«IDENTIFIER_PART» = «IDENTIFIER_START» | ("0"…"9"); + +(* + * 6. Yul: + *) + +(* 6.1. Yul Statements: *) + +YulBlock = OPEN_BRACE + YulStatements? + CLOSE_BRACE; + +YulStatements = YulStatement+; + +YulStatement = YulBlock + | YulFunctionDefinition + | YulVariableDeclarationStatement + | YulAssignmentStatement + | YulIfStatement + | YulForStatement + | YulSwitchStatement + | YulLeaveStatement (* Introduced in 0.6.0 *) + | YulBreakStatement + | YulContinueStatement + | YulExpression; + +YulFunctionDefinition = YUL_FUNCTION_KEYWORD + YUL_IDENTIFIER + YulParametersDeclaration + YulReturnsDeclaration? + YulBlock; + +YulParametersDeclaration = OPEN_PAREN + YulParameters? + CLOSE_PAREN; + +YulParameters = YUL_IDENTIFIER (COMMA YUL_IDENTIFIER)*; + +YulReturnsDeclaration = MINUS_GREATER_THAN + YulReturnVariables; + +YulReturnVariables = YUL_IDENTIFIER (COMMA YUL_IDENTIFIER)*; + +YulVariableDeclarationStatement = YUL_LET_KEYWORD + YulIdentifierPaths + YulVariableDeclarationValue?; + +YulVariableDeclarationValue = COLON_EQUAL + YulExpression; + +YulAssignmentStatement = YulIdentifierPaths + COLON_EQUAL + YulExpression; + +YulIfStatement = YUL_IF_KEYWORD + YulExpression + YulBlock; + +(* Introduced in 0.6.0 *) +YulLeaveStatement = YUL_LEAVE_KEYWORD; + +YulBreakStatement = YUL_BREAK_KEYWORD; + +YulContinueStatement = YUL_CONTINUE_KEYWORD; + +YulForStatement = YUL_FOR_KEYWORD + YulBlock + YulExpression + YulBlock + YulBlock; + +YulSwitchStatement = YUL_SWITCH_KEYWORD + YulExpression + YulSwitchCases; + +YulSwitchCases = YulSwitchCase+; + +YulSwitchCase = YulDefaultCase + | YulValueCase; + +YulDefaultCase = YUL_DEFAULT_KEYWORD + YulBlock; + +YulValueCase = YUL_CASE_KEYWORD + YulLiteral + YulBlock; + +(* 6.2. Yul Expressions: *) + +YulExpression = YulFunctionCallExpression + | YulLiteral + | YulIdentifierPath; + +YulArguments = YulExpression (COMMA YulExpression)*; + +YulIdentifierPaths = YulIdentifierPath (COMMA YulIdentifierPath)*; + +YulIdentifierPath = YUL_IDENTIFIER (PERIOD YUL_IDENTIFIER)*; + +YUL_IDENTIFIER = «RAW_IDENTIFIER»; + +YulLiteral = YUL_TRUE_KEYWORD + | YUL_FALSE_KEYWORD + | YUL_DECIMAL_LITERAL + | YUL_HEX_LITERAL + | HEX_STRING_LITERAL + | ASCII_STRING_LITERAL; + +YUL_DECIMAL_LITERAL = "0" | (("1"…"9") ("0"…"9")*); + +YUL_HEX_LITERAL = "0x" «HEX_CHARACTER»+; + +(* 6.3. Keywords: *) + +(* Reserved until 0.7.1 *) +YUL_ABSTRACT_KEYWORD = "abstract"; + +YUL_ADDRESS_KEYWORD = "address"; + +(* Reserved until 0.7.1 *) +YUL_AFTER_KEYWORD = "after"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_ALIAS_KEYWORD = "alias"; + +(* Reserved until 0.7.1 *) +YUL_ANONYMOUS_KEYWORD = "anonymous"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_APPLY_KEYWORD = "apply"; + +(* Reserved until 0.7.1 *) +YUL_AS_KEYWORD = "as"; + +(* Reserved until 0.7.1 *) +YUL_ASSEMBLY_KEYWORD = "assembly"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_AUTO_KEYWORD = "auto"; + +(* Reserved until 0.5.10 *) +YUL_BOOL_KEYWORD = "bool"; + +YUL_BREAK_KEYWORD = "break"; + +YUL_BYTE_KEYWORD = "byte"; + +(* Reserved until 0.7.1 *) +YUL_BYTES_KEYWORD = "bytes" ("1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "16" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "24" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "32")?; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_CALL_DATA_KEYWORD = "calldata"; + +YUL_CASE_KEYWORD = "case"; + +(* Reserved until 0.7.1 *) +YUL_CATCH_KEYWORD = "catch"; + +(* Reserved until 0.7.1 *) +YUL_CONSTANT_KEYWORD = "constant"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_CONSTRUCTOR_KEYWORD = "constructor"; + +YUL_CONTINUE_KEYWORD = "continue"; + +(* Reserved until 0.7.1 *) +YUL_CONTRACT_KEYWORD = "contract"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_COPY_OF_KEYWORD = "copyof"; + +(* Reserved until 0.7.1 *) +YUL_DAYS_KEYWORD = "days"; + +YUL_DEFAULT_KEYWORD = "default"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_DEFINE_KEYWORD = "define"; + +(* Reserved until 0.7.1 *) +YUL_DELETE_KEYWORD = "delete"; + +(* Reserved until 0.7.1 *) +YUL_DO_KEYWORD = "do"; + +(* Reserved until 0.7.1 *) +YUL_ELSE_KEYWORD = "else"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_EMIT_KEYWORD = "emit"; + +(* Reserved until 0.7.1 *) +YUL_ENUM_KEYWORD = "enum"; + +(* Reserved until 0.7.1 *) +YUL_ETHER_KEYWORD = "ether"; + +(* Reserved until 0.7.1 *) +YUL_EVENT_KEYWORD = "event"; + +(* Reserved until 0.7.1 *) +YUL_EXTERNAL_KEYWORD = "external"; + +(* Reserved from 0.6.0 until 0.7.1 *) +YUL_FALLBACK_KEYWORD = "fallback"; + +YUL_FALSE_KEYWORD = "false"; + +(* Reserved until 0.7.1 *) +YUL_FINAL_KEYWORD = "final"; + +(* Reserved until 0.7.0 *) +YUL_FINNEY_KEYWORD = "finney"; + +(* Reserved until 0.7.1 *) +YUL_FIXED_KEYWORD = "fixed"; + +(* Reserved until 0.7.1 *) +YUL_FIXED_KEYWORD = "fixed" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176") "x" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80"); + +(* Reserved until 0.7.1 *) +YUL_FIXED_KEYWORD = "fixed" ("184x8" | "184x16" | "184x24" | "184x32" | "184x40" | "184x48" | "184x56" | "184x64" | "184x72" | "192x8" | "192x16" | "192x24" | "192x32" | "192x40" | "192x48" | "192x56" | "192x64" | "200x8" | "200x16" | "200x24" | "200x32" | "200x40" | "200x48" | "200x56" | "208x8" | "208x16" | "208x24" | "208x32" | "208x40" | "208x48" | "216x8" | "216x16" | "216x24" | "216x32" | "216x40" | "224x8" | "224x16" | "224x24" | "224x32" | "232x8" | "232x16" | "232x24" | "240x8" | "240x16" | "248x8"); + +(* Reserved from 0.4.14 until 0.7.1 *) +YUL_FIXED_KEYWORD = "fixed" ("184x80" | "192x72" | "192x80" | "200x64" | "200x72" | "200x80" | "208x56" | "208x64" | "208x72" | "208x80" | "216x48" | "216x56" | "216x64" | "216x72" | "216x80" | "224x40" | "224x48" | "224x56" | "224x64" | "224x72" | "224x80" | "232x32" | "232x40" | "232x48" | "232x56" | "232x64" | "232x72" | "232x80" | "240x24" | "240x32" | "240x40" | "240x48" | "240x56" | "240x64" | "240x72" | "240x80" | "248x16" | "248x24" | "248x32" | "248x40" | "248x48" | "248x56" | "248x64" | "248x72" | "248x80" | "256x8" | "256x16" | "256x24" | "256x32" | "256x40" | "256x48" | "256x56" | "256x64" | "256x72" | "256x80"); + +(* Reserved from 0.4.14 until 0.7.1 *) +YUL_FIXED_KEYWORD = "fixed" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176" | "184" | "192" | "200" | "208" | "216" | "224" | "232" | "240" | "248" | "256") "x" ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "49" | "50" | "51" | "52" | "53" | "54" | "55" | "57" | "58" | "59" | "60" | "61" | "62" | "63" | "65" | "66" | "67" | "68" | "69" | "70" | "71" | "73" | "74" | "75" | "76" | "77" | "78" | "79"); + +YUL_FOR_KEYWORD = "for"; + +YUL_FUNCTION_KEYWORD = "function"; + +(* Reserved from 0.7.0 until 0.7.1 *) +YUL_GWEI_KEYWORD = "gwei"; + +YUL_HEX_KEYWORD = "hex"; + +(* Reserved until 0.7.1 *) +YUL_HOURS_KEYWORD = "hours"; + +YUL_IF_KEYWORD = "if"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_IMMUTABLE_KEYWORD = "immutable"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_IMPLEMENTS_KEYWORD = "implements"; + +(* Reserved until 0.7.1 *) +YUL_IMPORT_KEYWORD = "import"; + +(* Reserved until 0.7.1 *) +YUL_INDEXED_KEYWORD = "indexed"; + +(* Reserved until 0.6.8 *) +YUL_IN_KEYWORD = "in"; + +(* Reserved until 0.7.1 *) +YUL_INLINE_KEYWORD = "inline"; + +(* Reserved until 0.7.1 *) +YUL_INTERFACE_KEYWORD = "interface"; + +(* Reserved until 0.7.1 *) +YUL_INTERNAL_KEYWORD = "internal"; + +(* Reserved until 0.7.1 *) +YUL_INT_KEYWORD = "int" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176" | "184" | "192" | "200" | "208" | "216" | "224" | "232" | "240" | "248" | "256")?; + +(* Reserved until 0.7.1 *) +YUL_IS_KEYWORD = "is"; + +(* Introduced in 0.6.0 *) +(* Reserved in 0.7.1 *) +YUL_LEAVE_KEYWORD = "leave"; + +YUL_LET_KEYWORD = "let"; + +(* Reserved until 0.7.1 *) +YUL_LIBRARY_KEYWORD = "library"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_MACRO_KEYWORD = "macro"; + +(* Reserved until 0.7.1 *) +YUL_MAPPING_KEYWORD = "mapping"; + +(* Reserved until 0.7.1 *) +YUL_MATCH_KEYWORD = "match"; + +(* Reserved until 0.7.1 *) +YUL_MEMORY_KEYWORD = "memory"; + +(* Reserved until 0.7.1 *) +YUL_MINUTES_KEYWORD = "minutes"; + +(* Reserved until 0.7.1 *) +YUL_MODIFIER_KEYWORD = "modifier"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_MUTABLE_KEYWORD = "mutable"; + +(* Reserved until 0.7.1 *) +YUL_NEW_KEYWORD = "new"; + +(* Reserved until 0.7.1 *) +YUL_NULL_KEYWORD = "null"; + +(* Reserved until 0.7.1 *) +YUL_OF_KEYWORD = "of"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_OVERRIDE_KEYWORD = "override"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_PARTIAL_KEYWORD = "partial"; + +(* Reserved until 0.7.1 *) +YUL_PAYABLE_KEYWORD = "payable"; + +(* Reserved until 0.7.1 *) +YUL_PRAGMA_KEYWORD = "pragma"; + +(* Reserved until 0.7.1 *) +YUL_PRIVATE_KEYWORD = "private"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_PROMISE_KEYWORD = "promise"; + +(* Reserved until 0.7.1 *) +YUL_PUBLIC_KEYWORD = "public"; + +(* Reserved until 0.7.1 *) +YUL_PURE_KEYWORD = "pure"; + +(* Reserved from 0.6.0 until 0.7.1 *) +YUL_RECEIVE_KEYWORD = "receive"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_REFERENCE_KEYWORD = "reference"; + +(* Reserved until 0.7.1 *) +YUL_RELOCATABLE_KEYWORD = "relocatable"; + +YUL_RETURN_KEYWORD = "return"; + +(* Reserved until 0.7.1 *) +YUL_RETURNS_KEYWORD = "returns"; + +YUL_REVERT_KEYWORD = "revert"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_SEALED_KEYWORD = "sealed"; + +(* Reserved until 0.7.1 *) +YUL_SECONDS_KEYWORD = "seconds"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_SIZE_OF_KEYWORD = "sizeof"; + +(* Reserved until 0.7.1 *) +YUL_STATIC_KEYWORD = "static"; + +(* Reserved until 0.7.1 *) +YUL_STORAGE_KEYWORD = "storage"; + +(* Reserved until 0.7.1 *) +YUL_STRING_KEYWORD = "string"; + +(* Reserved until 0.7.1 *) +YUL_STRUCT_KEYWORD = "struct"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_SUPPORTS_KEYWORD = "supports"; + +YUL_SWITCH_KEYWORD = "switch"; + +(* Reserved until 0.7.0 *) +YUL_SZABO_KEYWORD = "szabo"; + +(* Reserved until 0.7.1 *) +YUL_THROW_KEYWORD = "throw"; + +YUL_TRUE_KEYWORD = "true"; + +(* Reserved until 0.7.1 *) +YUL_TRY_KEYWORD = "try"; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_TYPE_DEF_KEYWORD = "typedef"; + +(* Reserved until 0.7.1 *) +YUL_TYPE_KEYWORD = "type"; + +(* Reserved until 0.7.1 *) +YUL_TYPE_OF_KEYWORD = "typeof"; + +(* Reserved until 0.7.1 *) +YUL_UFIXED_KEYWORD = "ufixed"; + +(* Reserved until 0.7.1 *) +YUL_UFIXED_KEYWORD = "ufixed" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176") "x" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80"); + +(* Reserved until 0.7.1 *) +YUL_UFIXED_KEYWORD = "ufixed" ("184x8" | "184x16" | "184x24" | "184x32" | "184x40" | "184x48" | "184x56" | "184x64" | "184x72" | "192x8" | "192x16" | "192x24" | "192x32" | "192x40" | "192x48" | "192x56" | "192x64" | "200x8" | "200x16" | "200x24" | "200x32" | "200x40" | "200x48" | "200x56" | "208x8" | "208x16" | "208x24" | "208x32" | "208x40" | "208x48" | "216x8" | "216x16" | "216x24" | "216x32" | "216x40" | "224x8" | "224x16" | "224x24" | "224x32" | "232x8" | "232x16" | "232x24" | "240x8" | "240x16" | "248x8"); + +(* Reserved from 0.4.14 until 0.7.1 *) +YUL_UFIXED_KEYWORD = "ufixed" ("184x80" | "192x72" | "192x80" | "200x64" | "200x72" | "200x80" | "208x56" | "208x64" | "208x72" | "208x80" | "216x48" | "216x56" | "216x64" | "216x72" | "216x80" | "224x40" | "224x48" | "224x56" | "224x64" | "224x72" | "224x80" | "232x32" | "232x40" | "232x48" | "232x56" | "232x64" | "232x72" | "232x80" | "240x24" | "240x32" | "240x40" | "240x48" | "240x56" | "240x64" | "240x72" | "240x80" | "248x16" | "248x24" | "248x32" | "248x40" | "248x48" | "248x56" | "248x64" | "248x72" | "248x80" | "256x8" | "256x16" | "256x24" | "256x32" | "256x40" | "256x48" | "256x56" | "256x64" | "256x72" | "256x80"); + +(* Reserved from 0.4.14 until 0.7.1 *) +YUL_UFIXED_KEYWORD = "ufixed" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176" | "184" | "192" | "200" | "208" | "216" | "224" | "232" | "240" | "248" | "256") "x" ("0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "9" | "10" | "11" | "12" | "13" | "14" | "15" | "17" | "18" | "19" | "20" | "21" | "22" | "23" | "25" | "26" | "27" | "28" | "29" | "30" | "31" | "33" | "34" | "35" | "36" | "37" | "38" | "39" | "41" | "42" | "43" | "44" | "45" | "46" | "47" | "49" | "50" | "51" | "52" | "53" | "54" | "55" | "57" | "58" | "59" | "60" | "61" | "62" | "63" | "65" | "66" | "67" | "68" | "69" | "70" | "71" | "73" | "74" | "75" | "76" | "77" | "78" | "79"); + +(* Reserved until 0.7.1 *) +YUL_UINT_KEYWORD = "uint" ("8" | "16" | "24" | "32" | "40" | "48" | "56" | "64" | "72" | "80" | "88" | "96" | "104" | "112" | "120" | "128" | "136" | "144" | "152" | "160" | "168" | "176" | "184" | "192" | "200" | "208" | "216" | "224" | "232" | "240" | "248" | "256")?; + +(* Reserved from 0.5.0 until 0.7.1 *) +YUL_UNCHECKED_KEYWORD = "unchecked"; + +(* Reserved until 0.7.1 *) +YUL_USING_KEYWORD = "using"; + +(* Reserved until 0.6.5 *) +YUL_VAR_KEYWORD = "var"; + +(* Reserved until 0.7.1 *) +YUL_VIEW_KEYWORD = "view"; + +(* Reserved from 0.6.0 until 0.7.1 *) +YUL_VIRTUAL_KEYWORD = "virtual"; + +(* Reserved until 0.7.1 *) +YUL_WEEKS_KEYWORD = "weeks"; + +(* Reserved until 0.7.1 *) +YUL_WEI_KEYWORD = "wei"; + +(* Reserved until 0.7.1 *) +YUL_WHILE_KEYWORD = "while"; + +(* Reserved until 0.7.1 *) +YUL_YEARS_KEYWORD = "years"; +