Skip to content

Commit ab9c140

Browse files
committed
Modified the node checker for (Hex)StringLiterals
1 parent 2533795 commit ab9c140

File tree

10 files changed

+228
-28
lines changed

10 files changed

+228
-28
lines changed

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

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
11
pub use solidity::SolidityDefinition;
22

3+
// Conflicting keywords
4+
// - this and super: Before version 0.8.0 they were regular identifiers, from 0.8.0 they still are identifiers, but they
5+
// are not allowed in certain declarations.
6+
// https://docs.soliditylang.org/en/latest/080-breaking-changes.html
7+
// I propose to treat them as identifiers, with a later pass to check that they're not used in invalid places.
8+
// - HexStringLiteral and StringLiteral: before only a single literal was allows, after version 0.5.14 multiple
9+
// literals are allowed. This presents a conflict, i propose only allowing the plural forms, with a later
10+
// pass to check that the singular forms are not used after 0.5.14
11+
// - Disabled when unreserved: These cases have no overlap between being unreserved and being enabled, so it makes no sense
12+
// to treat the unreserved lexeme as a keyword; or, alternatively, the lexer could emit an identifier lexeme instead
13+
// Cases:
14+
// - calldata
15+
// - override
16+
// - unchecked
17+
// - virtual
18+
// - fallback and receive: I think they should be disabled when unreserved, since they werent used as keywords in that range
19+
// Note: Leaving this commented from now, I think this should be enabled from 0.6.0,
20+
// together with the uses of it. Then it'll fall into the category of keywords
21+
// that are only used as keywords while reserved (a lot easier to solve)
22+
// Note: fallback and receive are strange, since they can be used as identifiers in functions
23+
// - a bunch of fixed/ufixed cases: similar to fallback and receive, they should be disabled when unreserved (since they
24+
// were identifiers). This is a bit trickier since they are single definitions within a keyword that has other
25+
// definitions that should be enabled throughout. We should discuss this a bit more.
26+
327
language_v2_macros::compile!(Language(
428
name = Solidity,
529
root_item = SourceUnit,
@@ -662,7 +686,7 @@ PragmaDirective: PragmaDirective = {
662686
name = CallDataKeyword,
663687
enabled = From("0.5.0"),
664688
definitions = [KeywordDefinition(
665-
// TODO(v2) removing conflict - calldata unreserved conflicts with identifier in Parameter
689+
// TODO(v2) Check header
666690
// reserved = From("0.5.0"),
667691
value = Atom("calldata")
668692
)]
@@ -769,11 +793,7 @@ PragmaDirective: PragmaDirective = {
769793
Keyword(
770794
name = FallbackKeyword,
771795
definitions = [KeywordDefinition(
772-
// TODO(v2) removing conflict - fallback unreserved before 0.6.0 conflicts with FunctionName
773-
// Note: Leaving this commented from now, I think this should be enabled from 0.6.0,
774-
// together with the uses of it. Then it'll fall into the category of keywords
775-
// that are only used as keywords while reserved (a lot easier to solve)
776-
796+
// TODO(v2) check header
777797
// reserved = From("0.6.0"),
778798
value = Atom("fallback")
779799
)]
@@ -894,7 +914,7 @@ PragmaDirective: PragmaDirective = {
894914
])
895915
),
896916
KeywordDefinition(
897-
// TODO(v2) removing conflict
917+
// TODO(v2) check header
898918
// reserved = From("0.4.14"),
899919
value = Sequence([
900920
Atom("fixed"),
@@ -958,7 +978,7 @@ PragmaDirective: PragmaDirective = {
958978
])
959979
),
960980
KeywordDefinition(
961-
// TODO(v2) removing conflict
981+
// TODO(v2) check header
962982
// reserved = From("0.4.14"),
963983
value = Sequence([
964984
Atom("fixed"),
@@ -1276,7 +1296,7 @@ PragmaDirective: PragmaDirective = {
12761296
name = OverrideKeyword,
12771297
enabled = From("0.6.0"),
12781298
definitions = [KeywordDefinition(
1279-
// TODO(v2) removing conflict - override unreserved before 0.5.0 conflicts with ModifierInvocation
1299+
// TODO(v2) check header
12801300
// reserved = From("0.5.0"),
12811301
value = Atom("override")
12821302
)]
@@ -1321,7 +1341,7 @@ PragmaDirective: PragmaDirective = {
13211341
Keyword(
13221342
name = ReceiveKeyword,
13231343
definitions = [KeywordDefinition(
1324-
// TODO(v2) removing conflict - receive unreserved before 0.6.0 conflicts with FunctionName
1344+
// TODO(v2) check header
13251345
// reserved = From("0.6.0"),
13261346
value = Atom("receive")
13271347
)]
@@ -1395,7 +1415,7 @@ PragmaDirective: PragmaDirective = {
13951415
Keyword(
13961416
name = SuperKeyword,
13971417
definitions = [KeywordDefinition(
1398-
// TODO(v2) this needs manual handling
1418+
// TODO(v2) Check header
13991419
// reserved = From("0.8.0"),
14001420
value = Atom("super")
14011421
)]
@@ -1424,7 +1444,7 @@ PragmaDirective: PragmaDirective = {
14241444
Keyword(
14251445
name = ThisKeyword,
14261446
definitions = [KeywordDefinition(
1427-
// TODO(v2) This needs manual handling
1447+
// TODO(v2) Check header
14281448
// reserved = From("0.8.0"),
14291449
value = Atom("this")
14301450
)]
@@ -1568,7 +1588,7 @@ PragmaDirective: PragmaDirective = {
15681588
])
15691589
),
15701590
KeywordDefinition(
1571-
// TODO(v2) removing conflict
1591+
// TODO(v2) check header
15721592
// reserved = From("0.4.14"),
15731593
value = Sequence([
15741594
Atom("ufixed"),
@@ -1632,7 +1652,7 @@ PragmaDirective: PragmaDirective = {
16321652
])
16331653
),
16341654
KeywordDefinition(
1635-
// TODO(v2) removing conflict
1655+
// TODO(v2) check header
16361656
// reserved = From("0.4.14"),
16371657
value = Sequence([
16381658
Atom("ufixed"),
@@ -1794,7 +1814,7 @@ PragmaDirective: PragmaDirective = {
17941814
name = UncheckedKeyword,
17951815
enabled = From("0.8.0"),
17961816
definitions = [KeywordDefinition(
1797-
// TODO(v2) removing conflict - unchecked unreserved before 0.5.0 conflicts with identifier in UncheckedBlock
1817+
// TODO(v2) check header
17981818
// reserved = From("0.5.0"),
17991819
value = Atom("unchecked")
18001820
)]
@@ -1817,7 +1837,7 @@ PragmaDirective: PragmaDirective = {
18171837
name = VirtualKeyword,
18181838
enabled = From("0.6.0"),
18191839
definitions = [KeywordDefinition(
1820-
// TODO(v2) removing conflict - virtual unreserved before 0.6.0 conflicts with ModifierInvocation
1840+
// TODO(v2) check header
18211841
// reserved = From("0.6.0"),
18221842
value = Atom("virtual")
18231843
)]
@@ -2141,7 +2161,7 @@ BracedContractMembers: (OpenBrace, ContractMembers, CloseBrace) = {
21412161
reference = FallbackFunctionDefinition,
21422162
enabled = From("0.6.0")
21432163
),
2144-
// TODO(v2) removing conflict - UnnamedFunctionDefinition conflicts with FunctionDefinition
2164+
// TODO(v2) removing conflict - UnnamedFunctionDefinition conflicts with FunctionDefinition
21452165
// EnumVariant(
21462166
// reference = UnnamedFunctionDefinition,
21472167
// enabled = Till("0.6.0")
@@ -2576,7 +2596,7 @@ SpecialStateVariableAttribute: StateVariableAttribute = {
25762596
)
25772597
]
25782598
),
2579-
// TODO(v2) removing conflict - UnnamedFunctionDefinition conflicts with FunctionDefinition
2599+
// TODO(v2) removing conflict - UnnamedFunctionDefinition conflicts with FunctionDefinition
25802600
// Struct(
25812601
// name = UnnamedFunctionDefinition,
25822602
// enabled = Till("0.6.0"),
@@ -4579,7 +4599,7 @@ HexNumberExpression: HexNumberExpression = {
45794599
Enum(
45804600
name = StringExpression,
45814601
variants = [
4582-
// TODO(v2) this conflicts with the one below
4602+
// TODO(v2) this conflicts with the one below
45834603
// EnumVariant(
45844604
// reference = StringLiteral,
45854605
// enabled = Till("0.5.14")
@@ -4588,7 +4608,7 @@ HexNumberExpression: HexNumberExpression = {
45884608
reference = StringLiterals,
45894609
enabled = From("0.5.14")
45904610
),
4591-
// TODO(v2) this conflicts with the one below
4611+
// TODO(v2) this conflicts with the one below
45924612
// EnumVariant(
45934613
// reference = HexStringLiteral,
45944614
// enabled = Till("0.5.14")

crates/solidity-v2/outputs/cargo/parser/src/parser/temp_testing/node_checker.generated.rs

Lines changed: 36 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/solidity-v2/outputs/cargo/parser/src/parser/temp_testing/node_checker.rs.jinja2

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,116 @@ impl NodeChecker for UntypedTupleDeclarationElements {
10561056
}
10571057
}
10581058

1059+
{% elif parent_type == "StringLiterals" %}
1060+
/// `NodeChecker` for `StringLiterals` - V2 always uses StringLiterals (plural),
1061+
/// but V1 uses StringLiteral (singular) before 0.5.14
1062+
/// TODO(v2): This check should probably be versioned
1063+
impl NodeChecker for StringLiterals {
1064+
fn check_node_with_offset(&self, node: &Node, text_offset: TextIndex) -> Vec<NodeCheckerError> {
1065+
let node_range = text_offset..(text_offset + node.text_len());
1066+
1067+
// V1 uses StringLiteral (singular) before 0.5.14
1068+
if node.kind() == NodeKind::Nonterminal(NonterminalKind::StringLiteral) {
1069+
if self.elements.len() != 1 {
1070+
return vec![NodeCheckerError::new(
1071+
format!(
1072+
"V1 has StringLiteral (singular) but V2 has {} elements in StringLiterals",
1073+
self.elements.len()
1074+
),
1075+
node_range,
1076+
)];
1077+
}
1078+
return self.elements[0].check_node_with_offset(node, text_offset);
1079+
}
1080+
1081+
if node.kind() != NodeKind::Nonterminal(NonterminalKind::StringLiterals) {
1082+
return vec![NodeCheckerError::new(
1083+
format!(
1084+
"Expected node kind to be StringLiterals or StringLiteral, but it was {}",
1085+
node.kind()
1086+
),
1087+
node_range,
1088+
)];
1089+
}
1090+
1091+
let children = children_with_offsets(node, text_offset);
1092+
1093+
if children.len() != self.elements.len() {
1094+
return vec![NodeCheckerError::new(
1095+
format!(
1096+
"Expected {} elements, but got: {:#?}",
1097+
self.elements.len(),
1098+
children
1099+
),
1100+
node_range,
1101+
)];
1102+
}
1103+
1104+
let mut errors = vec![];
1105+
1106+
for (i, (child, child_offset)) in children.iter().enumerate() {
1107+
let element = &self.elements[i];
1108+
errors.extend(element.check_node_with_offset(&child.node, *child_offset));
1109+
}
1110+
errors
1111+
}
1112+
}
1113+
1114+
{% elif parent_type == "HexStringLiterals" %}
1115+
/// `NodeChecker` for `HexStringLiterals` - V2 always uses HexStringLiterals (plural),
1116+
/// but V1 uses HexStringLiteral (singular) before 0.5.14
1117+
/// TODO(v2): This check should probably be versioned
1118+
impl NodeChecker for HexStringLiterals {
1119+
fn check_node_with_offset(&self, node: &Node, text_offset: TextIndex) -> Vec<NodeCheckerError> {
1120+
let node_range = text_offset..(text_offset + node.text_len());
1121+
1122+
// V1 uses HexStringLiteral (singular) before 0.5.14
1123+
if node.kind() == NodeKind::Nonterminal(NonterminalKind::HexStringLiteral) {
1124+
if self.elements.len() != 1 {
1125+
return vec![NodeCheckerError::new(
1126+
format!(
1127+
"V1 has HexStringLiteral (singular) but V2 has {} elements in HexStringLiterals",
1128+
self.elements.len()
1129+
),
1130+
node_range,
1131+
)];
1132+
}
1133+
return self.elements[0].check_node_with_offset(node, text_offset);
1134+
}
1135+
1136+
if node.kind() != NodeKind::Nonterminal(NonterminalKind::HexStringLiterals) {
1137+
return vec![NodeCheckerError::new(
1138+
format!(
1139+
"Expected node kind to be HexStringLiterals or HexStringLiteral, but it was {}",
1140+
node.kind()
1141+
),
1142+
node_range,
1143+
)];
1144+
}
1145+
1146+
let children = children_with_offsets(node, text_offset);
1147+
1148+
if children.len() != self.elements.len() {
1149+
return vec![NodeCheckerError::new(
1150+
format!(
1151+
"Expected {} elements, but got: {:#?}",
1152+
self.elements.len(),
1153+
children
1154+
),
1155+
node_range,
1156+
)];
1157+
}
1158+
1159+
let mut errors = vec![];
1160+
1161+
for (i, (child, child_offset)) in children.iter().enumerate() {
1162+
let element = &self.elements[i];
1163+
errors.extend(element.check_node_with_offset(&child.node, *child_offset));
1164+
}
1165+
errors
1166+
}
1167+
}
1168+
10591169
{% else %}
10601170
/// Generic `NodeChecker` for repeated and separated
10611171
impl NodeChecker for {{ parent_type }} {

0 commit comments

Comments
 (0)