Skip to content

Commit 897b80a

Browse files
author
Diana Şutac
committed
Merge branch 'dev' into data-types
2 parents 9c5e7f3 + 7d6a2f9 commit 897b80a

13 files changed

+537
-22
lines changed

README.md

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,45 +2,92 @@
22

33
An interpreter for a subset of the Rune DSl.
44

5-
For most practical information, refer to the [original readme file](README_project.md)
5+
For more information, refer to the [original Rosetta readme file](README_project.md)
66

7-
## Authors
8-
- Jacek Kulik
9-
- Antonio Lupu
10-
- Maria Cristescu
11-
- Bogdan Damian
12-
- Diana Şutac
7+
## How to build
8+
9+
Refer to the main building instructions in the original readme.
10+
11+
Additionally, open the `interpreternew` module.
12+
13+
If the project still doesn't build try the following steps:
14+
- Mark [xsemantics gen](rosetta-lang/target/xsemantics-gen/main/java/) as a source folder
15+
- Close the projects: `com.regnosys.rosetta.ide`, `com.regnosys.rosetta.profiling`, `com.regnosys.rosetta.tools`, `rosetta-maven-plugin`
16+
- Update the Maven project
1317

1418
## Project Structure
1519

16-
FIGURE HERE
20+
![Class structure Diagram](img/Project_Structure.png)
1721

18-
Rune operations are defined in [xcore files](rosetta-lang/model/RosettaInterpreter.xcore)
22+
Rune operations are defined in [xcore files in the model folder](rosetta-lang/model/). The constructs defined there get auto generated into the generated source folders. They correspond to the objects that the parser can return, and thus are essential for ensuring compatibility with it. It does have some limitations, such as the lack of the notion of many data types, like streams, so some general operations are defined outside those files if they concern more complicated Java constructs. All objects generated via xcore have som associated EObject methods required for them, that are used to get back the original semantics of how they were generated. Thus to implement those methods, the generated objects we make use of also implement `MinimalEObject` to get a base implementation of those methods, if nothing custom is required.
1923

20-
All interpretable operations implement an interp method which takes in an expression and an environment.
24+
All interpretable operations implement an interp method which takes in a visitor and an environment.
2125

2226
There is a visitor which accepts the expressions and passes them along to the correct concrete interpreter to perform their operations.
2327

28+
Each concrete interpreter in the [interpreters module](rosetta-interpreter/src/main/java/com/regnosys/rosetta/interpreternew/visitors/) concerns the interpretation of a certain thematically linked part of Rune operations. For example the List Operators interpreter interprets list `exists`, `absent`, `first`, `only`, `last`, `distinct`, `reverse`, `sum` as they all apply an operation to a list of values and they are somewhat similar in their implementation pattern.
29+
30+
The program flow starts in the [main interpreter file](rosetta-interpreter/src/main/java/com/regnosys/rosetta/interpreternew/RosettaInterpreterNew.java). It contains fields for the visitor and the environment and keeps track of them. When interrpetation is started, this class is used by calling its `interp` method. This starts the interpretation flow and keeps track of the environment
31+
32+
## Error handling and preservation of semantics
33+
34+
All the operations are implementations of `EObject` so they retain information about the original text they were generated from and all other metadata about the parsing process. Thus it is important to preserve that information through the interpretation process.
35+
36+
When an error is encountered, it gets associated with an EObject, such that more diagnostic information can be retaing from it. Currently, the information that is given to the user is the position in the source code of the text that generated the error constructs, though in the future this functionality could be extended.
37+
38+
Errors are stored as `RosettaInterpreterErrorValue`. When an interpretation function encounteres an error value, it should try to propagate that error further up in the computation. This can be achieved by scanning through all the inputs received, and if any errors are found, returning them. The `RosettaInterpreterErrorValue.errorsExist()` and `RosettaInterpreterErrorValue.merge()` methods can be used for those purposes.
39+
40+
## Testing
41+
42+
The benchmark for good testing coverage for this project is 100% branch coverage, and should be achieved wherever possible.
43+
44+
Tests are created in the [interpreter test folder](rosetta-interpreter/src/test/java/com/regnosys/rosetta/interpreternew/)
45+
46+
Useful tools for the testing process:
47+
- Expressionparser: allows for parsing a string representation of a Rune expression into a `RosettaExpression`
48+
- ExpressionFactory: allows for directly instantiating an expression object
49+
- ExpressionValidationHelper: allows for validating that a parsed expression is actually a valid Rune expression
50+
51+
## Checkstyle
52+
53+
The [checkstyle file](checkstyle-SP.xml) is enforced for the project. It is not a very strict checkstyle, but ensures some style guidelines and helps with readability of the codebase.
54+
55+
## CI/CD Pipeline
56+
57+
The [pipeline](.gitlab-ci.yml) runs on the repository after each pushed commit.
58+
59+
It consists of three stages:
60+
1. Build - ensure the codebase compiles and builds successfully
61+
2. Test - run all the tests and ensure they all pass
62+
3. Checkstyle - check all Interpreter source files and ensure they adhere to the checkstyle
63+
2464
## How to extend
2565

2666
### New Expression
2767
The simplest extension is by adding new Rune constructs to interpret. The process for this is:
2868
1. Define the interp method for this expression in [RosettaExpression.xcore](rosetta-lang/model/RosettaExpression.xcore)
29-
2. Create a new class inside [interpreternew.visitors](rosetta-lang/src/main/java/com/regnosys/rosetta/interpreternew/visitors/) OR use one of the already existing ones if it fits thematically
30-
3. Implement a new interp method in [RosettaInterpreterVisitor.java](rosetta-lang/src/main/java/com/regnosys/rosetta/interpreternew/RosettaInterpreterVisitor.java) to accept the new expression
69+
2. Create a new class inside [interpreternew.visitors](rosetta-interpreter/src/main/java/com/regnosys/rosetta/interpreternew/visitors/) OR use one of the already existing ones if it fits thematically
70+
3. Implement a new interp method in [RosettaInterpreterVisitor.java](rosetta-interpreter/src/main/java/com/regnosys/rosetta/interpreternew/RosettaInterpreterVisitor.java) to accept the new expression
3171
4. Implement the interpretation of the expression
32-
5. Test the expression in [the testing module](rosetta-testing/src/test/java/com/regnosys/rosetta/interpreternew/visitors/)
72+
5. Test the expression in [the testing module](rosetta-interpreter/src/test/java/com/regnosys/rosetta/interpreternew/visitors/)
3373

3474
### New Value Domain Type
3575
Right now this process doesn't have any additional steps, but this may change in the future.
3676

37-
1. Create a new class in [the value domain folder](rosetta-lang/src/main/java/com/regnosys/rosetta/interpreternew/values/)
38-
2. Optionally also test the class if it requires it
77+
1. Create a new class in [the value domain folder](rosetta-interpreter/src/main/java/com/regnosys/rosetta/interpreternew/values/)
78+
2. Test the class if it requires it
3979

4080
### New Expression Function
4181

42-
Currently there is only the interpretation function defined for the expressions, but the visitor pattern allows for easily adding a new one.
82+
Currently there is only the interpretation function defined for the expressions, but the visitor pattern allows for adding a new one.
4383

4484
1. Create a new main visitor (like RosettaTypeCheckVisitor)
4585
2. Define accept methods for this visitor for all the expressions
46-
3. Implement concrete acceptors in the new visitor or in new files stemming from it
86+
3. Implement concrete acceptors in the new visitor or in new files stemming from it
87+
88+
## Authors
89+
- Jacek Kulik
90+
- Antonio Lupu
91+
- Maria Cristescu
92+
- Bogdan Damian
93+
- Diana Şutac

img/Project_Structure.png

326 KB
Loading

rosetta-interpreter/.project

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,15 @@
1515
<arguments>
1616
</arguments>
1717
</buildCommand>
18+
<buildCommand>
19+
<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
20+
<arguments>
21+
</arguments>
22+
</buildCommand>
1823
</buildSpec>
1924
<natures>
2025
<nature>org.eclipse.jdt.core.javanature</nature>
2126
<nature>org.eclipse.m2e.core.maven2Nature</nature>
27+
<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
2228
</natures>
2329
</projectDescription>
Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package com.regnosys.rosetta.interpreternew;
22

3+
34
import javax.inject.Inject;
45

56
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterEnvironment;
7+
import com.regnosys.rosetta.rosetta.RosettaEnumeration;
68
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterBaseEnvironment;
79
import com.regnosys.rosetta.rosetta.expression.RosettaExpression;
810
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterValue;
@@ -12,19 +14,56 @@ public class RosettaInterpreterNew {
1214
@Inject
1315
private RosettaInterpreterVisitor visitor;
1416

17+
@Inject
18+
private RosettaInterpreterEnvironment environment;
19+
1520
/**
1621
* Simple example interpret function to allow for better understanding
1722
* of the development workflow.
1823
*
1924
* @param expression the expression to be interpreted
20-
* @return value of RosettaIntLiteral otherwise exception
25+
* @return value of RosettaExpression otherwise exception
2126
*/
2227
public RosettaInterpreterValue interp(RosettaExpression expression) {
23-
return expression.accept(visitor, new RosettaInterpreterEnvironment());
28+
return expression.accept(visitor, environment);
2429
}
2530

31+
/**
32+
* Main interpret function to redirect the interpreter to the correct interpreter.
33+
*
34+
* @param expression the expression to be interpreted
35+
* @return value of RosettaExpression otherwise exception
36+
*/
2637
public RosettaInterpreterValue interp(RosettaExpression expression,
2738
RosettaInterpreterBaseEnvironment env) {
2839
return expression.accept(visitor, env);
2940
}
41+
42+
/**
43+
* Main interpret function for handling enum declaration.
44+
*
45+
* @param expression the expression to be interpreted
46+
* @return value of RosettaExpression otherwise exception
47+
*/
48+
public RosettaInterpreterEnvironment interp(RosettaEnumeration expression,
49+
RosettaInterpreterBaseEnvironment env) {
50+
51+
environment = (RosettaInterpreterEnvironment) expression.accept(visitor, env);
52+
53+
return environment;
54+
}
55+
56+
/**
57+
* Simple example interpret function to allow for better understanding
58+
* of the development workflow. It is used in testing for simplification.
59+
*
60+
* @param expression the expression to be interpreted
61+
* @return value of RosettaIntLiteral otherwise exception
62+
*/
63+
public RosettaInterpreterEnvironment interp(RosettaEnumeration expression) {
64+
65+
environment = (RosettaInterpreterEnvironment) expression.accept(visitor, environment);
66+
67+
return environment;
68+
}
3069
}

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.regnosys.rosetta.rosetta.expression.ArithmeticOperation;
44
import com.regnosys.rosetta.rosetta.expression.LogicalOperation;
5+
import com.regnosys.rosetta.rosetta.RosettaEnumeration;
56
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterBaseEnvironment;
67
import com.regnosys.rosetta.rosetta.expression.ReverseOperation;
78
import com.regnosys.rosetta.rosetta.expression.ComparisonOperation;
@@ -37,6 +38,7 @@
3738
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterError;
3839
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterErrorValue;
3940
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterComparisonOperationInterpreter;
41+
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterEnumerationInterpreter;
4042
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterListLiteralInterpreter;
4143
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterRosettaArithmeticOperationsInterpreter;
4244
import com.regnosys.rosetta.interpreternew.visitors.RosettaInterpreterListOperationsInterpreter;
@@ -220,6 +222,13 @@ public RosettaInterpreterValue interp(SumOperation exp,
220222
return new RosettaInterpreterListOperatorInterpreter().interp(exp,
221223
(RosettaInterpreterEnvironment) env);
222224
}
225+
226+
@Override
227+
public RosettaInterpreterEnvironment interp(RosettaEnumeration exp,
228+
RosettaInterpreterBaseEnvironment env) {
229+
return new RosettaInterpreterEnumerationInterpreter().interp(exp,
230+
(RosettaInterpreterEnvironment) env);
231+
}
223232

224233
@Override
225234
public RosettaInterpreterValue interp(RosettaConstructorExpression exp, RosettaInterpreterBaseEnvironment env) {
@@ -228,7 +237,9 @@ public RosettaInterpreterValue interp(RosettaConstructorExpression exp, RosettaI
228237

229238
@Override
230239
public RosettaInterpreterValue interp(RosettaFeatureCall exp, RosettaInterpreterBaseEnvironment env) {
231-
return new RosettaInterpreterRosettaFeatureCallInterpreter().interp(exp, env);
240+
return new RosettaInterpreterRosettaFeatureCallInterpreter().interp(exp,
241+
(RosettaInterpreterEnvironment) env);
242+
232243
}
233244
}
234245

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.regnosys.rosetta.interpreternew.values;
2+
3+
import java.util.Objects;
4+
import java.util.stream.Stream;
5+
6+
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterValue;
7+
8+
public class RosettaInterpreterEnumElementValue extends RosettaInterpreterBaseValue {
9+
10+
private String enumName;
11+
private String value;
12+
13+
/**
14+
* Constructor for an Enum Element Value.
15+
*
16+
* @param n Name of the Enum
17+
* @param v The String value
18+
*/
19+
public RosettaInterpreterEnumElementValue(String n, String v) {
20+
super();
21+
this.enumName = n;
22+
this.value = v;
23+
}
24+
25+
@Override
26+
public int hashCode() {
27+
return Objects.hash(value);
28+
}
29+
30+
@Override
31+
public String toString() {
32+
return "RosettaInterpreterEnumElementValue [value=" + value + "]";
33+
}
34+
35+
@Override
36+
public boolean equals(Object obj) {
37+
if (this == obj) {
38+
return true;
39+
}
40+
if (obj == null) {
41+
return false;
42+
}
43+
if (getClass() != obj.getClass()) {
44+
return false;
45+
}
46+
RosettaInterpreterEnumElementValue other = (RosettaInterpreterEnumElementValue) obj;
47+
return Objects.equals(value, other.value) && Objects.equals(enumName, other.enumName);
48+
}
49+
50+
public String getValue() { return value; }
51+
52+
public String getEnumName() { return enumName; }
53+
54+
@Override
55+
public Stream<Object> toElementStream() {
56+
return Stream.of(value);
57+
}
58+
59+
@Override
60+
public Stream<RosettaInterpreterValue> toValueStream() {
61+
return Stream.of(this);
62+
}
63+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.regnosys.rosetta.interpreternew.values;
2+
3+
import java.util.List;
4+
import java.util.Objects;
5+
import java.util.stream.Stream;
6+
7+
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterValue;
8+
9+
public class RosettaInterpreterEnumValue extends RosettaInterpreterBaseValue {
10+
11+
private String name;
12+
private List<RosettaInterpreterValue> values;
13+
14+
/**
15+
* Constructor for an Enum Value.
16+
*
17+
* @param name Name of the Enum
18+
* @param values A list of all the String values that the Enum accepts
19+
*/
20+
public RosettaInterpreterEnumValue(String name, List<RosettaInterpreterValue> values) {
21+
super();
22+
this.name = name;
23+
this.values = values;
24+
}
25+
26+
/**
27+
* Method that checks that the enum contains a certain value.
28+
*
29+
* @param name Name of the value that the enum should contain
30+
*/
31+
public boolean containsValueName(String name) {
32+
for (RosettaInterpreterValue v : values) {
33+
if (((RosettaInterpreterEnumElementValue) v).getValue().equals(name)) {
34+
return true;
35+
}
36+
}
37+
return false;
38+
}
39+
40+
public List<RosettaInterpreterValue> getValues() { return values; }
41+
42+
public String getName() { return name; }
43+
44+
@Override
45+
public int hashCode() {
46+
return Objects.hash(values);
47+
}
48+
49+
@Override
50+
public String toString() {
51+
return "RosettaInterpreterListValue [name = " + name + ", values=" + values.toString() + "]";
52+
}
53+
54+
@Override
55+
public boolean equals(Object obj) {
56+
if (this == obj) {
57+
return true;
58+
}
59+
if (obj == null) {
60+
return false;
61+
}
62+
if (getClass() != obj.getClass()) {
63+
return false;
64+
}
65+
RosettaInterpreterEnumValue other = (RosettaInterpreterEnumValue) obj;
66+
return Objects.equals(values, other.values) && Objects.equals(name, other.name);
67+
}
68+
69+
@Override
70+
public Stream<Object> toElementStream() {
71+
return Stream.of(values.toArray());
72+
}
73+
74+
@Override
75+
public Stream<RosettaInterpreterValue> toValueStream() {
76+
return values.stream();
77+
}
78+
}

0 commit comments

Comments
 (0)