Skip to content

Commit cc4424d

Browse files
Bogdan DamianAntonioLupu
authored andcommitted
Arithmetics operations implementation with error handling and tests
1 parent 0af3c74 commit cc4424d

File tree

8 files changed

+369
-7
lines changed

8 files changed

+369
-7
lines changed

rosetta-lang/model/RosettaExpression.xcore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ interface RosettaBinaryOperation extends RosettaOperation, HasGeneratedInput {
222222
}
223223

224224
class ArithmeticOperation extends RosettaBinaryOperation {
225+
226+
op RosettaInterpreterValue accept(InterpreterVisitor v) {
227+
v.interp(this)
228+
}
225229
}
226230

227231
class LogicalOperation extends RosettaBinaryOperation {

rosetta-lang/model/RosettaInterpreter.xcore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import com.regnosys.rosetta.rosetta.expression.RosettaConditionalExpression
1515
import com.regnosys.rosetta.rosetta.expression.LogicalOperation
1616
import com.regnosys.rosetta.rosetta.expression.EqualityOperation
1717
import com.regnosys.rosetta.rosetta.expression.ComparisonOperation
18+
import com.regnosys.rosetta.rosetta.expression.ArithmeticOperation
1819
import com.regnosys.rosetta.rosetta.expression.RosettaContainsExpression
1920
import com.regnosys.rosetta.rosetta.expression.RosettaDisjointExpression
2021
import com.regnosys.rosetta.rosetta.expression.JoinOperation
@@ -42,6 +43,7 @@ interface InterpreterVisitor {
4243
op RosettaInterpreterValue interp (LogicalOperation exp)
4344
op RosettaInterpreterValue interp (EqualityOperation exp)
4445
op RosettaInterpreterValue interp (ComparisonOperation exp)
46+
op RosettaInterpreterValue interp (ArithmeticOperation exp)
4547
op RosettaInterpreterValue interp (RosettaContainsExpression exp)
4648
op RosettaInterpreterValue interp (RosettaDisjointExpression exp)
4749
op RosettaInterpreterValue interp (JoinOperation exp)

rosetta-lang/src/main/java/com/regnosys/rosetta/interpreternew/RosettaInterpreterVisitor.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.regnosys.rosetta.interpreternew;
22

3+
import com.regnosys.rosetta.rosetta.expression.ArithmeticOperation;
34
import com.regnosys.rosetta.rosetta.expression.LogicalOperation;
45
import com.regnosys.rosetta.rosetta.expression.ComparisonOperation;
56
import com.regnosys.rosetta.rosetta.expression.EqualityOperation;
@@ -24,6 +25,7 @@
2425
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterErrorValue;
2526
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterComparisonOperationInterpreter;
2627
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterListLiteralInterpreter;
28+
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterRosettaArithmeticOperationsInterpreter;
2729
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterListOperationsInterpreter;
2830
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterRosettaBooleanLiteralInterpreter;
2931
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterRosettaConditionalExpressionInterpreter;
@@ -83,6 +85,11 @@ public RosettaInterpreterValue interp(EqualityOperation exp) {
8385
public RosettaInterpreterValue interp(ComparisonOperation exp) {
8486
return new RosettaInterpreterComparisonOperationInterpreter().interp(exp);
8587
}
88+
89+
@Override
90+
public RosettaInterpreterValue interp(ArithmeticOperation exp) {
91+
return new RosettaInterpreterRosettaArithmeticOperationsInterpreter().interp(exp);
92+
}
8693

8794
@Override
8895
public RosettaInterpreterValue interp(RosettaContainsExpression exp) {

rosetta-lang/src/main/java/com/regnosys/rosetta/interpreternew/values/RosettaInterpreterNumberValue.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,24 @@
66

77
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterValue;
88

9+
import com.rosetta.model.lib.RosettaNumber;
10+
911
public class RosettaInterpreterNumberValue extends RosettaInterpreterBaseValue
10-
implements Comparable<RosettaInterpreterNumberValue> {
11-
12-
private BigDecimal value;
12+
implements Comparable<RosettaInterpreterNumberValue> {
13+
private RosettaNumber value;
14+
1315

1416
public RosettaInterpreterNumberValue(BigDecimal value) {
17+
super();
18+
this.value = RosettaNumber.valueOf(value);
19+
}
20+
21+
public RosettaInterpreterNumberValue(RosettaNumber value) {
1522
super();
1623
this.value = value;
1724
}
1825

19-
public BigDecimal getValue() { return value; }
26+
public RosettaNumber getValue() { return value; }
2027

2128
@Override
2229
public int hashCode() {
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package com.regnosys.rosetta.interpreternew.visitors;
2+
3+
import java.util.List;
4+
5+
6+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterError;
7+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterErrorValue;
8+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterIntegerValue;
9+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterNumberValue;
10+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterStringValue;
11+
import com.regnosys.rosetta.rosetta.expression.ArithmeticOperation;
12+
import com.regnosys.rosetta.rosetta.expression.RosettaExpression;
13+
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterValue;
14+
import com.rosetta.model.lib.RosettaNumber;
15+
16+
public class RosettaInterpreterRosettaArithmeticOperationsInterpreter
17+
extends RosettaInterpreterConcreteInterpreter {
18+
/**
19+
* Interprets an arithmetic operation, evaluating the operation between the two terms.
20+
*
21+
* @param expr The ArithmeticOperation expression to interpret
22+
* @return If no errors are encountered, a RosettaInterpreterNumberValue or
23+
* RosettaInterpreterStringValue representing
24+
* the result of the arithmetic/concatenation operation.
25+
* If errors are encountered, a RosettaInterpreterErrorValue representing
26+
* the error.
27+
*/
28+
public RosettaInterpreterValue interp(ArithmeticOperation expr) {
29+
30+
String leftString = null;
31+
String rightString = null;
32+
33+
RosettaExpression left = expr.getLeft();
34+
RosettaExpression right = expr.getRight();
35+
RosettaInterpreterValue leftInterpreted = left.accept(visitor);
36+
RosettaInterpreterValue rightInterpreted = right.accept(visitor);
37+
38+
if (!(leftInterpreted instanceof RosettaInterpreterNumberValue
39+
|| leftInterpreted instanceof RosettaInterpreterStringValue
40+
|| leftInterpreted instanceof RosettaInterpreterIntegerValue)
41+
|| !(rightInterpreted instanceof RosettaInterpreterNumberValue
42+
|| rightInterpreted instanceof RosettaInterpreterStringValue
43+
|| rightInterpreted instanceof RosettaInterpreterIntegerValue)) {
44+
45+
// Check for errors in the left or right side of the binary operation
46+
RosettaInterpreterErrorValue leftErrors =
47+
checkForErrors(leftInterpreted, "Leftside");
48+
RosettaInterpreterErrorValue rightErrors =
49+
checkForErrors(rightInterpreted, "Rightside");
50+
return RosettaInterpreterErrorValue.merge(List.of(leftErrors, rightErrors));
51+
}
52+
53+
boolean sameType =
54+
(leftInterpreted instanceof RosettaInterpreterStringValue
55+
&& rightInterpreted instanceof RosettaInterpreterStringValue)
56+
|| (!(leftInterpreted instanceof RosettaInterpreterStringValue)
57+
&& !(rightInterpreted instanceof RosettaInterpreterStringValue));
58+
if (!sameType) {
59+
return new RosettaInterpreterErrorValue(
60+
new RosettaInterpreterError(
61+
"The terms of the operation "
62+
+ "are neither both strings nor both numbers"));
63+
}
64+
65+
if (leftInterpreted instanceof RosettaInterpreterStringValue) {
66+
leftString = ((RosettaInterpreterStringValue) leftInterpreted)
67+
.getValue();
68+
rightString = ((RosettaInterpreterStringValue) rightInterpreted)
69+
.getValue();
70+
if (expr.getOperator().equals("+")) {
71+
return new RosettaInterpreterStringValue(leftString + rightString);
72+
}
73+
else {
74+
return new RosettaInterpreterErrorValue(
75+
new RosettaInterpreterError(
76+
"The terms are strings but the operation "
77+
+ "is not concatenation: not implemented"));
78+
}
79+
}
80+
81+
RosettaNumber leftNumber;
82+
RosettaNumber rightNumber;
83+
84+
if (leftInterpreted instanceof RosettaInterpreterNumberValue) {
85+
leftNumber = ((RosettaInterpreterNumberValue) leftInterpreted).getValue();
86+
}
87+
else {
88+
leftNumber = RosettaNumber
89+
.valueOf(((RosettaInterpreterIntegerValue) leftInterpreted)
90+
.getValue());
91+
}
92+
if (rightInterpreted instanceof RosettaInterpreterNumberValue) {
93+
rightNumber = ((RosettaInterpreterNumberValue) rightInterpreted).getValue();
94+
} else {
95+
rightNumber = RosettaNumber
96+
.valueOf(((RosettaInterpreterIntegerValue) rightInterpreted)
97+
.getValue());
98+
}
99+
if (expr.getOperator().equals("+")) {
100+
return new RosettaInterpreterNumberValue((leftNumber
101+
.add(rightNumber)).bigDecimalValue());
102+
} else if (expr.getOperator().equals("-")) {
103+
return new RosettaInterpreterNumberValue((leftNumber
104+
.subtract(rightNumber)).bigDecimalValue());
105+
} else if (expr.getOperator().equals("*")) {
106+
return new RosettaInterpreterNumberValue((leftNumber
107+
.multiply(rightNumber)).bigDecimalValue());
108+
} else {
109+
return new RosettaInterpreterNumberValue((leftNumber
110+
.divide(rightNumber)).bigDecimalValue());
111+
}
112+
}
113+
114+
115+
/**
116+
* Helper method that takes an interpretedValue and a string,
117+
* and returns the correct error which
118+
* interpretedValue causes, if any.
119+
*
120+
* @param interpretedValue The interpreted value which we check for errors
121+
* @param side String containing either "Leftside" or "Rightside",
122+
* purely for clearer error messages
123+
* @return The correct RosettaInterpreterErrorValue, or "null"
124+
* if the interpretedValue does not cause an error
125+
*/
126+
private RosettaInterpreterErrorValue checkForErrors(
127+
RosettaInterpreterValue interpretedValue, String side) {
128+
if (interpretedValue instanceof RosettaInterpreterNumberValue
129+
|| interpretedValue instanceof RosettaInterpreterStringValue
130+
|| interpretedValue instanceof RosettaInterpreterIntegerValue) {
131+
// If the value satisfies the type conditions, we return an empty
132+
// error value so that the merger has two error values to merge
133+
return new RosettaInterpreterErrorValue();
134+
}
135+
136+
else if (RosettaInterpreterErrorValue.errorsExist(interpretedValue)) {
137+
// The interpreted value was an error so we propagate it
138+
return (RosettaInterpreterErrorValue) interpretedValue;
139+
} else {
140+
// The interpreted value was not an error,
141+
// but something other than a string or number
142+
return new RosettaInterpreterErrorValue(
143+
new RosettaInterpreterError(
144+
"Arithmetic Operation: " + side
145+
+ " is not of type Number/String"));
146+
}
147+
}
148+
}
149+

0 commit comments

Comments
 (0)