Skip to content
Snippets Groups Projects
Commit e2f997a9 authored by René Schöne's avatar René Schöne
Browse files

Begin with expression sub-language.

parent bd104d8b
No related branches found
No related tags found
No related merge requests found
aspect Expression {
syn boolean LogicalExpression.eval() = false;
eq NotExpression.eval() = !getOperand().eval();
eq ComparingExpression.eval() {
// TODO
return false;
}
eq AndExpression.eval() = getLeftOperand().eval() && getRightOperand().eval();
eq OrExpression.eval() = getLeftOperand().eval() || getRightOperand().eval();
}
abstract Expression ;
abstract NumberExpression : Expression ;
ParenthesizedNumberExpression : NumberExpression ::= Operand:NumberExpression ;
NumberLiteralExpression : NumberExpression ::= <Value:double> ;
// variation point of the expression language:
Designator : NumberExpression ;
rel Designator.Item -> Item ;
abstract BinaryNumberExpression : NumberExpression ::= LeftOperand:NumberExpression RightOperand:NumberExpression ;
AddExpression : BinaryNumberExpression ;
SubExpression : BinaryNumberExpression ;
MultExpression : BinaryNumberExpression ;
DivExpression : BinaryNumberExpression ;
PowerExpression : BinaryNumberExpression ;
abstract LogicalExpression : Expression ;
ParenthesizedLogicalExpression : LogicalExpression ::= Operand:LogicalExpression ;
NotExpression : LogicalExpression ::= Operand:LogicalExpression ;
ComparingExpression : LogicalExpression ::= LeftOperand:NumberExpression RightOperand:NumberExpression <Comparator:ComparatorType> ;
abstract BinaryLogicalExpression : LogicalExpression ::= LeftOperand:LogicalExpression RightOperand:LogicalExpression ;
AndExpression : BinaryLogicalExpression ;
OrExpression : BinaryLogicalExpression ;
...@@ -78,9 +78,13 @@ aspect Rules { ...@@ -78,9 +78,13 @@ aspect Rules {
// --- Condition.holdsFor --- // --- Condition.holdsFor ---
syn boolean Condition.holdsFor(Item item); syn boolean Condition.holdsFor(Item item);
eq ItemStateCheckCondition.holdsFor(Item item) = getItemStateCheck().holdsFor(item); eq ItemStateCheckCondition.holdsFor(Item item) = getItemStateCheck().holdsFor(item);
eq ExpressionCondition.holdsFor(Item item) = getLogicalExpression().eval();
// --- Action.applyFor --- // --- Action.applyFor ---
public abstract void Action.applyFor(Item item); public abstract void Action.applyFor(Item item);
public void NoopAction.applyFor(Item item) {
// empty by design
}
public void LambdaAction.applyFor(Item item) { public void LambdaAction.applyFor(Item item) {
getLambda().accept(item); getLambda().accept(item);
} }
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
Rule ::= Condition* Action* ; Rule ::= Condition* Action* ;
abstract Condition ; abstract Condition ;
ItemStateCheckCondition : Condition ::= ItemStateCheck ; ItemStateCheckCondition : Condition ::= ItemStateCheck ;
ExpressionCondition : Condition ::= LogicalExpression ;
abstract Action ; abstract Action ;
NoopAction : Action ;
LambdaAction : Action ::= <Lambda:Action2EditConsumer> ; LambdaAction : Action ::= <Lambda:Action2EditConsumer> ;
TriggerRuleAction : Action ; TriggerRuleAction : Action ;
......
...@@ -34,7 +34,7 @@ WhiteSpace = [ ] | \t | \f | \n | \r | \r\n ...@@ -34,7 +34,7 @@ WhiteSpace = [ ] | \t | \f | \n | \r | \r\n
Text = \" ([^\"]*) \" Text = \" ([^\"]*) \"
Integer = [:digit:]+ // | "+" [:digit:]+ | "-" [:digit:]+ Integer = [:digit:]+ // | "+" [:digit:]+ | "-" [:digit:]+
//Real = [:digit:]+ "." [:digit:]* | "." [:digit:]+ Real = [:digit:]+ "." [:digit:]* | "." [:digit:]+
Comment = "//" [^\n\r]+ Comment = "//" [^\n\r]+
...@@ -56,6 +56,7 @@ Comment = "//" [^\n\r]+ ...@@ -56,6 +56,7 @@ Comment = "//" [^\n\r]+
"Mqtt" { return sym(Terminals.MQTT); } "Mqtt" { return sym(Terminals.MQTT); }
"Influx" { return sym(Terminals.INFLUX); } "Influx" { return sym(Terminals.INFLUX); }
"ML" { return sym(Terminals.ML); } "ML" { return sym(Terminals.ML); }
"Rule" { return sym(Terminals.RULE); }
// special items (group already has a token definition) // special items (group already has a token definition)
"Activity" { return sym(Terminals.ACTIVITY); } "Activity" { return sym(Terminals.ACTIVITY); }
"Color" { return sym(Terminals.COLOR); } "Color" { return sym(Terminals.COLOR); }
...@@ -101,6 +102,20 @@ Comment = "//" [^\n\r]+ ...@@ -101,6 +102,20 @@ Comment = "//" [^\n\r]+
// special characters // special characters
"=" { return sym(Terminals.EQUALS); } "=" { return sym(Terminals.EQUALS); }
//"\"" { return sym(Terminals.QUOTE); } //"\"" { return sym(Terminals.QUOTE); }
"<" { return sym(Terminals.LE); }
"<=" { return sym(Terminals.LT); }
"==" { return sym(Terminals.EQ); }
"!=" { return sym(Terminals.NE); }
">" { return sym(Terminals.GT); }
">=" { return sym(Terminals.GE); }
"+" { return sym(Terminals.PLUS); }
"*" { return sym(Terminals.MULT); }
"-" { return sym(Terminals.MINUS); }
"/" { return sym(Terminals.DIV); }
"^" { return sym(Terminals.POW); }
"!" { return sym(Terminals.EXCLAMATION); }
"|" { return sym(Terminals.OR); }
"&" { return sym(Terminals.AND); }
":" { return sym(Terminals.COLON); } ":" { return sym(Terminals.COLON); }
"," { return sym(Terminals.COMMA); } "," { return sym(Terminals.COMMA); }
";" { return sym(Terminals.SEMICOLON); } ";" { return sym(Terminals.SEMICOLON); }
...@@ -112,8 +127,8 @@ Comment = "//" [^\n\r]+ ...@@ -112,8 +127,8 @@ Comment = "//" [^\n\r]+
"}" { return sym(Terminals.RB_CURLY); } "}" { return sym(Terminals.RB_CURLY); }
//{Identifier} { return sym(Terminals.NAME); } //{Identifier} { return sym(Terminals.NAME); }
{Text} { return symText(Terminals.TEXT); } {Text} { return symText(Terminals.TEXT); }
//{Real} { return sym(Terminals.REAL); }
{Integer} { return sym(Terminals.INTEGER); } {Integer} { return sym(Terminals.INTEGER); }
{Real} { return sym(Terminals.REAL); }
<<EOF>> { return sym(Terminals.EOF); } <<EOF>> { return sym(Terminals.EOF); }
/* error fallback */ /* error fallback */
[^] { throw new Error("Illegal character '"+ yytext() +"' at line " + (yyline+1) + " column " + (yycolumn+1)); } [^] { throw new Error("Illegal character '"+ yytext() +"' at line " + (yyline+1) + " column " + (yycolumn+1)); }
%header {: %header {:
package de.tudresden.inf.st.eraser.jastadd.parser; package de.tudresden.inf.st.eraser.jastadd.parser;
import de.tudresden.inf.st.eraser.jastadd.model.*; import de.tudresden.inf.st.eraser.jastadd.model.*;
import de.tudresden.inf.st.eraser.jastadd.model.Action;
import de.tudresden.inf.st.eraser.parser.EraserParserHelper; import de.tudresden.inf.st.eraser.parser.EraserParserHelper;
import java.util.Map; import java.util.Map;
import java.util.HashMap; import java.util.HashMap;
...@@ -23,6 +24,8 @@ import java.util.HashMap; ...@@ -23,6 +24,8 @@ import java.util.HashMap;
:} ; :} ;
%goal goal; %goal goal;
%goal number_expression;
%goal logical_expression;
Root goal = Root goal =
thing.t goal.r {: insertZero(r.getOpenHAB2Model().getThingList(), t); return r; :} thing.t goal.r {: insertZero(r.getOpenHAB2Model().getThingList(), t); return r; :}
...@@ -35,6 +38,7 @@ Root goal = ...@@ -35,6 +38,7 @@ Root goal =
| mqtt_root.mr goal.r {: r.setMqttRoot(mr); return r; :} | mqtt_root.mr goal.r {: r.setMqttRoot(mr); return r; :}
| influx_root.ir goal.r {: r.setInfluxRoot(ir); return r; :} | influx_root.ir goal.r {: r.setInfluxRoot(ir); return r; :}
| machine_learning_root.ml goal.r {: r.setMachineLearningRoot(ml); return r; :} | machine_learning_root.ml goal.r {: r.setMachineLearningRoot(ml); return r; :}
| rule.rule goal.r {: r.addRule(rule); return r; :}
| thing.t {: return eph.createRoot(t); :} | thing.t {: return eph.createRoot(t); :}
| item.i {: return eph.createRoot(); :} | item.i {: return eph.createRoot(); :}
| group.g {: return eph.createRoot(g); :} | group.g {: return eph.createRoot(g); :}
...@@ -45,6 +49,48 @@ Root goal = ...@@ -45,6 +49,48 @@ Root goal =
| mqtt_root.mr {: return eph.createRoot(mr); :} | mqtt_root.mr {: return eph.createRoot(mr); :}
| influx_root.ir {: return eph.createRoot(ir); :} | influx_root.ir {: return eph.createRoot(ir); :}
| machine_learning_root.ml {: return eph.createRoot(ml); :} | machine_learning_root.ml {: return eph.createRoot(ml); :}
| rule.rule {: return eph.createRoot(rule); :}
;
%left RB_ROUND;
%left MULT, DIV;
%left PLUS, MINUS;
%left POW;
%left LT, LE, EQ, GE, GT;
%left OR;
%left AND;
NumberExpression number_expression =
LB_ROUND number_expression.a MULT number_expression.b RB_ROUND {: return new MultExpression(a, b); :}
| LB_ROUND number_expression.a DIV number_expression.b RB_ROUND {: return new DivExpression(a, b); :}
| LB_ROUND number_expression.a PLUS number_expression.b RB_ROUND {: return new AddExpression(a, b); :}
| LB_ROUND number_expression.a MINUS number_expression.b RB_ROUND {: return new SubExpression(a, b); :}
| LB_ROUND number_expression.a POW number_expression.b RB_ROUND {: return new PowerExpression(a, b); :}
| literal_expression.l {: return l; :}
| designator.d {: return d; :}
| LB_ROUND number_expression.e RB_ROUND {: return new ParenthesizedNumberExpression(e); :}
;
LogicalExpression logical_expression =
LB_ROUND logical_expression.a AND logical_expression.b RB_ROUND {: return new AndExpression(a, b); :}
| LB_ROUND logical_expression.a OR logical_expression.b RB_ROUND {: return new OrExpression(a, b); :}
| LB_ROUND EXCLAMATION logical_expression.e RB_ROUND {: return new NotExpression(e); :}
| LB_ROUND logical_expression.e RB_ROUND {: return new ParenthesizedLogicalExpression(e); :}
| LB_ROUND number_expression.a LT number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.LessThan); :}
| LB_ROUND number_expression.a LE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.LessOrEqualThan); :}
| LB_ROUND number_expression.a EQ number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.Equals); :}
| LB_ROUND number_expression.a NE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.NotEquals); :}
| LB_ROUND number_expression.a GE number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.GreaterOrEqualThan); :}
| LB_ROUND number_expression.a GT number_expression.b RB_ROUND {: return new ComparingExpression(a, b, ComparatorType.GreaterThan); :}
;
NumberLiteralExpression literal_expression =
INTEGER.n {: return new NumberLiteralExpression(Integer.parseInt(n)); :}
| REAL.n {: return new NumberLiteralExpression(Double.parseDouble(n)); :}
;
Designator designator =
TEXT.n {: return eph.createDesignator(n); :}
; ;
Thing thing = Thing thing =
...@@ -208,6 +254,21 @@ MachineLearningRoot machine_learning_root_body = ...@@ -208,6 +254,21 @@ MachineLearningRoot machine_learning_root_body =
| {: return MachineLearningRoot.createDefault(); :} | {: return MachineLearningRoot.createDefault(); :}
; ;
// Rule: condition=condition action=a1 action=a2;
// (only allow one condition and action for now)
Rule rule =
RULE COLON CONDITION EQUALS condition.c action.a SEMICOLON {: return eph.createRule(c, a); :}
;
Condition condition =
logical_expression.be {: return new ExpressionCondition(be); :}
;
// TODO implement action cases
Action action = {: return new NoopAction(); :}
;
// Util: StringList, StringKeyMap, IntegerKeyMap
StringList string_list = StringList string_list =
LB_SQUARE string_list_body.slb RB_SQUARE {: return slb; :} LB_SQUARE string_list_body.slb RB_SQUARE {: return slb; :}
| LB_SQUARE RB_SQUARE {: return new StringList(); :} | LB_SQUARE RB_SQUARE {: return new StringList(); :}
......
...@@ -7,6 +7,7 @@ import org.apache.logging.log4j.LogManager; ...@@ -7,6 +7,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import java.util.*; import java.util.*;
import java.util.Comparator;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
/** /**
...@@ -29,6 +30,7 @@ public class EraserParserHelper { ...@@ -29,6 +30,7 @@ public class EraserParserHelper {
private Map<Channel, String> missingChannelTypeMap = new HashMap<>(); private Map<Channel, String> missingChannelTypeMap = new HashMap<>();
private Map<Item, String> missingTopicMap = new HashMap<>(); private Map<Item, String> missingTopicMap = new HashMap<>();
private Map<Item, String> missingItemCategoryMap = new HashMap<>(); private Map<Item, String> missingItemCategoryMap = new HashMap<>();
private Map<Designator, String> missingItemForDesignator = new HashMap<>();
private Map<Thing, Iterable<String>> missingChannelListMap = new HashMap<>(); private Map<Thing, Iterable<String>> missingChannelListMap = new HashMap<>();
private Map<Channel, Iterable<String>> missingItemLinkListMap = new HashMap<>(); private Map<Channel, Iterable<String>> missingItemLinkListMap = new HashMap<>();
...@@ -64,11 +66,16 @@ public class EraserParserHelper { ...@@ -64,11 +66,16 @@ public class EraserParserHelper {
* @throws java.util.NoSuchElementException if a reference can not be resolved * @throws java.util.NoSuchElementException if a reference can not be resolved
*/ */
public void resolveReferences() { public void resolveReferences() {
if (this.root == null) {
// when parsing expressions
this.root = createRoot();
}
if (checkUnusedElements) { if (checkUnusedElements) {
fillUnused(); fillUnused();
} }
resolve(thingTypeMap, missingThingTypeMap, Thing::setType); resolve(thingTypeMap, missingThingTypeMap, Thing::setType);
resolve(channelTypeMap, missingChannelTypeMap, Channel::setType); resolve(channelTypeMap, missingChannelTypeMap, Channel::setType);
resolve(itemMap, missingItemForDesignator, Designator::setItem);
missingTopicMap.forEach((topic, parts) -> ParserUtils.createMqttTopic(topic, parts, this.root)); missingTopicMap.forEach((topic, parts) -> ParserUtils.createMqttTopic(topic, parts, this.root));
this.root.getMqttRoot().ensureCorrectPrefixes(); this.root.getMqttRoot().ensureCorrectPrefixes();
...@@ -448,4 +455,24 @@ public class EraserParserHelper { ...@@ -448,4 +455,24 @@ public class EraserParserHelper {
return result; return result;
} }
public Root createRoot(Rule rule) {
Root result = createRoot();
result.addRule(rule);
return result;
}
//+++ newStuff (to be categorized) +++
public Designator createDesignator(String itemName) {
Designator result = new Designator();
missingItemForDesignator.put(result, itemName);
return result;
}
public Rule createRule(Condition c, Action a) {
Rule result = new Rule();
result.addCondition(c);
result.addAction(a);
return result;
}
} }
...@@ -192,4 +192,35 @@ public class ParserUtils { ...@@ -192,4 +192,35 @@ public class ParserUtils {
})); }));
} }
public static NumberExpression parseNumberExpression(String expression_string) throws IOException, Parser.Exception {
return (NumberExpression) parseExpression(expression_string, EraserParser.AltGoals.number_expression);
}
public static LogicalExpression parseLogicalExpression(String expression_string) throws IOException, Parser.Exception {
return (LogicalExpression) parseExpression(expression_string, EraserParser.AltGoals.logical_expression);
}
private static Expression parseExpression(String expression_string, short alt_goal) throws IOException, Parser.Exception {
StringReader reader = new StringReader(expression_string);
if (verboseLoading) {
EraserScanner scanner = new EraserScanner(reader);
try {
Symbol token;
while ((token = scanner.nextToken()).getId() != EraserParser.Terminals.EOF) {
logger.debug("start: {}, end: {}, id: {}, value: {}",
token.getStart(), token.getEnd(), EraserParser.Terminals.NAMES[token.getId()], token.value);
}
} catch (Scanner.Exception e) {
e.printStackTrace();
}
}
reader = new StringReader(expression_string);
EraserScanner scanner = new EraserScanner(reader);
EraserParser parser = new EraserParser();
Expression result = (Expression) parser.parse(scanner, alt_goal);
parser.resolveReferences();
reader.close();
return result;
}
} }
package de.tudresden.inf.st.eraser;
import beaver.Parser;
import de.tudresden.inf.st.eraser.jastadd.model.*;
import de.tudresden.inf.st.eraser.util.ParserUtils;
import org.junit.Test;
import java.io.IOException;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertThat;
/**
* Test correct parsing of NumberExpression and LogicalExpression.
*
* @author rschoene - Initial contribution
*/
public class ExpressionParserTest {
@Test
public void plusExpression() throws IOException, Parser.Exception {
NumberExpression sut = ParserUtils.parseNumberExpression("(3 + 4)");
assertThat(sut, instanceOf(AddExpression.class));
AddExpression addExpression = (AddExpression) sut;
assertThat(addExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression left = (NumberLiteralExpression) addExpression.getLeftOperand();
assertThat(left.getValue(), equalTo(3.0));
assertThat(addExpression.getRightOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression right = (NumberLiteralExpression) addExpression.getRightOperand();
assertThat(right.getValue(), equalTo(4.0));
}
@Test
public void minusExpression() throws IOException, Parser.Exception {
NumberExpression sut = ParserUtils.parseNumberExpression("(12.5 - 4.1)");
assertThat(sut, instanceOf(SubExpression.class));
SubExpression subExpression = (SubExpression) sut;
assertThat(subExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression left = (NumberLiteralExpression) subExpression.getLeftOperand();
assertThat(left.getValue(), equalTo(12.5));
assertThat(subExpression.getRightOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression right = (NumberLiteralExpression) subExpression.getRightOperand();
assertThat(right.getValue(), equalTo(4.1));
}
@Test
public void multExpression() throws IOException, Parser.Exception {
NumberExpression sut = ParserUtils.parseNumberExpression("(0 * 0)");
assertThat(sut, instanceOf(MultExpression.class));
MultExpression multExpression = (MultExpression) sut;
assertThat(multExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression left = (NumberLiteralExpression) multExpression.getLeftOperand();
assertThat(left.getValue(), equalTo(0.0));
assertThat(multExpression.getRightOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression right = (NumberLiteralExpression) multExpression.getRightOperand();
assertThat(right.getValue(), equalTo(0.0));
}
@Test
public void divExpression() throws IOException, Parser.Exception {
NumberExpression sut = ParserUtils.parseNumberExpression("(1.1 / 0.0)");
assertThat(sut, instanceOf(DivExpression.class));
DivExpression divExpression = (DivExpression) sut;
assertThat(divExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression left = (NumberLiteralExpression) divExpression.getLeftOperand();
assertThat(left.getValue(), equalTo(1.1));
assertThat(divExpression.getRightOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression right = (NumberLiteralExpression) divExpression.getRightOperand();
assertThat(right.getValue(), equalTo(0.0));
}
@Test
public void powerExpression() throws IOException, Parser.Exception {
NumberExpression sut = ParserUtils.parseNumberExpression("(3 ^ 0.5)");
assertThat(sut, instanceOf(PowerExpression.class));
PowerExpression powExpression = (PowerExpression) sut;
assertThat(powExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression left = (NumberLiteralExpression) powExpression.getLeftOperand();
assertThat(left.getValue(), equalTo(3.0));
assertThat(powExpression.getRightOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression right = (NumberLiteralExpression) powExpression.getRightOperand();
assertThat(right.getValue(), equalTo(0.5));
}
@Test
public void parenthesizedExpression() throws IOException, Parser.Exception {
NumberExpression sut = ParserUtils.parseNumberExpression("(3)");
assertThat(sut, instanceOf(ParenthesizedNumberExpression.class));
ParenthesizedNumberExpression parenExpression = (ParenthesizedNumberExpression) sut;
assertThat(parenExpression.getOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression left = (NumberLiteralExpression) parenExpression.getOperand();
assertThat(left.getValue(), equalTo(3.0));
}
@Test
public void complexExpression() throws IOException, Parser.Exception {
ParserUtils.setVerboseLoading(true);
NumberExpression sut = ParserUtils.parseNumberExpression("((3 + 4) * (1 / (12 - 8)))");
assertThat(sut, instanceOf(MultExpression.class));
MultExpression multExpression = (MultExpression) sut;
// 3+4
assertThat(multExpression.getLeftOperand(), instanceOf(AddExpression.class));
AddExpression addExpression = (AddExpression) multExpression.getLeftOperand();
assertThat(addExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression left = (NumberLiteralExpression) addExpression.getLeftOperand();
assertThat(left.getValue(), equalTo(3.0));
assertThat(addExpression.getRightOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression right = (NumberLiteralExpression) addExpression.getRightOperand();
assertThat(right.getValue(), equalTo(4.0));
// 1/(12-8)
assertThat(multExpression.getRightOperand(), instanceOf(DivExpression.class));
DivExpression divExpression = (DivExpression) multExpression.getRightOperand();
assertThat(divExpression.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression leftOfDiv = (NumberLiteralExpression) divExpression.getLeftOperand();
assertThat(leftOfDiv.getValue(), equalTo(1.0));
// 12-8
assertThat(divExpression.getRightOperand(), instanceOf(SubExpression.class));
SubExpression rightofDiv = (SubExpression) divExpression.getRightOperand();
assertThat(rightofDiv.getLeftOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression leftOfSSub = (NumberLiteralExpression) rightofDiv.getLeftOperand();
assertThat(leftOfSSub.getValue(), equalTo(12.0));
assertThat(rightofDiv.getRightOperand(), instanceOf(NumberLiteralExpression.class));
NumberLiteralExpression rightOfSub = (NumberLiteralExpression) rightofDiv.getRightOperand();
assertThat(rightOfSub.getValue(), equalTo(8.0));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment