From 2d7277234702b63348a2f95d944c49293c4bc7a8 Mon Sep 17 00:00:00 2001 From: Igor Matuszewski Date: Fri, 5 Apr 2024 00:45:34 +0200 Subject: [PATCH] fix: Allow duplicate `indexed` event attribute until 0.8.18 --- .../inputs/language/src/definition.rs | 19 +++++++- .../slang_solidity/src/generated/kinds.rs | 4 ++ .../slang_solidity/src/generated/language.rs | 48 ++++++++++++++++--- .../generated/napi_interface/ast_selectors.rs | 27 ++++++++++- .../cst_output/generated/event_definition.rs | 5 ++ .../package/src/ast/generated/ast_types.ts | 47 ++++++++++++++++-- .../npm/package/src/generated/index.d.ts | 4 ++ .../outputs/spec/generated/grammar.ebnf | 8 +++- .../public/02-definitions/10-events.md | 14 +++++- .../generated/0.4.11-success.yml | 10 ++-- .../generated/0.4.11-success.yml | 34 +++++++++++++ .../generated/0.8.18-failure.yml | 39 +++++++++++++++ .../EventDefinition/indexed_indexed/input.sol | 3 ++ .../transfer/generated/0.4.11-success.yml | 10 ++-- 14 files changed, 249 insertions(+), 23 deletions(-) create mode 100644 crates/solidity/testing/snapshots/cst_output/EventDefinition/indexed_indexed/generated/0.4.11-success.yml create mode 100644 crates/solidity/testing/snapshots/cst_output/EventDefinition/indexed_indexed/generated/0.8.18-failure.yml create mode 100644 crates/solidity/testing/snapshots/cst_output/EventDefinition/indexed_indexed/input.sol diff --git a/crates/solidity/inputs/language/src/definition.rs b/crates/solidity/inputs/language/src/definition.rs index afc260a449..0ace0b7613 100644 --- a/crates/solidity/inputs/language/src/definition.rs +++ b/crates/solidity/inputs/language/src/definition.rs @@ -2579,9 +2579,26 @@ codegen_language_macros::compile!(Language( name = EventParameter, fields = ( type_name = Required(TypeName), - indexed_keyword = Optional(reference = IndexedKeyword), + indexed_attribute = Optional(reference = EventIndexedAttribute), name = Optional(reference = Identifier) ) + ), + Struct( + name = EventIndexedAttribute, + fields = ( + indexed_keyword = Required(IndexedKeyword), + // Replicate solc bug: https://github.com/ethereum/solidity/issues/13681 + repeated = Optional( + reference = RepeatedIndexedKeyword, + enabled = Till("0.8.18") + ) + ) + ), + Repeated( + name = RepeatedIndexedKeyword, + reference = IndexedKeyword, + enabled = Till("0.8.18"), + allow_empty = false ) ] ), diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/kinds.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/kinds.rs index e32d5c8a93..0e21cc0eeb 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/kinds.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/kinds.rs @@ -63,6 +63,7 @@ pub enum RuleKind { ErrorParameters, ErrorParametersDeclaration, EventDefinition, + EventIndexedAttribute, EventParameter, EventParameters, EventParametersDeclaration, @@ -141,6 +142,7 @@ pub enum RuleKind { ReceiveFunctionAttribute, ReceiveFunctionAttributes, ReceiveFunctionDefinition, + RepeatedIndexedKeyword, ReturnStatement, ReturnsDeclaration, RevertStatement, @@ -316,6 +318,7 @@ pub enum NodeLabel { IfKeyword, ImportKeyword, Index, + IndexedAttribute, IndexedKeyword, Inheritence, Initialization, @@ -353,6 +356,7 @@ pub enum NodeLabel { PragmaKeyword, QuestionMark, ReceiveKeyword, + Repeated, ReturnKeyword, Returns, ReturnsKeyword, diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language.rs index 911e545699..fe8fb99078 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/language.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/language.rs @@ -1496,18 +1496,34 @@ impl Language { } #[allow(unused_assignments, unused_parens)] - fn event_parameter(&self, input: &mut ParserContext<'_>) -> ParserResult { + fn event_indexed_attribute(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { - seq.elem_labeled(NodeLabel::TypeName, self.type_name(input))?; seq.elem_labeled( NodeLabel::IndexedKeyword, - OptionalHelper::transform( - self.parse_token_with_trivia::( - input, - TokenKind::IndexedKeyword, - ), + self.parse_token_with_trivia::( + input, + TokenKind::IndexedKeyword, ), )?; + if !self.version_is_at_least_0_8_18 { + seq.elem_labeled( + NodeLabel::Repeated, + OptionalHelper::transform(self.repeated_indexed_keyword(input)), + )?; + } + seq.finish() + }) + .with_kind(RuleKind::EventIndexedAttribute) + } + + #[allow(unused_assignments, unused_parens)] + fn event_parameter(&self, input: &mut ParserContext<'_>) -> ParserResult { + SequenceHelper::run(|mut seq| { + seq.elem_labeled(NodeLabel::TypeName, self.type_name(input))?; + seq.elem_labeled( + NodeLabel::IndexedAttribute, + OptionalHelper::transform(self.event_indexed_attribute(input)), + )?; seq.elem_labeled( NodeLabel::Name, OptionalHelper::transform( @@ -4072,6 +4088,22 @@ impl Language { .with_kind(RuleKind::ReceiveFunctionDefinition) } + #[allow(unused_assignments, unused_parens)] + fn repeated_indexed_keyword(&self, input: &mut ParserContext<'_>) -> ParserResult { + if !self.version_is_at_least_0_8_18 { + OneOrMoreHelper::run(input, |input| { + self.parse_token_with_trivia::( + input, + TokenKind::IndexedKeyword, + ) + .with_label(NodeLabel::Item) + }) + } else { + ParserResult::disabled() + } + .with_kind(RuleKind::RepeatedIndexedKeyword) + } + #[allow(unused_assignments, unused_parens)] fn return_statement(&self, input: &mut ParserContext<'_>) -> ParserResult { SequenceHelper::run(|mut seq| { @@ -9027,6 +9059,7 @@ impl Language { Self::error_parameters_declaration.parse(self, input) } RuleKind::EventDefinition => Self::event_definition.parse(self, input), + RuleKind::EventIndexedAttribute => Self::event_indexed_attribute.parse(self, input), RuleKind::EventParameter => Self::event_parameter.parse(self, input), RuleKind::EventParameters => Self::event_parameters.parse(self, input), RuleKind::EventParametersDeclaration => { @@ -9135,6 +9168,7 @@ impl Language { RuleKind::ReceiveFunctionDefinition => { Self::receive_function_definition.parse(self, input) } + RuleKind::RepeatedIndexedKeyword => Self::repeated_indexed_keyword.parse(self, input), RuleKind::ReturnStatement => Self::return_statement.parse(self, input), RuleKind::ReturnsDeclaration => Self::returns_declaration.parse(self, input), RuleKind::RevertStatement => Self::revert_statement.parse(self, input), diff --git a/crates/solidity/outputs/cargo/slang_solidity/src/generated/napi_interface/ast_selectors.rs b/crates/solidity/outputs/cargo/slang_solidity/src/generated/napi_interface/ast_selectors.rs index 27c971e25e..6afb661102 100644 --- a/crates/solidity/outputs/cargo/slang_solidity/src/generated/napi_interface/ast_selectors.rs +++ b/crates/solidity/outputs/cargo/slang_solidity/src/generated/napi_interface/ast_selectors.rs @@ -70,6 +70,7 @@ pub fn select_sequence( RuleKind::EventDefinition => selector.event_definition()?, RuleKind::EventParametersDeclaration => selector.event_parameters_declaration()?, RuleKind::EventParameter => selector.event_parameter()?, + RuleKind::EventIndexedAttribute => selector.event_indexed_attribute()?, RuleKind::UserDefinedValueTypeDefinition => { selector.user_defined_value_type_definition()? } @@ -622,12 +623,21 @@ impl Selector { fn event_parameter(&mut self) -> Result>> { Ok(vec![ Some(self.select(|node| node.is_rule_with_kind(RuleKind::TypeName))?), - self.try_select(|node| node.is_token_with_kind(TokenKind::IndexedKeyword))?, + self.try_select(|node| node.is_rule_with_kind(RuleKind::EventIndexedAttribute))?, self.try_select(|node| node.is_token_with_kind(TokenKind::Identifier))?, ]) } } +impl Selector { + fn event_indexed_attribute(&mut self) -> Result>> { + Ok(vec![ + Some(self.select(|node| node.is_token_with_kind(TokenKind::IndexedKeyword))?), + self.try_select(|node| node.is_rule_with_kind(RuleKind::RepeatedIndexedKeyword))?, + ]) + } +} + impl Selector { fn user_defined_value_type_definition(&mut self) -> Result>> { Ok(vec![ @@ -2235,6 +2245,7 @@ pub fn select_repeated( RuleKind::FallbackFunctionAttributes => selector.fallback_function_attributes()?, RuleKind::ReceiveFunctionAttributes => selector.receive_function_attributes()?, RuleKind::ModifierAttributes => selector.modifier_attributes()?, + RuleKind::RepeatedIndexedKeyword => selector.repeated_indexed_keyword()?, RuleKind::FunctionTypeAttributes => selector.function_type_attributes()?, RuleKind::Statements => selector.statements()?, RuleKind::CatchClauses => selector.catch_clauses()?, @@ -2434,6 +2445,20 @@ impl Selector { } } +impl Selector { + fn repeated_indexed_keyword(&mut self) -> Result> { + let mut items = vec![]; + + while let Some(item) = + self.try_select(|node| node.is_token_with_kind(TokenKind::IndexedKeyword))? + { + items.push(item); + } + + Ok(items) + } +} + impl Selector { fn function_type_attributes(&mut self) -> Result> { let mut items = vec![]; diff --git a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/event_definition.rs b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/event_definition.rs index f2d99c3ea2..49f784bf3e 100644 --- a/crates/solidity/outputs/cargo/tests/src/cst_output/generated/event_definition.rs +++ b/crates/solidity/outputs/cargo/tests/src/cst_output/generated/event_definition.rs @@ -4,6 +4,11 @@ use anyhow::Result; use crate::cst_output::runner::run; +#[test] +fn indexed_indexed() -> Result<()> { + run("EventDefinition", "indexed_indexed") +} + #[test] fn no_parens() -> Result<()> { run("EventDefinition", "no_parens") diff --git a/crates/solidity/outputs/npm/package/src/ast/generated/ast_types.ts b/crates/solidity/outputs/npm/package/src/ast/generated/ast_types.ts index b85a9e15b2..5d2166ab1d 100644 --- a/crates/solidity/outputs/npm/package/src/ast/generated/ast_types.ts +++ b/crates/solidity/outputs/npm/package/src/ast/generated/ast_types.ts @@ -1315,11 +1315,12 @@ export class EventParametersDeclaration { export class EventParameter { private readonly fetch = once(() => { - const [$typeName, $indexedKeyword, $name] = ast_internal.selectSequence(this.cst); + const [$typeName, $indexedAttribute, $name] = ast_internal.selectSequence(this.cst); return { typeName: new TypeName($typeName as RuleNode), - indexedKeyword: $indexedKeyword === null ? undefined : ($indexedKeyword as TokenNode), + indexedAttribute: + $indexedAttribute === null ? undefined : new EventIndexedAttribute($indexedAttribute as RuleNode), name: $name === null ? undefined : ($name as TokenNode), }; }); @@ -1332,8 +1333,8 @@ export class EventParameter { return this.fetch().typeName; } - public get indexedKeyword(): TokenNode | undefined { - return this.fetch().indexedKeyword; + public get indexedAttribute(): EventIndexedAttribute | undefined { + return this.fetch().indexedAttribute; } public get name(): TokenNode | undefined { @@ -1341,6 +1342,29 @@ export class EventParameter { } } +export class EventIndexedAttribute { + private readonly fetch = once(() => { + const [$indexedKeyword, $repeated] = ast_internal.selectSequence(this.cst); + + return { + indexedKeyword: $indexedKeyword as TokenNode, + repeated: $repeated === null ? undefined : new RepeatedIndexedKeyword($repeated as RuleNode), + }; + }); + + public constructor(public readonly cst: RuleNode) { + assertKind(this.cst.kind, RuleKind.EventIndexedAttribute); + } + + public get indexedKeyword(): TokenNode { + return this.fetch().indexedKeyword; + } + + public get repeated(): RepeatedIndexedKeyword | undefined { + return this.fetch().repeated; + } +} + export class UserDefinedValueTypeDefinition { private readonly fetch = once(() => { const [$typeKeyword, $name, $isKeyword, $valueType, $semicolon] = ast_internal.selectSequence(this.cst); @@ -5470,6 +5494,21 @@ export class ModifierAttributes { } } +export class RepeatedIndexedKeyword { + private readonly fetch = once(() => { + const items = ast_internal.selectRepeated(this.cst); + return items as TokenNode[]; + }); + + public constructor(public readonly cst: RuleNode) { + assertKind(this.cst.kind, RuleKind.RepeatedIndexedKeyword); + } + + public get items(): readonly TokenNode[] { + return this.fetch(); + } +} + export class FunctionTypeAttributes { private readonly fetch = once(() => { const items = ast_internal.selectRepeated(this.cst); diff --git a/crates/solidity/outputs/npm/package/src/generated/index.d.ts b/crates/solidity/outputs/npm/package/src/generated/index.d.ts index 9d31b9bc2e..b28c08e7e3 100644 --- a/crates/solidity/outputs/npm/package/src/generated/index.d.ts +++ b/crates/solidity/outputs/npm/package/src/generated/index.d.ts @@ -55,6 +55,7 @@ export namespace kinds { ErrorParameters = "ErrorParameters", ErrorParametersDeclaration = "ErrorParametersDeclaration", EventDefinition = "EventDefinition", + EventIndexedAttribute = "EventIndexedAttribute", EventParameter = "EventParameter", EventParameters = "EventParameters", EventParametersDeclaration = "EventParametersDeclaration", @@ -133,6 +134,7 @@ export namespace kinds { ReceiveFunctionAttribute = "ReceiveFunctionAttribute", ReceiveFunctionAttributes = "ReceiveFunctionAttributes", ReceiveFunctionDefinition = "ReceiveFunctionDefinition", + RepeatedIndexedKeyword = "RepeatedIndexedKeyword", ReturnStatement = "ReturnStatement", ReturnsDeclaration = "ReturnsDeclaration", RevertStatement = "RevertStatement", @@ -290,6 +292,7 @@ export namespace kinds { IfKeyword = "IfKeyword", ImportKeyword = "ImportKeyword", Index = "Index", + IndexedAttribute = "IndexedAttribute", IndexedKeyword = "IndexedKeyword", Inheritence = "Inheritence", Initialization = "Initialization", @@ -327,6 +330,7 @@ export namespace kinds { PragmaKeyword = "PragmaKeyword", QuestionMark = "QuestionMark", ReceiveKeyword = "ReceiveKeyword", + Repeated = "Repeated", ReturnKeyword = "ReturnKeyword", Returns = "Returns", ReturnsKeyword = "ReturnsKeyword", diff --git a/crates/solidity/outputs/spec/generated/grammar.ebnf b/crates/solidity/outputs/spec/generated/grammar.ebnf index cdc23d019f..49ec95980f 100644 --- a/crates/solidity/outputs/spec/generated/grammar.ebnf +++ b/crates/solidity/outputs/spec/generated/grammar.ebnf @@ -835,9 +835,15 @@ EventParametersDeclaration = OPEN_PAREN EventParameters = (EventParameter (COMMA EventParameter)*)?; EventParameter = TypeName - INDEXED_KEYWORD? + EventIndexedAttribute? IDENTIFIER?; +EventIndexedAttribute = INDEXED_KEYWORD + RepeatedIndexedKeyword?; (* Deprecated in 0.8.18 *) + +(* Deprecated in 0.8.18 *) +RepeatedIndexedKeyword = INDEXED_KEYWORD+; + (* 2.11. User Defined Value Types: *) (* Introduced in 0.8.8 *) diff --git a/crates/solidity/outputs/spec/generated/public/02-definitions/10-events.md b/crates/solidity/outputs/spec/generated/public/02-definitions/10-events.md index e9e83bf53e..09ce0907f4 100644 --- a/crates/solidity/outputs/spec/generated/public/02-definitions/10-events.md +++ b/crates/solidity/outputs/spec/generated/public/02-definitions/10-events.md @@ -26,6 +26,18 @@ ``` -
EventParameter = TypeName
INDEXED_KEYWORD?
IDENTIFIER?;
+
EventParameter = TypeName
EventIndexedAttribute?
IDENTIFIER?;
+ +```{ .ebnf #EventIndexedAttribute } + +``` + +
EventIndexedAttribute = INDEXED_KEYWORD
RepeatedIndexedKeyword?; (* Deprecated in 0.8.18 *)
+ +```{ .ebnf #RepeatedIndexedKeyword } + +``` + +
(* Deprecated in 0.8.18 *)
RepeatedIndexedKeyword = INDEXED_KEYWORD+;
--8<-- "crates/solidity/inputs/language/docs/02-definitions/10-events.md" diff --git a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/member_event_definition/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/member_event_definition/generated/0.4.11-success.yml index f0a46daff2..2c7f258d11 100644 --- a/crates/solidity/testing/snapshots/cst_output/ContractDefinition/member_event_definition/generated/0.4.11-success.yml +++ b/crates/solidity/testing/snapshots/cst_output/ContractDefinition/member_event_definition/generated/0.4.11-success.yml @@ -26,8 +26,9 @@ Tree: - (parameters꞉ EventParameters): # "uint256 indexed a, uint256 indexed b" (30..66) - (item꞉ EventParameter): # "uint256 indexed a" (30..47) - (type_name꞉ TypeName) ► (variant꞉ ElementaryType) ► (variant꞉ UintKeyword): "uint256" # (30..37) - - (leading_trivia꞉ Whitespace): " " # (37..38) - - (indexed_keyword꞉ IndexedKeyword): "indexed" # (38..45) + - (indexed_attribute꞉ EventIndexedAttribute): # " indexed" (37..45) + - (leading_trivia꞉ Whitespace): " " # (37..38) + - (indexed_keyword꞉ IndexedKeyword): "indexed" # (38..45) - (leading_trivia꞉ Whitespace): " " # (45..46) - (name꞉ Identifier): "a" # (46..47) - (separator꞉ Comma): "," # (47..48) @@ -35,8 +36,9 @@ Tree: - (type_name꞉ TypeName) ► (variant꞉ ElementaryType): # " uint256" (48..56) - (leading_trivia꞉ Whitespace): " " # (48..49) - (variant꞉ UintKeyword): "uint256" # (49..56) - - (leading_trivia꞉ Whitespace): " " # (56..57) - - (indexed_keyword꞉ IndexedKeyword): "indexed" # (57..64) + - (indexed_attribute꞉ EventIndexedAttribute): # " indexed" (56..64) + - (leading_trivia꞉ Whitespace): " " # (56..57) + - (indexed_keyword꞉ IndexedKeyword): "indexed" # (57..64) - (leading_trivia꞉ Whitespace): " " # (64..65) - (name꞉ Identifier): "b" # (65..66) - (close_paren꞉ CloseParen): ")" # (66..67) diff --git a/crates/solidity/testing/snapshots/cst_output/EventDefinition/indexed_indexed/generated/0.4.11-success.yml b/crates/solidity/testing/snapshots/cst_output/EventDefinition/indexed_indexed/generated/0.4.11-success.yml new file mode 100644 index 0000000000..56e2279e34 --- /dev/null +++ b/crates/solidity/testing/snapshots/cst_output/EventDefinition/indexed_indexed/generated/0.4.11-success.yml @@ -0,0 +1,34 @@ +# This file is generated automatically by infrastructure scripts. Please don't edit by hand. + +Source: > + 1 │ // This replicates a solc's bug, where we could specify indexed multiple times. │ 0..79 + 2 │ // This was fixed in 0.8.18, see . │ 80..163 + 3 │ event Updated(uint256 indexed indexed id); │ 164..206 + +Errors: [] + +Tree: + - (EventDefinition): # "// This replicates a solc's bug, where we could sp..." (0..207) + - (leading_trivia꞉ SingleLineComment): "// This replicates a solc's bug, where we could sp..." # (0..79) + - (leading_trivia꞉ EndOfLine): "\n" # (79..80) + - (leading_trivia꞉ SingleLineComment): "// This was fixed in 0.8.18, see + 1 │ // This replicates a solc's bug, where we could specify indexed multiple times. │ 0..79 + 2 │ // This was fixed in 0.8.18, see . │ 80..163 + 3 │ event Updated(uint256 indexed indexed id); │ 164..206 + +Errors: # 1 total + - > + Error: Expected CloseParen or Comma. + ╭─[crates/solidity/testing/snapshots/cst_output/EventDefinition/indexed_indexed/input.sol:3:31] + │ + 3 │ event Updated(uint256 indexed indexed id); + │ ─────┬──── + │ ╰────── Error occurred here. + ───╯ + +Tree: + - (EventDefinition): # "// This replicates a solc's bug, where we could sp..." (0..207) + - (leading_trivia꞉ SingleLineComment): "// This replicates a solc's bug, where we could sp..." # (0..79) + - (leading_trivia꞉ EndOfLine): "\n" # (79..80) + - (leading_trivia꞉ SingleLineComment): "// This was fixed in 0.8.18, see . +event Updated(uint256 indexed indexed id); 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 index 1987ea059c..fa81a84c0d 100644 --- 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 @@ -15,8 +15,9 @@ Tree: - (parameters꞉ EventParameters): # "address indexed from, address indexed to, uint256 ..." (15..70) - (item꞉ EventParameter): # "address indexed from" (15..35) - (type_name꞉ TypeName) ► (variant꞉ ElementaryType) ► (variant꞉ AddressType) ► (address_keyword꞉ AddressKeyword): "address" # (15..22) - - (leading_trivia꞉ Whitespace): " " # (22..23) - - (indexed_keyword꞉ IndexedKeyword): "indexed" # (23..30) + - (indexed_attribute꞉ EventIndexedAttribute): # " indexed" (22..30) + - (leading_trivia꞉ Whitespace): " " # (22..23) + - (indexed_keyword꞉ IndexedKeyword): "indexed" # (23..30) - (leading_trivia꞉ Whitespace): " " # (30..31) - (name꞉ Identifier): "from" # (31..35) - (separator꞉ Comma): "," # (35..36) @@ -24,8 +25,9 @@ Tree: - (type_name꞉ TypeName) ► (variant꞉ ElementaryType) ► (variant꞉ AddressType): # " address" (36..44) - (leading_trivia꞉ Whitespace): " " # (36..37) - (address_keyword꞉ AddressKeyword): "address" # (37..44) - - (leading_trivia꞉ Whitespace): " " # (44..45) - - (indexed_keyword꞉ IndexedKeyword): "indexed" # (45..52) + - (indexed_attribute꞉ EventIndexedAttribute): # " indexed" (44..52) + - (leading_trivia꞉ Whitespace): " " # (44..45) + - (indexed_keyword꞉ IndexedKeyword): "indexed" # (45..52) - (leading_trivia꞉ Whitespace): " " # (52..53) - (name꞉ Identifier): "to" # (53..55) - (separator꞉ Comma): "," # (55..56)