]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.modeling/src/org/simantics/modeling/InvertBasicExpressionVisitor.java
Fixed InvertBasicExpressionVisitor bugs with subtractions and divisions
[simantics/platform.git] / bundles / org.simantics.modeling / src / org / simantics / modeling / InvertBasicExpressionVisitor.java
index 75660a1c5d63201b0a415196a82087855b001877..6293cbac9fd7d9c9fe3c6989e33ac368b5784fe5 100644 (file)
-package org.simantics.modeling;\r
-\r
-import gnu.trove.map.hash.THashMap;\r
-\r
-import java.util.Stack;\r
-\r
-import org.simantics.basicexpression.Expressions;\r
-import org.simantics.basicexpression.analysis.DepthFirstAdapter;\r
-import org.simantics.basicexpression.node.AConstantValue;\r
-import org.simantics.basicexpression.node.ADivMultiplicative;\r
-import org.simantics.basicexpression.node.AMultMultiplicative;\r
-import org.simantics.basicexpression.node.APlusExpression;\r
-import org.simantics.basicexpression.node.AVariablePrimary;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.WriteGraph;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.scl.compiler.types.Type;\r
-import org.simantics.structural.stubs.StructuralResource2;\r
-import org.simantics.utils.datastructures.Pair;\r
-import org.simantics.utils.datastructures.Triple;\r
-\r
-public class InvertBasicExpressionVisitor extends DepthFirstAdapter {\r
-\r
-       Stack<Object> stack = new Stack<Object>();\r
-\r
-       public Object getResult() {\r
-               if(stack.size() != 1) return null; \r
-               return stack.pop();\r
-       }\r
-\r
-       public void outAConstantValue(AConstantValue node) {\r
-               stack.push(Double.valueOf(node.toString()));\r
-       }\r
-\r
-       @Override\r
-       public void outAVariablePrimary(AVariablePrimary node) {\r
-        String value = node.toString().trim();\r
-        stack.push(Triple.make(1.0, 0.0, value));\r
-       }\r
-       \r
-       @SuppressWarnings("unchecked")\r
-    public void outAPlusExpression(APlusExpression node) {\r
-               \r
-               final Object o1 = stack.pop();\r
-               final Object o2 = stack.pop();\r
-               \r
-               if(o1 instanceof Double && o2 instanceof Triple) {\r
-                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
-                       stack.push(Triple.make(p.first, p.second + (Double)o1, p.third));\r
-               } else if (o2 instanceof Double && o1 instanceof Triple) {\r
-                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
-                       stack.push(Triple.make(p.first, p.second + (Double)o2, p.third));\r
-               } else if (o2 instanceof Double && o1 instanceof Double) {\r
-                       stack.push((Double)o1 + (Double)o2);\r
-               } else {\r
-                       stack.push(Double.NaN);\r
-               }\r
-               \r
-       }\r
-\r
-       @SuppressWarnings("unchecked")\r
-    public void outAMinusExpression(APlusExpression node) {\r
-               \r
-               final Object o1 = stack.pop();\r
-               final Object o2 = stack.pop();\r
-               \r
-               if(o1 instanceof Double && o2 instanceof Triple) {\r
-                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
-                       stack.push(Triple.make(-p.first, (Double)o1 - p.second, p.third ));\r
-               } else if (o2 instanceof Double && o1 instanceof Triple) {\r
-                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
-                       stack.push(Triple.make(p.first, p.second - (Double)o2, p.third));\r
-               } else if (o2 instanceof Double && o1 instanceof Double) {\r
-                       stack.push((Double)o1 - (Double)o2);\r
-               } else {\r
-                       stack.push(Double.NaN);\r
-               }\r
-               \r
-       }\r
-\r
-       @SuppressWarnings("unchecked")\r
-    public void outAMultMultiplicative(AMultMultiplicative node) {\r
-               \r
-               final Object o1 = stack.pop();\r
-               final Object o2 = stack.pop();\r
-               \r
-               if(o1 instanceof Double && o2 instanceof Triple) {\r
-                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o2;\r
-                       stack.push(Triple.make(p.first * (Double)o1, p.second * (Double)o1, p.third));\r
-               } else if (o2 instanceof Double && o1 instanceof Triple) {\r
-                       Triple<Double, Double, String> p = (Triple<Double, Double, String>)o1;\r
-                       stack.push(Triple.make(p.first * (Double)o2, p.second * (Double)o2, p.third));\r
-               } else if (o2 instanceof Double && o1 instanceof Double) {\r
-                       stack.push((Double)o1 * (Double)o2);\r
-               } else {\r
-                       stack.push(Double.NaN);\r
-               }\r
-               \r
-       }\r
-\r
-       @SuppressWarnings("unchecked")\r
-    public void outADivMultiplicative(ADivMultiplicative node) {\r
-               \r
-               final Object o1 = stack.pop();\r
-               final Object o2 = stack.pop();\r
-               \r
-               if(o1 instanceof Double && o2 instanceof Triple) {\r
-                       stack.push(Double.NaN);\r
-               } else if (o2 instanceof Double && o1 instanceof Triple) {\r
-                       Triple<Double, Double, String> p = (Triple<Double,Double, String>)o1;\r
-                       stack.push(Triple.make(p.first / (Double)o2, p.second / (Double)o2, p.third));\r
-               } else if (o2 instanceof Double && o1 instanceof Double) {\r
-                       stack.push((Double)o1 / (Double)o2);\r
-               } else {\r
-                       stack.push(Double.NaN);\r
-               }\r
-               \r
-       }\r
-\r
-       private static final String MAGIC = "_111_";\r
-       \r
-       private static String replaced(String expression) {\r
-           return expression.replaceAll("\\.([A-Za-z])", MAGIC + "$1");\r
-       }\r
-       \r
-    public static void invert(WriteGraph graph, Variable base, String expression, Object value) throws DatabaseException {\r
-        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
-        Expressions.evaluate(replaced(expression), visitor);\r
-        Object pair = visitor.getResult();\r
-        if(pair == null) return;\r
-        if(pair instanceof Triple) {\r
-            @SuppressWarnings("unchecked")\r
-            Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
-            String key = data.third.replace(MAGIC, ".");\r
-            String path = getVariablePath(graph, base, key);\r
-            Variable targetVariable = base.browse(graph, path);\r
-            if(value instanceof Number) {\r
-                if(Math.abs(data.first) > 1e-9) {\r
-                    Double inverted = (((Number)value).doubleValue() - data.second) / data.first;\r
-                    targetVariable.setValue(graph, inverted);\r
-                }\r
-            } else if (value instanceof Boolean) {\r
-                // TODO: support 'not'\r
-                targetVariable.setValue(graph, value);\r
-            }\r
-        }\r
-        \r
-    }\r
-    \r
-    private static String getVariablePath(ReadGraph graph, Variable base, String key) throws DatabaseException {\r
-        StructuralResource2 STR = StructuralResource2.getInstance(graph);\r
-        Resource type = base.getPossibleType(graph);\r
-        if(type == null)\r
-            return null;\r
-        boolean procedural = graph.isInstanceOf(type, STR.ProceduralComponentType);\r
-        Pair<String, Type> pair;\r
-        if(procedural)\r
-            pair = graph.sync(new ProceduralSubstructureMapRequest(base)).get(key);\r
-        else\r
-            pair = ComponentTypeSubstructure.forType(graph, type).possibleTypedRVI(key);\r
-        if(pair == null)\r
-            return null;\r
-        return pair.first;\r
-    }\r
-\r
-    /**\r
-     * @param graph\r
-     * @param base\r
-     * @param expression the expression to check for invertibility. An empty is expression is not invertible.\r
-     * @return\r
-     * @throws DatabaseException\r
-     * @throws NullPointerException for null expression\r
-     */\r
-    public static boolean isInvertible(ReadGraph graph, Variable base, String expression) throws DatabaseException {\r
-        if (expression == null)\r
-            throw new NullPointerException("null expression for variable " + base.getURI(graph));\r
-        if (expression.isEmpty())\r
-            return false;\r
-\r
-        Resource type = base.getPossibleType(graph);\r
-        if(type == null) return false;\r
-\r
-        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
-        Expressions.evaluate(replaced(expression), visitor);\r
-        Object pair = visitor.getResult();\r
-        if(pair == null) return false;\r
-        if(pair instanceof Triple) {\r
-            @SuppressWarnings("unchecked")\r
-            Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
-            String key = data.third.replace(MAGIC,".");\r
-            return getVariablePath(graph, base, key) != null;\r
-        }\r
-        return false;\r
-        \r
-    }\r
-\r
-    public static Variable possibleInvertibleExpressionReferencedProperty(ReadGraph graph, Variable base, String expression) throws DatabaseException {\r
-        if (base == null || expression == null || expression.isEmpty())\r
-            return null;\r
-        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();\r
-        //System.out.println("invert : " + expression + " -> " + replaced(expression) + " for " + base.getURI(graph));\r
-        Expressions.evaluate(replaced(expression), visitor);\r
-        Object pair = visitor.getResult();\r
-        if(pair == null)\r
-            return null;\r
-        if(pair instanceof Triple) {\r
-            @SuppressWarnings("unchecked")\r
-            Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;\r
-            String key = data.third.replace(MAGIC,".");\r
-            String path = getVariablePath(graph, base, key);\r
-            Variable targetVariable = base.browsePossible(graph, path);\r
-            return targetVariable;\r
-        }\r
-        return null;\r
-    }\r
-\r
-}\r
+package org.simantics.modeling;
+
+import org.simantics.basicexpression.Expressions;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.WriteGraph;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.utils.datastructures.Pair;
+import org.simantics.utils.datastructures.Triple;
+
+public class InvertBasicExpressionVisitor extends InvertBasicExpressionVisitorBase {
+
+       private static final String MAGIC = "_111_";
+
+       private static String replaced(String expression) {
+           return expression.replaceAll("\\.([A-Za-z])", MAGIC + "$1");
+       }
+
+    public static void invert(WriteGraph graph, Variable base, String expression, Object value) throws DatabaseException {
+        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();
+        Expressions.evaluate(replaced(expression), visitor);
+        Object result = visitor.getResult();
+        if(result == null) return;
+        if(result instanceof Triple) {
+            @SuppressWarnings("unchecked")
+            Triple<Double, Double, String> data = (Triple<Double, Double, String>)result;
+            String key = data.third.replace(MAGIC, ".");
+            String path = getVariablePath(graph, base, key);
+            Variable targetVariable = base.browse(graph, path);
+            if(value instanceof Number) {
+                if(Math.abs(data.first) > 1e-9) {
+                    double inverted = (double) (((Number)value).doubleValue() - data.second) / data.first;
+                    Object invertedValue = numericValueInType(inverted, value.getClass());
+                    targetVariable.setValue(graph, invertedValue);
+                }
+            } else if (value instanceof Boolean) {
+                // TODO: support 'not'
+                targetVariable.setValue(graph, value);
+            }
+        }
+        
+    }
+
+    private static Object numericValueInType(double value, Class<?> type) {
+        if (type == Integer.class) {
+            return (int) value;
+        } else if (type == Long.class) {
+            return (long) value;
+        } else if (type == Byte.class) {
+            return (byte) value;
+        } else if (type == Float.class) {
+            return (float) value;
+        }
+        return value;
+    }
+
+    private static String getVariablePath(ReadGraph graph, Variable base, String key) throws DatabaseException {
+        StructuralResource2 STR = StructuralResource2.getInstance(graph);
+        Resource type = base.getPossibleType(graph);
+        if(type == null)
+            return null;
+        boolean procedural = graph.isInstanceOf(type, STR.ProceduralComponentType);
+        Pair<String, Type> pair;
+        if(procedural)
+            pair = graph.sync(new ProceduralSubstructureMapRequest(base)).get(key);
+        else
+            pair = ComponentTypeSubstructure.forType(graph, type).possibleTypedRVI(key);
+        if(pair == null)
+            return null;
+        return pair.first;
+    }
+
+    /**
+     * @param graph
+     * @param base
+     * @param expression the expression to check for invertibility. An empty is expression is not invertible.
+     * @return
+     * @throws DatabaseException
+     * @throws NullPointerException for null expression
+     */
+    public static boolean isInvertible(ReadGraph graph, Variable base, String expression) throws DatabaseException {
+        if (expression == null)
+            throw new NullPointerException("null expression for variable " + base.getURI(graph));
+        if (expression.isEmpty())
+            return false;
+
+        Resource type = base.getPossibleType(graph);
+        if(type == null) return false;
+
+        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();
+        Expressions.evaluate(replaced(expression), visitor);
+        Object pair = visitor.getResult();
+        if(pair == null) return false;
+        if(pair instanceof Triple) {
+            @SuppressWarnings("unchecked")
+            Triple<Double, Double, String> data = (Triple<Double, Double, String>)pair;
+            String key = data.third.replace(MAGIC,".");
+            return getVariablePath(graph, base, key) != null;
+        }
+        return false;
+        
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Triple<Double, Double, String> possibleInvertibleExpression(ReadGraph graph, Variable base, String expression) throws DatabaseException {
+        if (base == null || expression == null || expression.isEmpty())
+            return null;
+        InvertBasicExpressionVisitor visitor = new InvertBasicExpressionVisitor();
+        //System.out.println("invert : " + expression + " -> " + replaced(expression) + " for " + base.getURI(graph));
+        Expressions.evaluate(replaced(expression), visitor);
+        Object result = visitor.getResult();
+        if (result instanceof Triple)
+            return (Triple<Double, Double, String>) result;
+        return null;
+    }
+
+    public static Variable possibleInvertibleExpressionReferencedProperty(ReadGraph graph, Variable base, String expression) throws DatabaseException {
+        Triple<Double, Double, String> data = possibleInvertibleExpression(graph, base, expression);
+        if (data == null)
+            return null;
+        String path = getVariablePath(graph, base, data.third.replace(MAGIC, "."));
+        return path != null ? base.browsePossible(graph, path) : null;
+    }
+
+    public static Triple<Double, Double, Variable> possibleInvertibleExpressionReferencedTransformedProperty(ReadGraph graph, Variable base, String expression) throws DatabaseException {
+        Triple<Double, Double, String> data = possibleInvertibleExpression(graph, base, expression);
+        if (data == null)
+            return null;
+        String path = getVariablePath(graph, base, data.third.replace(MAGIC, "."));
+        if (path == null)
+            return null;
+        Variable targetVariable = base.browsePossible(graph, path);
+        return targetVariable != null ? Triple.make(data.first, data.second, targetVariable) : null;
+    }
+
+}