Skip to content

Commit 967552b

Browse files
author
Bogdan Damian
committed
Added the missing file
1 parent f62575a commit 967552b

File tree

1 file changed

+374
-0
lines changed

1 file changed

+374
-0
lines changed
Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
package com.regnosys.rosetta.interpreternew.visitors;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.stream.Collectors;
7+
8+
9+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterBaseValue;
10+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterBooleanValue;
11+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterDateTimeValue;
12+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterDateValue;
13+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterEnumValue;
14+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterEnvironment;
15+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterError;
16+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterErrorValue;
17+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterFunctionValue;
18+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterListValue;
19+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterNumberValue;
20+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterStringValue;
21+
import com.regnosys.rosetta.interpreternew.values.RosettaInterpreterZonedDateTimeValue;
22+
import com.regnosys.rosetta.rosetta.expression.RosettaExpression;
23+
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterBaseEnvironment;
24+
import com.regnosys.rosetta.rosetta.interpreter.RosettaInterpreterValue;
25+
import com.regnosys.rosetta.rosetta.simple.Condition;
26+
import com.regnosys.rosetta.rosetta.simple.Operation;
27+
import com.regnosys.rosetta.rosetta.simple.ShortcutDeclaration;
28+
import com.regnosys.rosetta.rosetta.simple.impl.AttributeImpl;
29+
import com.regnosys.rosetta.rosetta.simple.impl.FunctionImpl;
30+
31+
32+
public class RosettaInterpreterFunctionInterpreter
33+
extends RosettaInterpreterConcreteInterpreter {
34+
35+
/**
36+
* Interprets a function, returns the result.
37+
*
38+
* @param func The name of the function to interpret
39+
* @param env RosettaInterpreterEnvironment that keeps track
40+
* of the current state of the program
41+
* @return If no errors are encountered, a RosettaInterpreterValue representing
42+
* the value of the function.
43+
* If errors are encountered, a RosettaInterpreterErrorValue representing
44+
* the error.
45+
*/
46+
public RosettaInterpreterValue interp(FunctionImpl func, List<RosettaExpression> args,
47+
RosettaInterpreterEnvironment env) {
48+
49+
final FunctionImpl f = ((RosettaInterpreterFunctionValue) env.findValue(func.getName()))
50+
.getFunction();
51+
RosettaInterpreterErrorValue acc = new RosettaInterpreterErrorValue();
52+
List<RosettaInterpreterValue> interpretedArgs = new ArrayList<>();
53+
RosettaInterpreterEnvironment nv = copyDataTypesOnly(env);
54+
55+
acc = processInputs(f, args, env, interpretedArgs, acc, nv);
56+
if (acc.getErrors().size() > 0) {
57+
return acc;
58+
}
59+
60+
//check the pre-conditions of the function
61+
List<Condition> conditions = func.getConditions();
62+
acc = processConditions(conditions, acc, nv);
63+
if (acc.getErrors().size() > 0) {
64+
return acc;
65+
}
66+
67+
//Add all aliases to the environment, throw errors if any are found
68+
List<ShortcutDeclaration> aliases = f.getShortcuts();
69+
acc = processAliases(aliases, acc, nv);
70+
if (acc.getErrors().size() > 0) {
71+
return acc;
72+
}
73+
74+
75+
//compute the results of all operations in the function
76+
RosettaInterpreterValue result;
77+
result = processOperations(f, args, acc, nv);
78+
if (result instanceof RosettaInterpreterErrorValue) {
79+
return result;
80+
}
81+
82+
//check the post-conditions of the function
83+
nv.addValue(f.getOutput().getName(), result);
84+
conditions = func.getPostConditions();
85+
acc = processConditions(conditions, acc, nv);
86+
if (acc.getErrors().size() > 0) {
87+
return acc;
88+
}
89+
90+
91+
//if everything went well, return the result
92+
return result;
93+
}
94+
95+
/**
96+
* Subroutine for processing the inputs.
97+
*
98+
*
99+
* @param f The function we are interpreting
100+
* @param args The raw arguments
101+
* @param env The original environment
102+
* @param interpretedArgs The interpreted arguments
103+
* @param acc Error accumulator
104+
* @param nv The new, local, environment
105+
* @return The error accumulator, since all correct operations do not require a return value
106+
*/
107+
public RosettaInterpreterErrorValue processInputs(FunctionImpl f, List<RosettaExpression> args,
108+
RosettaInterpreterBaseEnvironment env, List<RosettaInterpreterValue> interpretedArgs,
109+
RosettaInterpreterErrorValue acc, RosettaInterpreterBaseEnvironment nv) {
110+
111+
//interpret the raw arguments
112+
for (RosettaExpression e : args) {
113+
interpretedArgs.add(e.accept(visitor, env));
114+
}
115+
116+
//check if there are any errors in interpreting the arguments. If so, return them
117+
for (RosettaInterpreterValue value : interpretedArgs) {
118+
acc.addAllErrors(value);
119+
}
120+
if (acc.getErrors().size() > 0) {
121+
return acc;
122+
}
123+
124+
//check that all argument/passed value correspond in type and cardinality
125+
//if not, return errors pointing to each attribute reference where this is the case
126+
int inputSize = f.getInputs().size();
127+
for (int i = 0 ; i < inputSize ; i++) {
128+
acc.addAllErrors(checkPair((AttributeImpl) f.getInputs().get(i),
129+
(RosettaInterpreterBaseValue) interpretedArgs.get(i)));
130+
}
131+
if (acc.getErrors().size() > 0) {
132+
return acc;
133+
}
134+
135+
//create a copy of the enums and data types in the passed environment
136+
//since those are the only "global" variables
137+
// RosettaInterpreterEnvironment nv = copyDataTypesOnly(env);
138+
//add all the argument/value pairs to the NEW environment
139+
for (int i = 0 ; i < inputSize ; i++) {
140+
AttributeImpl attr = (AttributeImpl) f.getInputs().get(i);
141+
RosettaInterpreterBaseValue value = (RosettaInterpreterBaseValue) interpretedArgs.get(i);
142+
nv.addValue(attr.getName(), value);
143+
}
144+
return acc;
145+
146+
}
147+
148+
/**
149+
* Subroutine for processing conditions.
150+
*
151+
*
152+
* @param conditions The list of conditions to check
153+
* @param acc Error accumulator
154+
* @param nv The new, local, environment
155+
* @return The error accumulator, since all correct operations do not require a return value
156+
*/
157+
public RosettaInterpreterErrorValue processConditions(List<Condition> conditions,
158+
RosettaInterpreterErrorValue acc, RosettaInterpreterBaseEnvironment nv) {
159+
160+
for (Condition c : conditions) {
161+
RosettaInterpreterValue v = c.getExpression().accept(visitor, nv);
162+
if (v instanceof RosettaInterpreterBooleanValue) {
163+
if (((RosettaInterpreterBooleanValue) v).getValue() == false) {
164+
acc.addError(new RosettaInterpreterError("Condition \""
165+
+ c.getName() + "\" does not hold for this function call"));
166+
}
167+
} else { //must be an error if not a boolean value
168+
acc.addAllErrors(v);
169+
}
170+
}
171+
return acc;
172+
}
173+
174+
/**
175+
* Subroutine for processing aliases.
176+
*
177+
*
178+
* @param aliases The list of aliases to interpret
179+
* @param acc Error accumulator
180+
* @param nv The new, local, environment
181+
* @return The error accumulator, since all correct operations do not require a return value
182+
*/
183+
public RosettaInterpreterErrorValue processAliases(List<ShortcutDeclaration> aliases,
184+
RosettaInterpreterErrorValue acc, RosettaInterpreterBaseEnvironment nv) {
185+
186+
for (ShortcutDeclaration alias : aliases) {
187+
RosettaInterpreterBaseValue val = (RosettaInterpreterBaseValue)
188+
alias.getExpression().accept(visitor, nv);
189+
acc.addAllErrors(val);
190+
nv.addValue(alias.getName(), val);
191+
}
192+
return acc;
193+
}
194+
195+
/**
196+
* Subroutine for processing operations.
197+
*
198+
*
199+
* @param f The function we are interpreting
200+
* @param args The raw arguments
201+
* @param acc Error accumulator
202+
* @param nv The new, local, environment
203+
* @return The error accumulator if there are any errors, and the result value otherwise
204+
*/
205+
public RosettaInterpreterValue processOperations(FunctionImpl f, List<RosettaExpression> args,
206+
RosettaInterpreterErrorValue acc, RosettaInterpreterBaseEnvironment nv) {
207+
208+
209+
List<RosettaInterpreterValue> resultList = new ArrayList<>();;
210+
211+
for (Operation o : f.getOperations()) {
212+
if (o.isAdd()) {
213+
resultList.add(o.getExpression().accept(visitor, nv));
214+
} else {
215+
resultList = ((RosettaInterpreterBaseValue) o.getExpression().accept(visitor, nv))
216+
.toValueStream().collect(Collectors.toList());
217+
}
218+
}
219+
220+
//check that the function operations yield no errors
221+
for (RosettaInterpreterValue value : resultList) {
222+
acc.addAllErrors(value);
223+
} if (acc.getErrors().size() > 0) {
224+
return acc;
225+
}
226+
227+
//check cardinality and type of output matches computed value
228+
RosettaInterpreterBaseValue result;
229+
int upperLimit = f.getOutput().getCard().isUnbounded() ? Integer.MAX_VALUE :
230+
f.getOutput().getCard().getSup();
231+
int lowerLimit = f.getOutput().getCard().getInf();
232+
//make the result a single element or a list depending on its stated cardinality
233+
if (upperLimit == 1 && lowerLimit == 1) {
234+
result = (RosettaInterpreterBaseValue) resultList.get(0);
235+
} else {
236+
result = new RosettaInterpreterListValue(resultList);
237+
}
238+
acc.addAllErrors(checkPair((AttributeImpl) f.getOutput(), result));
239+
if (acc.getErrors().size() > 0) {
240+
return acc;
241+
} else {
242+
return result;
243+
}
244+
}
245+
246+
247+
248+
/**
249+
* Subroutine for checking that the function call is valid based on cardinality and type checking.
250+
*
251+
* @param attr The attribute object that contains the pertinent information
252+
* @param value The interpreted value that is passed to the function
253+
* @return True if the type and cardinality of the attribute and value match, false otherwise
254+
*/
255+
public RosettaInterpreterErrorValue checkPair(AttributeImpl attr, RosettaInterpreterBaseValue value) {
256+
//This will consider only basic types, this will be changed after datatypes are done
257+
String typeName = attr.getTypeCall().getType().getName();
258+
List<RosettaInterpreterValue> vals = value.toValueStream()
259+
.collect(Collectors.toList());
260+
261+
//check that the cardinality of the arg and the value match
262+
int paramSize = vals.size();
263+
int lowerLimit = attr.getCard().getInf();
264+
if (paramSize < lowerLimit) {
265+
return new RosettaInterpreterErrorValue(
266+
new RosettaInterpreterError("The attribute \""
267+
+ attr.getName() + "\" has cardinality lower than the limit "
268+
+ lowerLimit));
269+
}
270+
int upperLimit = attr.getCard().isUnbounded() ? Integer.MAX_VALUE : attr.getCard().getSup();
271+
if (paramSize > upperLimit) {
272+
return new RosettaInterpreterErrorValue(
273+
new RosettaInterpreterError("The attribute \""
274+
+ attr.getName() + "\" has cardinality higher than the limit "
275+
+ upperLimit));
276+
}
277+
278+
//checking that the potential list of elements in arg and value are of the same type
279+
switch (typeName) {
280+
case "number":
281+
for (RosettaInterpreterValue val : vals) {
282+
if (!(val instanceof RosettaInterpreterNumberValue)) {
283+
return new RosettaInterpreterErrorValue(
284+
new RosettaInterpreterError("The attribute \""
285+
+ attr.getName() + "\" requires a number, but received a "
286+
+ val.getClass()));
287+
}
288+
}
289+
break;
290+
case "int":
291+
for (RosettaInterpreterValue val : vals) {
292+
if (!(val instanceof RosettaInterpreterNumberValue)) {
293+
return new RosettaInterpreterErrorValue(
294+
new RosettaInterpreterError("The attribute \""
295+
+ attr.getName() + "\" requires a number, but received a "
296+
+ val.getClass()));
297+
}
298+
}
299+
break;
300+
case "boolean":
301+
for (RosettaInterpreterValue val : vals) {
302+
if (!(val instanceof RosettaInterpreterBooleanValue)) {
303+
return new RosettaInterpreterErrorValue(
304+
new RosettaInterpreterError("The attribute \""
305+
+ attr.getName() + "\" requires a boolean, but received a "
306+
+ val.getClass()));
307+
}
308+
}
309+
break;
310+
case "string":
311+
for (RosettaInterpreterValue val : vals) {
312+
if (!(val instanceof RosettaInterpreterStringValue)) {
313+
return new RosettaInterpreterErrorValue(
314+
new RosettaInterpreterError("The attribute \""
315+
+ attr.getName() + "\" requires a string, but received a "
316+
+ val.getClass()));
317+
}
318+
}
319+
break;
320+
case "date":
321+
for (RosettaInterpreterValue val : vals) {
322+
if (!(val instanceof RosettaInterpreterDateValue)) {
323+
return new RosettaInterpreterErrorValue(
324+
new RosettaInterpreterError("The attribute \""
325+
+ attr.getName() + "\" requires a date, but received a "
326+
+ val.getClass()));
327+
}
328+
}
329+
break;
330+
case "dateTime":
331+
for (RosettaInterpreterValue val : vals) {
332+
if (!(val instanceof RosettaInterpreterDateTimeValue)) {
333+
return new RosettaInterpreterErrorValue(
334+
new RosettaInterpreterError("The attribute \""
335+
+ attr.getName() + "\" requires a dateTime, but received a "
336+
+ val.getClass()));
337+
}
338+
}
339+
break;
340+
case "zonedDateTime":
341+
for (RosettaInterpreterValue val : vals) {
342+
if (!(val instanceof RosettaInterpreterZonedDateTimeValue)) {
343+
return new RosettaInterpreterErrorValue(
344+
new RosettaInterpreterError("The attribute \""
345+
+ attr.getName() + "\" requires a zonedDateTime, but received a "
346+
+ val.getClass()));
347+
}
348+
}
349+
break;
350+
default:
351+
}
352+
//if all checks pass, return true
353+
return new RosettaInterpreterErrorValue();
354+
355+
}
356+
357+
/**
358+
* Subroutine for copying data type/enum declarations from the old environment.
359+
*
360+
* @param env Old environment
361+
* @return new environment that contains the filtered values from the old one
362+
*/
363+
public RosettaInterpreterEnvironment copyDataTypesOnly(RosettaInterpreterEnvironment env) {
364+
RosettaInterpreterEnvironment result = new RosettaInterpreterEnvironment();
365+
Map<String, RosettaInterpreterValue> environment = env.getEnvironment();
366+
for (Map.Entry<String, RosettaInterpreterValue> entry : environment.entrySet()) {
367+
if (entry.getValue() instanceof RosettaInterpreterEnumValue) {
368+
result.addValue(entry.getKey(), entry.getValue());
369+
}
370+
}
371+
return result;
372+
}
373+
374+
}

0 commit comments

Comments
 (0)