From 7adcdbb2a09e447598e588ffbf1d229634ad622a Mon Sep 17 00:00:00 2001
From: tempiaa <tempiaa@eurecom.fr>
Date: Fri, 12 Jun 2020 12:16:18 +0200
Subject: [PATCH] Added syntax check rules to AvaterExpression solvers, added
 tests

---
 .../AvatarExpressionAttribute.java            |  12 +
 .../AvatarExpressionSolver.java               | 259 ++++++++++++++----
 .../AvatarExpressionTest.java                 |  39 ++-
 3 files changed, 242 insertions(+), 68 deletions(-)

diff --git a/src/main/java/avatartranslator/AvatarExpressionAttribute.java b/src/main/java/avatartranslator/AvatarExpressionAttribute.java
index bcf8ffe035..290b018dd3 100644
--- a/src/main/java/avatartranslator/AvatarExpressionAttribute.java
+++ b/src/main/java/avatartranslator/AvatarExpressionAttribute.java
@@ -239,6 +239,18 @@ public class AvatarExpressionAttribute {
         }
     }
     
+    
+    public int getAttributeType() {
+        if (isState) {
+            return AvatarExpressionSolver.IMMEDIATE_BOOL;
+        } else if (block.getAttribute(accessIndex - SpecificationBlock.ATTR_INDEX).getType() == AvatarType.BOOLEAN) {
+            return AvatarExpressionSolver.IMMEDIATE_BOOL;
+        } else {
+            return AvatarExpressionSolver.IMMEDIATE_INT;
+        }
+    }
+    
+    
     public boolean isState() {
         return isState;
     }
diff --git a/src/main/java/avatartranslator/AvatarExpressionSolver.java b/src/main/java/avatartranslator/AvatarExpressionSolver.java
index e73a5c237c..d3bcceef3f 100644
--- a/src/main/java/avatartranslator/AvatarExpressionSolver.java
+++ b/src/main/java/avatartranslator/AvatarExpressionSolver.java
@@ -50,8 +50,10 @@ import avatartranslator.modelchecker.SpecificationState;
  * @version 1.0 17/04/2020
  */
 public class AvatarExpressionSolver {
-    private static final int IMMEDIATE_NO = 0;
-    private static final int IMMEDIATE_INT = 1;
+    protected static final int IMMEDIATE_NO = 0;
+    protected static final int IMMEDIATE_INT = 1;
+    protected static final int IMMEDIATE_BOOL = 2;
+
     
     private AvatarExpressionSolver left, right;
     private char operator;
@@ -59,7 +61,7 @@ public class AvatarExpressionSolver {
     private boolean isLeaf; //variable
     private boolean isNot;
     private boolean isNegated;
-    private int isImmediateValue; //0: No; 1: Boolean; 2: Int
+    private int isImmediateValue; //0: No; 1: Int; 2: Boolean;
     private int intValue;
     private AvatarExpressionAttribute leaf;
     
@@ -93,6 +95,48 @@ public class AvatarExpressionSolver {
     public boolean buildExpression(AvatarSpecification spec) {
         boolean returnVal;
         
+        returnVal = buildExpressionRec(spec); 
+        if (returnVal == false) {
+            return false;
+        }
+        
+        return checkIntegrity();
+    }
+    
+    public boolean buildExpression(AvatarBlock block) {
+        boolean returnVal;
+        
+        returnVal = buildExpressionRec(block); 
+        if (returnVal == false) {
+            return false;
+        }
+        
+        return checkIntegrity();
+    }
+    
+    public boolean buildExpression() {
+        boolean returnVal;
+        
+        returnVal = buildExpressionRec(); 
+        if (returnVal == false) {
+            return false;
+        }
+        
+        return checkIntegrity();
+    }
+    
+    public boolean builExpression(AvatarExpressionAttribute attribute) {
+        this.expression = attribute.toString();
+        isLeaf = true;
+        isImmediateValue = IMMEDIATE_NO;
+        leaf = attribute;
+        return true;
+    }
+    
+    
+    public boolean buildExpressionRec(AvatarSpecification spec) {
+        boolean returnVal;
+        
         removeUselessBrackets();
         
         if (!expression.matches("^.+[\\+\\-<>=:;\\$&\\|\\*/].*$")) {
@@ -103,11 +147,11 @@ public class AvatarExpressionSolver {
             checkNegatedNoBrackets();
             if (expression.equals("true")) {
                 intValue = 1;
-                isImmediateValue = IMMEDIATE_INT;
+                isImmediateValue = IMMEDIATE_BOOL;
                 returnVal = true;
             } else if (expression.equals("false")) {
                 intValue = 0;
-                isImmediateValue = IMMEDIATE_INT;
+                isImmediateValue = IMMEDIATE_BOOL;
                 returnVal = true;
             } else if (expression.matches("-?\\d+")) {
                 intValue = Integer.parseInt(expression);
@@ -145,13 +189,13 @@ public class AvatarExpressionSolver {
         left = new AvatarExpressionSolver(leftExpression);
         right = new AvatarExpressionSolver(rightExpression);
         //System.out.println("Expression " + expression + " ; " + leftExpression + " ; " + rightExpression + "\n");  
-        returnVal = left.buildExpression(spec);
-        returnVal &= right.buildExpression(spec);   
+        returnVal = left.buildExpressionRec(spec);
+        returnVal &= right.buildExpressionRec(spec);   
         
         return returnVal;
     }
     
-    public boolean buildExpression(AvatarBlock block) {
+    public boolean buildExpressionRec(AvatarBlock block) {
         boolean returnVal;
         
         removeUselessBrackets();
@@ -164,11 +208,11 @@ public class AvatarExpressionSolver {
             checkNegatedNoBrackets();
             if (expression.equals("true")) {
                 intValue = 1;
-                isImmediateValue = IMMEDIATE_INT;
+                isImmediateValue = IMMEDIATE_BOOL;
                 returnVal = true;
             } else if (expression.equals("false")) {
                 intValue = 0;
-                isImmediateValue = IMMEDIATE_INT;
+                isImmediateValue = IMMEDIATE_BOOL;
                 returnVal = true;
             } else if (expression.matches("-?\\d+")) {
                 intValue = Integer.parseInt(expression);
@@ -206,21 +250,14 @@ public class AvatarExpressionSolver {
         left = new AvatarExpressionSolver(leftExpression);
         right = new AvatarExpressionSolver(rightExpression);
         //System.out.println("Expression " + expression + " ; " + leftExpression + " ; " + rightExpression + "\n");  
-        returnVal = left.buildExpression(block);
-        returnVal &= right.buildExpression(block);
+        returnVal = left.buildExpressionRec(block);
+        returnVal &= right.buildExpressionRec(block);
         
         return returnVal;
     }
     
-    public boolean builExpression(AvatarExpressionAttribute attribute) {
-        this.expression = attribute.toString();
-        isLeaf = true;
-        isImmediateValue = IMMEDIATE_NO;
-        leaf = attribute;
-        return true;
-    }
     
-    public boolean buildExpression() {
+    public boolean buildExpressionRec() {
         boolean returnVal;
         
         removeUselessBrackets();
@@ -233,11 +270,11 @@ public class AvatarExpressionSolver {
             checkNegatedNoBrackets();
             if (expression.equals("true")) {
                 intValue = 1;
-                isImmediateValue = IMMEDIATE_INT;
+                isImmediateValue = IMMEDIATE_BOOL;
                 returnVal = true;
             } else if (expression.equals("false")) {
                 intValue = 0;
-                isImmediateValue = IMMEDIATE_INT;
+                isImmediateValue = IMMEDIATE_BOOL;
                 returnVal = true;
             } else if (expression.matches("-?\\d+")) {
                 intValue = Integer.parseInt(expression);
@@ -274,8 +311,8 @@ public class AvatarExpressionSolver {
         left = new AvatarExpressionSolver(leftExpression);
         right = new AvatarExpressionSolver(rightExpression);
         //System.out.println("Expression " + expression + " ; " + leftExpression + " ; " + rightExpression + "\n");  
-        returnVal = left.buildExpression();
-        returnVal &= right.buildExpression();
+        returnVal = left.buildExpressionRec();
+        returnVal &= right.buildExpressionRec();
         
         return returnVal;
     }
@@ -346,43 +383,55 @@ public class AvatarExpressionSolver {
         for (i = 0, index = -1; i < expression.length(); i++) {
             a = expression.charAt(i);
             switch (a) {
-            case '=':
+            case '|':
                 if (level == 0) {
                     index = i;
-                    priority = 2;
+                    priority = 5;
+                }
+                break;
+            case '&':
+                if (level == 0 && priority < 5) {
+                    index = i;
+                    priority = 4;
+                }
+                break;
+            case '=':
+                if (level == 0 && priority < 4) {
+                    index = i;
+                    priority = 3;
                 }
                 subVar = true;
                 break;
             case '$':
-                if (level == 0) {
+                if (level == 0 && priority < 4) {
                     index = i;
-                    priority = 2;
+                    priority = 3;
                 }
                 subVar = true;
                 break;
             case '<':
-                if (level == 0) {
+                if (level == 0 && priority < 3) {
                     index = i;
                     priority = 2;
                 }
                 subVar = true;
                 break;
             case '>':
-                if (level == 0) {
+                if (level == 0 && priority < 3) {
                     index = i;
                     priority = 2;
                 }
                 subVar = true;
                 break;
             case ':':
-                if (level == 0) {
+                if (level == 0 && priority < 3) {
                     index = i;
                     priority = 2;
                 }
                 subVar = true;
                 break;
             case ';':
-                if (level == 0) {
+                if (level == 0 && priority < 3) {
                     index = i;
                     priority = 2;
                 }
@@ -400,12 +449,6 @@ public class AvatarExpressionSolver {
                     priority = 1;
                 }
                 break;
-            case '|':
-                if (level == 0 && priority < 2) {
-                    index = i;
-                    priority = 1;
-                }
-                break;
             case '/':
                 if (level == 0  && priority == 0) {
                     index = i;
@@ -416,11 +459,6 @@ public class AvatarExpressionSolver {
                     index = i;
                 }
                 break;
-            case '&':
-                if (level == 0  && priority == 0) {
-                    index = i;
-                }
-                break;
             case '(':
                 level++;
                 subVar = true;
@@ -442,7 +480,7 @@ public class AvatarExpressionSolver {
     public int getResult() {
         int res;
         if (isLeaf) {
-            if (isImmediateValue == IMMEDIATE_INT) {
+            if (isImmediateValue != IMMEDIATE_NO) {
                 res = intValue;
             } else {
                 return 0;
@@ -462,7 +500,7 @@ public class AvatarExpressionSolver {
     public int getResult(SpecificationState ss) {
         int res;
         if (isLeaf) {
-            if (isImmediateValue == IMMEDIATE_INT) {
+            if (isImmediateValue != IMMEDIATE_NO) {
                 res = intValue;
             } else {
                 res = leaf.getValue(ss);
@@ -482,7 +520,7 @@ public class AvatarExpressionSolver {
     public int getResult(SpecificationState ss, AvatarStateMachineElement asme) {
         int res;
         if (isLeaf) {
-            if (isImmediateValue == IMMEDIATE_INT) {
+            if (isImmediateValue != IMMEDIATE_NO) {
                 res = intValue;
             } else {
                 res = leaf.getValue(ss, asme);
@@ -502,7 +540,7 @@ public class AvatarExpressionSolver {
     public int getResult(SpecificationBlock sb) {
         int res;
         if (isLeaf) {
-            if (isImmediateValue == IMMEDIATE_INT) {
+            if (isImmediateValue != IMMEDIATE_NO) {
                 res = intValue;
             } else {
                 res = leaf.getValue(sb);
@@ -573,8 +611,14 @@ public class AvatarExpressionSolver {
         if (isLeaf) {
             if (isImmediateValue == IMMEDIATE_NO) {
                 retS = leaf.toString();
-            } else {
+            } else if (isImmediateValue == IMMEDIATE_INT){
                 retS = String.valueOf(intValue);
+            } else {
+                if (intValue == 0) {
+                    retS = "false";
+                } else {
+                    retS = "true";
+                }
             }
             if (isNegated) {
                 retS = "-(" + retS + ")";
@@ -646,6 +690,51 @@ public class AvatarExpressionSolver {
         }
     }
     
+    private boolean checkIntegrity() {
+        int optype, optypel, optyper;
+        boolean returnVal;
+        
+        if (isLeaf) {
+            if (isNot) {
+                return getReturnType() == IMMEDIATE_BOOL;
+            } else if (isNegated) {
+                return getReturnType() == IMMEDIATE_INT;
+            } else {
+                return true;
+            }
+        }
+        
+        optype = getType();
+        optypel = left.getReturnType();
+        optyper = right.getReturnType();
+                
+        switch(optype) {
+        case IMMEDIATE_NO:
+            returnVal = false; //Error
+            break;
+        case IMMEDIATE_INT:
+            returnVal = (optypel == IMMEDIATE_INT && optyper == IMMEDIATE_INT) ? true : false;
+            break;
+        case IMMEDIATE_BOOL:
+            returnVal = (optypel == IMMEDIATE_BOOL && optyper == IMMEDIATE_BOOL) ? true : false;
+            break;
+        case 3:
+            returnVal = (optypel == optyper) ? true : false;
+            break;
+        default:
+            returnVal = false;
+        }
+        
+        if (returnVal == false) {
+            return false;
+        }
+        
+        returnVal = left.checkIntegrity();
+        returnVal &= right.checkIntegrity();
+
+        return returnVal;
+    }
+    
     private void removeUselessBrackets() {
         while (expression.startsWith("(") && expression.endsWith(")")) {
             if (getClosingBracket(1) == expression.length() - 1) {
@@ -673,5 +762,79 @@ public class AvatarExpressionSolver {
         }
         return -1;
     }
+    
+    private int getType() {
+        int optype;
+        
+        if (isLeaf) {
+            if (isImmediateValue == IMMEDIATE_NO) {
+                return leaf.getAttributeType();
+            } else {
+                return isImmediateValue;
+            }      
+        }
+        
+        switch (operator) {
+        case '=':
+        case '$':
+            optype = 3; //BOTH sides must have the same type
+            break;
+        case '<':
+        case '>':
+        case ':':
+        case ';':
+        case '-':
+        case '+':
+        case '/':
+        case '*':
+            optype = IMMEDIATE_INT;
+            break;
+        case '|':
+        case '&':
+            optype = IMMEDIATE_BOOL;
+            break;
+        default:
+            optype = IMMEDIATE_NO; //ERROR
+            break;
+        }
+        
+        return optype;
+    }
+    
+    private int getReturnType() {
+        int optype;
+        
+        if (isLeaf) {
+            if (isImmediateValue == IMMEDIATE_NO) {
+                return leaf.getAttributeType();
+            } else {
+                return isImmediateValue;
+            }      
+        }
+        
+        switch (operator) {
+        case '<':
+        case '>':
+        case ':':
+        case ';':
+        case '-':
+        case '+':
+        case '/':
+        case '*':
+            optype = IMMEDIATE_INT;
+            break;
+        case '|':
+        case '&':
+        case '=':
+        case '$':
+            optype = IMMEDIATE_BOOL;
+            break;
+        default:
+            optype = IMMEDIATE_NO; //ERROR
+            break;
+        }
+        
+        return optype;
+    }
 
 }
diff --git a/ttool/src/test/java/avatartranslator/AvatarExpressionTest.java b/ttool/src/test/java/avatartranslator/AvatarExpressionTest.java
index 7e1ad29cc7..d941e627c3 100644
--- a/ttool/src/test/java/avatartranslator/AvatarExpressionTest.java
+++ b/ttool/src/test/java/avatartranslator/AvatarExpressionTest.java
@@ -104,22 +104,21 @@ public class AvatarExpressionTest {
     @Test
     public void testImmediate() {
         AvatarExpressionSolver e1 = new AvatarExpressionSolver("10 + 15 >= 20");
-        e1.buildExpression();
+        assertTrue(e1.buildExpression());
         AvatarExpressionSolver e2 = new AvatarExpressionSolver("-10 / 2 - 15 * 2 + 1 == -30 -4");
-        e2.buildExpression();
+        assertTrue(e2.buildExpression());
         AvatarExpressionSolver e3 = new AvatarExpressionSolver("not(-10 / 2 - 15 * 2 + 1 == -(60 - 26))");
-        e3.buildExpression();
+        assertTrue(e3.buildExpression());
         AvatarExpressionSolver e4 = new AvatarExpressionSolver("1 && 0 >= 1 || 0");
-        e4.buildExpression();
+        assertFalse(e4.buildExpression());
         AvatarExpressionSolver e5 = new AvatarExpressionSolver("true and not(false) == not(false or false)");
-        e5.buildExpression();
+        assertTrue(e5.buildExpression());
         AvatarExpressionSolver e6 = new AvatarExpressionSolver("10 -Cabin.match");
+        assertFalse(e6.buildExpression());
         assertTrue(e1.getResult() == 1);
         assertTrue(e2.getResult() == 1);
         assertTrue(e3.getResult() == 0);
-        assertTrue(e4.getResult() == 0);
         assertTrue(e5.getResult() == 1);
-        assertTrue(e6.buildExpression() == false);
     }
     
     @Test
@@ -128,25 +127,25 @@ public class AvatarExpressionTest {
         specBlock.init(block1, false);
         
         AvatarExpressionSolver e1 = new AvatarExpressionSolver("x + y");
-        e1.buildExpression(block1);
+        assertTrue(e1.buildExpression(block1));
         AvatarExpressionSolver e2 = new AvatarExpressionSolver("-x / y - 15 * z + 1 == -31");
-        e2.buildExpression(block1);
+        assertTrue(e2.buildExpression(block1));
         AvatarExpressionSolver e3 = new AvatarExpressionSolver("not(-x / z - (x + y) * 2 + 1 >= -(60 - 26))");
-        e3.buildExpression(block1);
+        assertTrue(e3.buildExpression(block1));
         AvatarExpressionSolver e4 = new AvatarExpressionSolver("(key1==true) and (key2==false)");
-        e4.buildExpression(block1);
+        assertTrue(e4.buildExpression(block1));
         AvatarExpressionSolver e5 = new AvatarExpressionSolver("(key1) and (key2)");
-        e5.buildExpression(block1);
+        assertTrue(e5.buildExpression(block1));
         AvatarExpressionSolver e6 = new AvatarExpressionSolver("(key1==key1) or (key2==key1)");
-        e6.buildExpression(block1);
+        assertTrue(e6.buildExpression(block1));
         AvatarExpressionSolver e7 = new AvatarExpressionSolver("((key1==key1) and not(key2==key1)) and (x - y == z + 3)");
-        e7.buildExpression(block1);
+        assertTrue(e7.buildExpression(block1));
         AvatarExpressionSolver e8 = new AvatarExpressionSolver("x + x*(y+z)/(x + z - x)");
-        e8.buildExpression(block1);
+        assertTrue(e8.buildExpression(block1));
         AvatarExpressionSolver e9 = new AvatarExpressionSolver("x + x*(y+z)*(x - z)");
-        e9.buildExpression(block1);
+        assertTrue(e9.buildExpression(block1));
         AvatarExpressionSolver e10 = new AvatarExpressionSolver("x*((x + y)*z + (x+z)/z)/x");
-        e10.buildExpression(block1);
+        assertTrue(e10.buildExpression(block1));
         assertTrue(e1.getResult(specBlock) == 15);
         assertTrue(e2.getResult(specBlock) == 1);
         assertTrue(e3.getResult(specBlock) == 0);
@@ -165,11 +164,11 @@ public class AvatarExpressionTest {
         ss.setInit(as, false);
         
         AvatarExpressionSolver e1 = new AvatarExpressionSolver("block1.x + block2.y");
-        e1.buildExpression(as);
+        assertTrue(e1.buildExpression(as));
         AvatarExpressionSolver e2 = new AvatarExpressionSolver("-block1.x / block1.y - 15 * block2.z + 1 == -46");
-        e2.buildExpression(as);
+        assertTrue(e2.buildExpression(as));
         AvatarExpressionSolver e3 = new AvatarExpressionSolver("not(-block2.x / block2.z - not(block1.x + block2.y) * -2 + -(1) <= -(-4 + 7))");
-        e3.buildExpression(as);
+        assertFalse(e3.buildExpression(as));
         assertTrue(e1.getResult(ss) == 17);
         assertTrue(e2.getResult(ss) == 1);
         assertTrue(e3.getResult(ss) == 0);
-- 
GitLab