Skip to content

Commit a7b5378

Browse files
committed
Add explanation for predicate in identifier parser rule
Also adds some more tests.
1 parent 1ab7f46 commit a7b5378

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

Rubberduck.Parsing/Grammar/VBAParser.g4

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,13 @@ subscript : (expression whiteSpace TO whiteSpace)? expression;
579579

580580
unrestrictedIdentifier : identifier | statementKeyword | markerKeyword;
581581
legalLabelIdentifier : { !(new[]{DOEVENTS,END,CLOSE,ELSE,LOOP,NEXT,RANDOMIZE,REM,RESUME,RETURN,STOP,WEND}).Contains(_input.La(1))}? identifier | markerKeyword;
582+
//The predicate in the following rule has been introduced to lessen the problem that VBA uses the same characters used as type hints in other syntactical constructs,
583+
//e.g. in the bang notation (see withDictionaryAccessExpr). Generally, it is not legal to have an identifier of openeing bracket follow immediately after a type hint.
584+
//The first part of the predicate tries to exclude these two situations. Unfortunately, predicates have to be at the start of a rule. S, an assumprion about the number
585+
//of tokens in the identifier is made. All untypedIdentifers not a foreignNames consist of exactly one token and a typedIdentifier is an untypes one followed by a typeHint,
586+
//again a single token. So, in the majority of situations, the third token is the token following the potential type hint.
587+
//For foreignNames, no assumption can be made because they consist of a pair of brackets containing arbitrarily many tokens.
588+
//That is why the second part of the predicate looks at the first character in order to determine whether the identifier is a foreignName.
582589
identifier : {_input.La(3) != IDENTIFIER && _input.La(3) != L_SQUARE_BRACKET || _input.La(1) == L_SQUARE_BRACKET}? typedIdentifier
583590
| untypedIdentifier;
584591
untypedIdentifier : identifierValue;

RubberduckTests/Grammar/VBAParserTests.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2961,10 +2961,11 @@ public void ParserDoesNotFailDoubleBracketForgeignIdentifierWithTypeHint()
29612961
Sub Test()
29622962
Dim x
29632963
x = [[bar]]!
2964+
x = [bar]!
29642965
End Sub
29652966
";
29662967
var parseResult = Parse(code);
2967-
AssertTree(parseResult.Item1, parseResult.Item2, "//typeHint", matches => matches.Count == 1);
2968+
AssertTree(parseResult.Item1, parseResult.Item2, "//typeHint", matches => matches.Count == 2);
29682969
}
29692970

29702971
[Category("Parser")]
@@ -2980,6 +2981,7 @@ Dim x
29802981
End Sub
29812982
";
29822983
var parseResult = Parse(code);
2984+
AssertTree(parseResult.Item1, parseResult.Item2, "//typeHint", matches => matches.Count == 0);
29832985
}
29842986

29852987
[Category("Parser")]
@@ -2995,6 +2997,55 @@ Dim x
29952997
End Sub
29962998
";
29972999
var parseResult = Parse(code);
3000+
AssertTree(parseResult.Item1, parseResult.Item2, "//typeHint", matches => matches.Count == 0);
3001+
}
3002+
3003+
[Category("Parser")]
3004+
[Test]
3005+
[Ignore("This cannot work with the current setup of identifiers bacause the SLL parser confuses the bang for a type hint.")]
3006+
public void ParserDoesNotFailOnBangOperatorOnForeignIdentifier()
3007+
{
3008+
const string code = @"
3009+
Sub Test()
3010+
Dim x
3011+
x = [dict]!a
3012+
End Sub
3013+
";
3014+
var parseResult = Parse(code);
3015+
AssertTree(parseResult.Item1, parseResult.Item2, "//typeHint", matches => matches.Count == 0);
3016+
}
3017+
3018+
[Category("Parser")]
3019+
[Test]
3020+
public void ParserDoesNotFailOnStackedBangOperator()
3021+
{
3022+
const string code = @"
3023+
Sub Test()
3024+
Dim dict As Scripting.Dictionary
3025+
3026+
Dim x
3027+
x = dict!a!b!c
3028+
End Sub
3029+
";
3030+
var parseResult = Parse(code);
3031+
AssertTree(parseResult.Item1, parseResult.Item2, "//typeHint", matches => matches.Count == 0);
3032+
}
3033+
3034+
[Category("Parser")]
3035+
[Test]
3036+
[Ignore("This cannot work with the current setup of identifiers bacause the SLL parser confuses the bang for a type hint.")]
3037+
public void ParserDoesNotFailOnStackedBangOperator_ForeignIdentifier()
3038+
{
3039+
const string code = @"
3040+
Sub Test()
3041+
Dim dict As Scripting.Dictionary
3042+
3043+
Dim x
3044+
x = dict![a]!b!c
3045+
End Sub
3046+
";
3047+
var parseResult = Parse(code);
3048+
AssertTree(parseResult.Item1, parseResult.Item2, "//typeHint", matches => matches.Count == 0);
29983049
}
29993050

30003051
[Category("Parser")]

0 commit comments

Comments
 (0)