Skip to content

Commit 7a20e88

Browse files
committed
Changes to V2 language definition
1 parent d95ed0d commit 7a20e88

File tree

7 files changed

+1241
-486
lines changed

7 files changed

+1241
-486
lines changed

crates/solidity-v2/inputs/language/src/BREAKING_CHANGES.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,52 @@ We should consider adding validation for these at a later stage if needed:
2727
- They were only enabled after `0.7.0`.
2828
- `HexLiteral` and `YulHexLiteral` and `DecimalLiteral` and `YulDecimalLiteral`:
2929
- It was illegal for them to be followed by `IdentifierStart`. Now we will produce two separate tokens rather than rejecting it.
30+
31+
## Language Definition Changes
32+
33+
The following changes modify the language definition to support the new parser and resolve grammar ambiguities.
34+
In some cases we also try to simplify the model.
35+
36+
### AddressKeyword
37+
38+
- Made the `address` keyword reserved in all versions, handling the few cases where it can be used as an identifier separately.
39+
- `MemberAccessIdentifier` handles the cases where `address` can be used as an `Identifier`, either in an `IdentifierPath` or a `MemberAccessExpression`.
40+
41+
### MemberAccessIdentifier
42+
43+
New enum added to allow the reserved `address` keyword in member access expressions (from Solidity 0.6.0):
44+
45+
- Variants: `Identifier` | `AddressKeyword` (enabled from 0.6.0)
46+
- Used in `MemberAccessExpression` (previously just `Identifier`) and in `IdentifierPathTailElements` (for identifier path tails)
47+
48+
### IdentifierPath
49+
50+
Changed from a simple `Separated` list to a structured format to allow the reserved `address` keyword to appear in identifier paths (but not as the head):
51+
52+
- **Before**: `Separated(name = IdentifierPath, reference = Identifier, separator = Period)`
53+
- **After**: `Struct` with `head: Identifier` and `tail: Optional<IdentifierPathTail>`, where `IdentifierPathTail` contains a `Period` separator followed by `IdentifierPathTailElements` (a `Separated` list of `MemberAccessIdentifier`).
54+
55+
### TupleDeconstructionStatement
56+
57+
Major restructuring to resolve ambiguities with tuple expressions and assignment expressions:
58+
59+
- **Before**: Single struct with optional `var_keyword`, `open_paren`, `elements: TupleDeconstructionElements`, `close_paren`, `equal`, `expression`, `semicolon`.
60+
- **After**: Split into typed and untyped (var) variants:
61+
- `TupleDeconstructionStatement`: Contains `target: TupleDeconstructionTarget`, `equal`, `expression`, `semicolon`
62+
- `TupleDeconstructionTarget`: Enum with `VarTupleDeconstructionTarget` (till 0.5.0) | `TypedTupleDeconstructionTarget`
63+
- `VarTupleDeconstructionTarget`: For `var (a, b) = ...` syntax (till 0.5.0)
64+
- `TypedTupleDeconstructionTarget`: For `(uint a, uint b) = ...` syntax
65+
66+
This makes certain cases that were allowed before disallowed in V2, in particular having untyped declarations (like `(a, bool b) = ...`)
67+
or having typed together with `var` (like `var (a, bool b) = ... `).
68+
The cases where using empty tuples are still ambiguous, `(,,,) = ...` can still be a `TupleDeconstructionStatement` or a
69+
an `AssignmentExpression` with a `TupleExpression` on the lhs.
70+
71+
Removed types: `TupleDeconstructionElements`, `TupleDeconstructionElement`, `TupleMember`, `TypedTupleMember`, `UntypedTupleMember`
72+
73+
Added types: `TupleDeconstructionTarget`, `VarTupleDeconstructionTarget`, `UntypedTupleDeconstructionElements`, `UntypedTupleDeconstructionElement`, `TypedTupleDeconstructionTarget`, `TypedTupleDeconstructionElements`, `TypedTupleDeconstructionElement`, `TypedTupleDeconstructionMember`
74+
75+
### NamedArgumentsDeclaration
76+
77+
- Changed `arguments` field from `Optional(NamedArgumentGroup)` to `Required(NamedArgumentGroup)`.
78+
- This avoids ambiguity with empty argument lists `()` which could be either positional or named.

crates/solidity-v2/inputs/language/src/definition.rs

Lines changed: 85 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,13 @@ language_v2_macros::compile!(Language(
493493
definitions = [KeywordDefinition(value = Atom("abstract"))]
494494
),
495495
Keyword(
496+
// `address` is a reserved keyword, but it can still be used as an identifier in some contexts,
497+
// in particular as a member access (e.g., `myPayload.address`) or as an identifier
498+
// path
499+
// See `MemberAccessIdentifier` for details
496500
name = AddressKeyword,
497501
identifier = Identifier,
498-
definitions =
499-
[KeywordDefinition(reserved = Never, value = Atom("address"))]
502+
definitions = [KeywordDefinition(value = Atom("address"))]
500503
),
501504
Keyword(
502505
name = AfterKeyword,
@@ -2926,49 +2929,75 @@ language_v2_macros::compile!(Language(
29262929
items = [
29272930
Struct(
29282931
name = TupleDeconstructionStatement,
2932+
error_recovery = FieldsErrorRecovery(terminator = semicolon),
2933+
fields = (
2934+
target = Required(TupleDeconstructionTarget),
2935+
equal = Required(Equal),
2936+
expression = Required(Expression),
2937+
semicolon = Required(Semicolon)
2938+
)
2939+
),
2940+
Enum(
2941+
name = TupleDeconstructionTarget,
2942+
variants = [
2943+
EnumVariant(
2944+
reference = VarTupleDeconstructionTarget,
2945+
enabled = Till("0.5.0")
2946+
),
2947+
EnumVariant(reference = TypedTupleDeconstructionTarget)
2948+
]
2949+
),
2950+
Struct(
2951+
name = VarTupleDeconstructionTarget,
2952+
enabled = Till("0.5.0"),
29292953
error_recovery = FieldsErrorRecovery(
2930-
terminator = semicolon,
29312954
delimiters =
29322955
FieldDelimiters(open = open_paren, close = close_paren)
29332956
),
29342957
fields = (
2935-
var_keyword =
2936-
Optional(reference = VarKeyword, enabled = Till("0.5.0")),
2958+
var_keyword = Required(VarKeyword),
29372959
open_paren = Required(OpenParen),
2938-
elements = Required(TupleDeconstructionElements),
2939-
close_paren = Required(CloseParen),
2940-
equal = Required(Equal),
2941-
expression = Required(Expression),
2942-
semicolon = Required(Semicolon)
2960+
elements = Required(UntypedTupleDeconstructionElements),
2961+
close_paren = Required(CloseParen)
29432962
)
29442963
),
29452964
Separated(
2946-
name = TupleDeconstructionElements,
2947-
reference = TupleDeconstructionElement,
2948-
separator = Comma
2965+
name = UntypedTupleDeconstructionElements,
2966+
reference = UntypedTupleDeconstructionElement,
2967+
separator = Comma,
2968+
enabled = Till("0.5.0")
29492969
),
29502970
Struct(
2951-
name = TupleDeconstructionElement,
2952-
fields = (member = Optional(reference = TupleMember))
2953-
),
2954-
Enum(
2955-
name = TupleMember,
2956-
variants = [
2957-
EnumVariant(reference = TypedTupleMember),
2958-
EnumVariant(reference = UntypedTupleMember)
2959-
]
2971+
name = UntypedTupleDeconstructionElement,
2972+
enabled = Till("0.5.0"),
2973+
fields = (name = Optional(reference = Identifier))
29602974
),
29612975
Struct(
2962-
name = TypedTupleMember,
2976+
name = TypedTupleDeconstructionTarget,
2977+
error_recovery = FieldsErrorRecovery(
2978+
delimiters =
2979+
FieldDelimiters(open = open_paren, close = close_paren)
2980+
),
29632981
fields = (
2964-
type_name = Required(TypeName),
2965-
storage_location = Optional(reference = StorageLocation),
2966-
name = Required(Identifier)
2982+
open_paren = Required(OpenParen),
2983+
elements = Required(TypedTupleDeconstructionElements),
2984+
close_paren = Required(CloseParen)
29672985
)
29682986
),
2987+
Separated(
2988+
name = TypedTupleDeconstructionElements,
2989+
reference = TypedTupleDeconstructionElement,
2990+
separator = Comma
2991+
),
29692992
Struct(
2970-
name = UntypedTupleMember,
2993+
name = TypedTupleDeconstructionElement,
2994+
fields =
2995+
(member = Optional(reference = TypedTupleDeconstructionMember))
2996+
),
2997+
Struct(
2998+
name = TypedTupleDeconstructionMember,
29712999
fields = (
3000+
type_name = Required(TypeName),
29723001
storage_location = Optional(reference = StorageLocation),
29733002
name = Required(Identifier)
29743003
)
@@ -3499,7 +3528,7 @@ language_v2_macros::compile!(Language(
34993528
model = Postfix,
35003529
fields = (
35013530
period = Required(Period),
3502-
member = Required(Identifier)
3531+
member = Required(MemberAccessIdentifier)
35033532
)
35043533
)]
35053534
),
@@ -3551,6 +3580,14 @@ language_v2_macros::compile!(Language(
35513580
colon = Required(Colon),
35523581
end = Optional(reference = Expression)
35533582
)
3583+
),
3584+
Enum(
3585+
// A member access can be either an identifier or the reserved `address` keyword
3586+
name = MemberAccessIdentifier,
3587+
variants = [
3588+
EnumVariant(reference = Identifier),
3589+
EnumVariant(reference = AddressKeyword, enabled = From("0.6.0"))
3590+
]
35543591
)
35553592
]
35563593
),
@@ -3591,7 +3628,7 @@ language_v2_macros::compile!(Language(
35913628
),
35923629
fields = (
35933630
open_paren = Required(OpenParen),
3594-
arguments = Optional(reference = NamedArgumentGroup),
3631+
arguments = Required(NamedArgumentGroup),
35953632
close_paren = Required(CloseParen)
35963633
)
35973634
),
@@ -3986,9 +4023,26 @@ language_v2_macros::compile!(Language(
39864023
title = "Identifiers",
39874024
lexical_context = Solidity,
39884025
items = [
3989-
Separated(
4026+
// Since an identifier path can include the reserved keyword `address` as parth of the path
4027+
// (but not as the head), we differentiate between head (any `Identifier`)
4028+
// and tail (which can use `MemberAccessIdentifier`)
4029+
Struct(
39904030
name = IdentifierPath,
3991-
reference = Identifier,
4031+
fields = (
4032+
head = Required(Identifier),
4033+
tail = Optional(reference = IdentifierPathTail)
4034+
)
4035+
),
4036+
Struct(
4037+
name = IdentifierPathTail,
4038+
fields = (
4039+
sep = Required(Period),
4040+
elements = Required(IdentifierPathTailElements)
4041+
)
4042+
),
4043+
Separated(
4044+
name = IdentifierPathTailElements,
4045+
reference = MemberAccessIdentifier,
39924046
separator = Period
39934047
),
39944048
Token(

0 commit comments

Comments
 (0)