Skip to content

Commit 67510c1

Browse files
author
Andrin Meier
committed
bug fixes and minor cleanups (#1132)
Changes: 1. fix expression date - date = double (not date as wrongly assumed before) 2. remove useless code 3. make fallback to unprocessed code clearer
1 parent eb1d42b commit 67510c1

File tree

5 files changed

+60
-31
lines changed

5 files changed

+60
-31
lines changed

Rubberduck.Parsing/Preprocessing/VBAExpressionEvaluator.cs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ private object VisitPlus(VBAConditionalCompilationParser.CcExpressionContext con
126126
{
127127
return (string)left + (string)right;
128128
}
129-
else if (left is DateTime)
129+
else if (left is DateTime || right is DateTime)
130130
{
131131
decimal leftValue = _letCoercions[left.GetType()].ToDecimal(left);
132132
decimal rightValue = _letCoercions[right.GetType()].ToDecimal(right);
@@ -156,22 +156,28 @@ private object VisitMinus(VBAConditionalCompilationParser.CcExpressionContext co
156156
{
157157
return null;
158158
}
159-
if (left is DateTime)
159+
else if (left is DateTime && right is DateTime)
160160
{
161+
// 5.6.9.3.3 - Effective value type exception.
162+
// If left + right are both Date then effective value type is double.
161163
decimal leftValue = _letCoercions[left.GetType()].ToDecimal(left);
162164
decimal rightValue = _letCoercions[right.GetType()].ToDecimal(right);
163165
decimal difference = leftValue - rightValue;
164-
// 5.6.9.3.3 Should actually return date if no overflow.
165-
// At least Excel always seems to return the double value (instead of date)
166166
return difference;
167-
//try
168-
//{
169-
// return _letCoercions[typeof(decimal)].ToDate(difference);
170-
//}
171-
//catch
172-
//{
173-
// return difference;
174-
//}
167+
}
168+
else if (left is DateTime || right is DateTime)
169+
{
170+
decimal leftValue = _letCoercions[left.GetType()].ToDecimal(left);
171+
decimal rightValue = _letCoercions[right.GetType()].ToDecimal(right);
172+
decimal difference = leftValue - rightValue;
173+
try
174+
{
175+
return _letCoercions[typeof(decimal)].ToDate(difference);
176+
}
177+
catch
178+
{
179+
return difference;
180+
}
175181
}
176182
else
177183
{
@@ -1182,8 +1188,6 @@ private object VisitDateLiteral(VBAConditionalCompilationParser.LiteralContext c
11821188
hours = 0;
11831189
}
11841190
}
1185-
1186-
var text = dateLiteral.GetText();
11871191
var date = new DateTime(year, month, day, hours, mins, seconds);
11881192
return date;
11891193
}

Rubberduck.Parsing/Preprocessing/VBAPredefinedCompilationConstants.cs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
using System;
2-
using System.Collections.Generic;
3-
using System.Linq;
4-
using System.Text;
5-
using System.Threading.Tasks;
62

73
namespace Rubberduck.Parsing.Preprocessing
84
{
95
public sealed class VBAPredefinedCompilationConstants
106
{
11-
private readonly string _vbVersion;
7+
private readonly double _vbVersion;
128

13-
public VBAPredefinedCompilationConstants(string vbVersion)
9+
public VBAPredefinedCompilationConstants(double vbVersion)
1410
{
1511
_vbVersion = vbVersion;
1612
}
@@ -22,19 +18,19 @@ public VBAPredefinedCompilationConstants(string vbVersion)
2218
public const string WIN16_NAME = "Win16";
2319
public const string MAC_NAME = "Mac";
2420

25-
public bool VBA6
21+
public bool VBA7
2622
{
2723
get
2824
{
29-
return _vbVersion.StartsWith("6.");
25+
return _vbVersion < 8;
3026
}
3127
}
3228

33-
public bool VBA7
29+
public bool VBA6
3430
{
3531
get
3632
{
37-
return _vbVersion.StartsWith("7.");
33+
return _vbVersion < 7;
3834
}
3935
}
4036

Rubberduck.Parsing/Preprocessing/VBAPreprocessor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ namespace Rubberduck.Parsing.Preprocessing
66
{
77
public sealed class VBAPreprocessor
88
{
9-
private readonly string _vbaVersion;
9+
private readonly double _vbaVersion;
1010

11-
public VBAPreprocessor(string vbaVersion)
11+
public VBAPreprocessor(double vbaVersion)
1212
{
1313
_vbaVersion = vbaVersion;
1414
}

Rubberduck.Parsing/VBA/RubberduckParser.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,16 @@ private void ParseInternal(VBComponent vbComponent, string code, CancellationTok
225225

226226
token.ThrowIfCancellationRequested();
227227

228-
var preprocessor = new VBAPreprocessor(_vbe.Version);
229-
string preprocessedModuleBody = code;
228+
var preprocessor = new VBAPreprocessor(double.Parse(_vbe.Version));
229+
string preprocessedModuleBody;
230230
try
231231
{
232232
preprocessedModuleBody = preprocessor.Process(code);
233233
}
234234
catch (VBAPreprocessorException ex)
235235
{
236236
// Fall back to not doing any preprocessing at all.
237+
preprocessedModuleBody = code;
237238
}
238239
ITokenStream stream;
239240
var tree = ParseInternal(preprocessedModuleBody, listeners, out stream);

RubberduckTests/Preprocessing/VBAPreprocessorVisitorTests.cs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,17 @@ public void TestMinusOperator()
9191
#Const c = False - True - True
9292
#Const d = Nothing
9393
#Const e = ""3"" - ""1""
94+
#Const f = #1/1/2351# - 2
95+
#Const g = #1/1/2400# - #1/1/1800# - #1/1/1800#
9496
";
9597
var result = Preprocess(code);
9698
Assert.AreEqual(2m, result.Item1.Get("a"));
9799
Assert.AreEqual(184018m, result.Item1.Get("b"));
98100
Assert.AreEqual(2m, result.Item1.Get("c"));
99101
Assert.AreEqual(null, result.Item1.Get("d"));
100102
Assert.AreEqual(2m, result.Item1.Get("e"));
103+
Assert.AreEqual(new DateTime(2350, 12, 30), result.Item1.Get("f"));
104+
Assert.AreEqual(new DateTime(2599, 12, 27), result.Item1.Get("g"));
101105
}
102106

103107
[TestMethod]
@@ -965,8 +969,8 @@ public void TestStringLiteral()
965969
public void TestNumberLiteral()
966970
{
967971
string code = @"
968-
#Const a = &HAF$ 175
969-
#Const b = &O423# 275
972+
#Const a = &HAF$
973+
#Const b = &O423#
970974
#Const c = -50.323e5
971975
";
972976
var result = Preprocess(code);
@@ -1009,6 +1013,30 @@ public void TestKeywordLiterals()
10091013
Assert.AreEqual(VBAEmptyValue.Value, result.Item1.Get("e"));
10101014
}
10111015

1016+
[TestMethod]
1017+
public void TestComplexExpressions()
1018+
{
1019+
string code = @"
1020+
#Const a = 23
1021+
#Const b = 500
1022+
#Const c = a >= b Or True ^ #1/1/1900#
1023+
#Const d = True + #1/1/1800# - (4 * Empty Mod (Abs(-5)))
1024+
";
1025+
var result = Preprocess(code);
1026+
Assert.AreEqual(1m, result.Item1.Get("c"));
1027+
Assert.AreEqual(new DateTime(1799, 12, 31), result.Item1.Get("d"));
1028+
}
1029+
1030+
[TestMethod]
1031+
public void TestOperatorPrecedence()
1032+
{
1033+
string code = @"
1034+
#Const a = 2 ^ 3 + -5 * 40 / 2 \ 4 Mod 2 + 3 - (2 * 4) Xor 4 Eqv 5 Imp 6 Or 2 And True
1035+
";
1036+
var result = Preprocess(code);
1037+
Assert.AreEqual(7m, result.Item1.Get("a"));
1038+
}
1039+
10121040
[TestMethod]
10131041
public void TestPreprocessingLiveDeadCode()
10141042
{
@@ -1081,7 +1109,7 @@ private Tuple<SymbolTable, object> Preprocess(string code)
10811109
var tokens = new CommonTokenStream(lexer);
10821110
var parser = new VBAConditionalCompilationParser(tokens);
10831111
parser.AddErrorListener(new ExceptionErrorListener());
1084-
var evaluator = new VBAPreprocessorVisitor(symbolTable, new VBAPredefinedCompilationConstants("7.01"));
1112+
var evaluator = new VBAPreprocessorVisitor(symbolTable, new VBAPredefinedCompilationConstants(7.01));
10851113
var tree = parser.compilationUnit();
10861114
return Tuple.Create(symbolTable, evaluator.Visit(tree));
10871115
}

0 commit comments

Comments
 (0)