]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.spreadsheet.graph/src/org/simantics/spreadsheet/graph/CellValueVisitor.java
Introduce new DiagramViewer.getRuntimeFromManager()
[simantics/platform.git] / bundles / org.simantics.spreadsheet.graph / src / org / simantics / spreadsheet / graph / CellValueVisitor.java
index b0abb61b15627f3d828fd5404ccb6fd27a533797..8150b4dbadba87104e927a965c1e963970ea2fd0 100644 (file)
-package org.simantics.spreadsheet.graph;\r
-\r
-import org.simantics.databoard.binding.mutable.Variant;\r
-import org.simantics.spreadsheet.Range;\r
-import org.simantics.spreadsheet.graph.formula.FormulaError2;\r
-import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstApply;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstArgList;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstArithmeticExpression;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstArray;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstArrayFormulaReference;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstBoolean;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstDouble;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstFactor;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstIdentifier;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstInteger;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstNothing;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstNull;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstRange;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstRelation;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstString;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstTerm;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstValue;\r
-import org.simantics.spreadsheet.graph.parser.ast.AstValueVisitor;\r
-import org.simantics.spreadsheet.util.SpreadsheetUtils;\r
-\r
-import it.unimi.dsi.fastutil.longs.AbstractLongList;\r
-import it.unimi.dsi.fastutil.longs.LongArrayList;\r
-\r
-public class CellValueVisitor implements AstValueVisitor<Object> {\r
-\r
-       final public SpreadsheetBook book;\r
-       final private SpreadsheetEvaluationEnvironment env;\r
-       final private SpreadsheetCell thisCell;\r
-       final private LongArrayList references = new LongArrayList();\r
-       \r
-       public CellValueVisitor(SpreadsheetEvaluationEnvironment env, SpreadsheetCell thisCell) {\r
-               this.book = env.getBook();\r
-               this.env = env;\r
-               this.thisCell = thisCell;\r
-       }\r
-       \r
-       public void addReference(long ref) {\r
-               references.add(ref);\r
-       }\r
-       \r
-       public AbstractLongList getReferences() {\r
-               return references;\r
-       }\r
-       \r
-       @Override\r
-       public Object visit(AstBoolean astBoolean) {\r
-               return astBoolean.value;\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstDouble astFloat) {\r
-               return astFloat.value;\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstInteger astInteger) {\r
-               return astInteger.value;\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstNull astNull) {\r
-               throw new IllegalStateException();\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstString astString) {\r
-               return astString.value;\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstRange astRange) {\r
-               \r
-               if(astRange.isRef()){\r
-                       return FormulaError2.REF.getString();\r
-               }\r
-               \r
-               if(astRange.isCell()) {\r
-                       String ref = astRange.first;\r
-                       Range r = SpreadsheetUtils.decodeCell(ref, 0, 0);\r
-                       String sheetName = astRange.sheetName != null ? astRange.sheetName : thisCell.getEngine().getName();\r
-                       SpreadsheetCell cell = thisCell.getBook().get(sheetName, r.startRow, r.startColumn);\r
-                       if(cell == null) {\r
-                           SpreadsheetEngine eng = thisCell.getBook().getEngine(sheetName);\r
-                           SpreadsheetLine line = eng.getLine(r.startRow);\r
-                           \r
-                           if (line == null) {\r
-                               line = new SpreadsheetLine(eng.lines, r.startRow);\r
-                               eng.lines.lines.put(-r.startRow, line);\r
-                           }\r
-                           cell = SpreadsheetCell.empty(line, r.startColumn);\r
-                       }\r
-                       return cell.evaluate(env, this);\r
-                       \r
-               } else {\r
-                       \r
-                       Object cached = thisCell.getEngine().getCachedRange(astRange);\r
-                       if(cached != null) {\r
-                               \r
-                               Range r_ = SpreadsheetUtils.decodeRange(astRange.first + ":" + astRange.second);\r
-                               String sheetName = astRange.sheetName != null ? astRange.sheetName : thisCell.getEngine().getName();\r
-                               SpreadsheetEngine eng = thisCell.getBook().getEngine(sheetName);\r
-                               Range r = eng.actualRange(r_);\r
-                               for(int row=0; row < r.height();row++) {\r
-                                       SpreadsheetLine line = eng.getLine(r.startRow + row);\r
-                                       if(line != null) {\r
-                                               for(int column=0; column < r.width();column++) {\r
-                                                       int col = r.startColumn + column;\r
-                                                       if(line.cells.size() > col) {\r
-                                                               SpreadsheetCell cell = line.cells.get(r.startColumn + column);\r
-                                                               //Add references, but do not evaluate if there exists a cached range.\r
-                                                               addReference(cell.makeReferenceKey());\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }       \r
-                               return cached;\r
-                       }\r
-                       \r
-                       Range r_ = SpreadsheetUtils.decodeRange(astRange.first + ":" + astRange.second);\r
-                       String sheetName = astRange.sheetName != null ? astRange.sheetName : thisCell.getEngine().getName();\r
-                       SpreadsheetEngine eng = thisCell.getBook().getEngine(sheetName);\r
-                       // Full ranges are resolved here\r
-                       Range r = eng.actualRange(r_);\r
-                       SpreadsheetMatrix result = new SpreadsheetMatrix(r.width(), r.height());\r
-                       for(int row=0; row < r.height();row++) {\r
-                               SpreadsheetLine line = eng.getLine(r.startRow + row);\r
-                               if(line != null) {\r
-                                       for(int column=0; column < r.width();column++) {\r
-                                               int col = r.startColumn + column;\r
-                                               if(line.cells.size() > col) {\r
-                                                       SpreadsheetCell cell = line.cells.get(r.startColumn + column);\r
-                                                       result.values[r.width()*row + column] = cell.evaluate(env, this);\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-                       thisCell.getEngine().cacheRange(astRange, result);\r
-                       return result;\r
-               }\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstArgList astArgList) {\r
-               throw new IllegalStateException();\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstApply astApply) {\r
-               CellFormulaFunction<?> fn = env.getFunction(astApply.value);\r
-               if(fn != null) {\r
-                       return fn.evaluate(this, astApply.args);\r
-               } else {\r
-                       return FormulaError2.NAME.getString();\r
-               }\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstRelation astRelation) {\r
-\r
-               Object leftResult = astRelation.left.accept(this);\r
-               Object rightResult = astRelation.right.accept(this);\r
-               \r
-               FormulaError2 err = FormulaError2.forObject(leftResult);\r
-               if(err!=null) return err.getString();\r
-               FormulaError2 err2 = FormulaError2.forObject(rightResult);\r
-               if(err2!=null) return err2.getString();\r
-               \r
-               if(leftResult instanceof Variant){\r
-                       Object leftTemp = ((Variant)leftResult).getValue();\r
-                       Double leftVal = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftTemp);\r
-                       if(leftVal==null) leftResult = leftTemp.toString();\r
-                       else leftResult = leftVal;\r
-               }\r
-               if(rightResult instanceof Variant){\r
-                       Object rightTemp = ((Variant)rightResult).getValue();\r
-                       Double rightVal = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(rightTemp);\r
-                       if(rightVal==null) rightResult = rightTemp.toString();\r
-                       else rightResult = rightVal;\r
-               }\r
-               \r
-               if ((leftResult instanceof String) || (rightResult instanceof String)) {\r
-                       String leftString = (leftResult.toString()).toLowerCase();\r
-                       String rightString = (rightResult.toString()).toLowerCase();\r
-                       if("<".equals(astRelation.op.trim())) return leftString.compareTo(rightString) < 0;\r
-                       else if(">".equals(astRelation.op.trim())) return leftString.compareTo(rightString) > 0;\r
-                       else if("=".equals(astRelation.op.trim())) return leftString.compareTo(rightString) == 0;\r
-                       else if("<>".equals(astRelation.op.trim())) return leftString.compareTo(rightString) != 0 ;\r
-                       else if("<=".equals(astRelation.op.trim())) return leftString.compareTo(rightString) <= 0 ;\r
-                       else if(">=".equals(astRelation.op.trim())) return leftString.compareTo(rightString) >= 0 ;\r
-                       else throw new IllegalStateException();\r
-               } else {\r
-                       Number leftNumber = SpreadsheetGraphUtils.asNumber(leftResult);\r
-                       Number rightNumber = SpreadsheetGraphUtils.asNumber(rightResult);\r
-                       if("<".equals(astRelation.op.trim())) return leftNumber.doubleValue() < rightNumber.doubleValue();\r
-                       else if(">".equals(astRelation.op.trim())) return leftNumber.doubleValue() > rightNumber.doubleValue();\r
-                       else if("=".equals(astRelation.op.trim())) return leftNumber.doubleValue() == rightNumber.doubleValue();\r
-                       else if("<>".equals(astRelation.op.trim())) return leftNumber.doubleValue() != rightNumber.doubleValue();\r
-                       else if("<=".equals(astRelation.op.trim())) return leftNumber.doubleValue() <= rightNumber.doubleValue();\r
-                       else if(">=".equals(astRelation.op.trim())) return leftNumber.doubleValue() >= rightNumber.doubleValue();\r
-                       else throw new IllegalStateException();\r
-               }\r
-       }\r
-       \r
-       Object leftValueWithPrefix(Object result, AstValue value, String prefix, boolean forceNumber) {\r
-               if(result == null) {\r
-                       Object obj = value.accept(this);\r
-                       FormulaError2 err = FormulaError2.forObject(obj);\r
-                       if(err!=null) return err.getString();\r
-                       \r
-                       if("-".equals(prefix)) {\r
-                               result = SpreadsheetGraphUtils.asNumber(obj);\r
-                               return -((Number)result).doubleValue();\r
-                       } else {\r
-                               if(forceNumber) return SpreadsheetGraphUtils.asNumber(obj);\r
-                               else return obj;\r
-                       }\r
-               }\r
-               try{\r
-                       return (Number)Double.parseDouble(result.toString());\r
-               } catch (NumberFormatException e){\r
-                       return result;\r
-               }\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstArithmeticExpression exp) {\r
-               Object result = null;\r
-               Object other = null;\r
-               AstValue value = null;\r
-               Object acceptedValue = null;\r
-               \r
-               for(int i=0;i<exp.rightCount();i++) {\r
-                       String op = exp.rightOp(i);\r
-                       value = exp.rightValue(i);\r
-                       acceptedValue = value.accept(this);\r
-                       if("+".equals(op)) {\r
-                               result = leftValueWithPrefix(result, exp.left, exp.prefix, false);\r
-                               \r
-                               if(!(result instanceof Number)) {\r
-                                       FormulaError2 err = FormulaError2.forObject(result);\r
-                                       if(err!=null) return err.getString();\r
-                                       \r
-                                       if(result instanceof String && !((String) result).isEmpty()){\r
-                                               return FormulaError2.VALUE.getString();\r
-                                       } \r
-                                       else if(result instanceof Variant){\r
-                                               Object val = ((Variant)result).getValue();\r
-                                               if(val instanceof String && (val.toString().isEmpty())){\r
-                                                       result = 0.0;\r
-                                               } else {\r
-                                                       Number resNum = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(val);\r
-                                                       if(resNum==null) return FormulaError2.VALUE.getString();\r
-                                                       else result = resNum;\r
-                                               }\r
-                                       } else {\r
-                                               result = 0.0;\r
-                                       }\r
-                               }\r
-                               \r
-                               FormulaError2 err2 = FormulaError2.forObject(acceptedValue);\r
-                               if(err2!=null) return err2.getString();\r
-                               \r
-                               other = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(acceptedValue);\r
-                               if(other==null)\r
-                                       return FormulaError2.handleErrorCall(acceptedValue);\r
-                               \r
-                               result = ((Number)result).doubleValue() + ((Number)other).doubleValue();\r
-                               \r
-                       } else if("-".equals(op)) {\r
-                               result = leftValueWithPrefix(result, exp.left, exp.prefix, false);\r
-                               \r
-                               if(!(result instanceof Number)) {\r
-                                       FormulaError2 err = FormulaError2.forObject(result);\r
-                                       if(err!=null) return err.getString();\r
-                                       \r
-                                       if(result instanceof String && !((String) result).isEmpty()){\r
-                                               return FormulaError2.VALUE.getString();\r
-                                       } \r
-                                       else if(result instanceof Variant){\r
-                                               Object val = ((Variant)result).getValue();\r
-                                               if(val instanceof String && (val.toString().isEmpty())){\r
-                                                       result = 0.0;\r
-                                               } else {\r
-                                                       Number resNum = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(val);\r
-                                                       if(resNum==null)\r
-                                                               return FormulaError2.VALUE.getString();\r
-                                                       else result = resNum;\r
-                                               }\r
-                                       } else {\r
-                                               result = 0.0;\r
-                                       }\r
-                               }\r
-                               FormulaError2 err2 = FormulaError2.forObject(acceptedValue);\r
-                               if(err2!=null) return err2.getString();\r
-                               \r
-                               other = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(acceptedValue);\r
-                               if(other==null)\r
-                                       return FormulaError2.handleErrorCall(acceptedValue);\r
-                               \r
-                               result = ((Number)result).doubleValue() - ((Number)other).doubleValue();\r
-                               \r
-                       } else if("&".equals(op)) {\r
-                               result = leftValueWithPrefix(result, exp.left, exp.prefix, false);\r
-                               FormulaError2 err = FormulaError2.forObject(result);\r
-                               if(err!=null) return err.getString();\r
-                               FormulaError2 err2 = FormulaError2.forObject(acceptedValue);\r
-                               if(err2!=null) return err2.getString();\r
-                               \r
-                               result = SpreadsheetGraphUtils.asString(result);\r
-                               other = SpreadsheetGraphUtils.asString(acceptedValue);\r
-\r
-                               result += (String)other;\r
-                       }\r
-               }\r
-               return leftValueWithPrefix(result, exp.left, exp.prefix, false);\r
-               \r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstTerm exp) {\r
-               Number result = null;\r
-               for(int i=0;i<exp.rightCount();i++) {\r
-                       String op = exp.rightOp(i);\r
-                       AstValue value = exp.rightValue(i);\r
-                       Object leftValue = exp.left.accept(this);\r
-                       Object rightValue = value.accept(this);\r
-                       if("*".equals(op)) {\r
-                               if(result == null) {\r
-                                       result = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftValue);\r
-                                       if(result == null)\r
-                                               return FormulaError2.handleErrorCall(leftValue);\r
-                               }\r
-                               Number other = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(rightValue);\r
-                               if(other==null) return FormulaError2.handleErrorCall(rightValue);\r
-                               \r
-                               result = new Double(result.doubleValue() * other.doubleValue());\r
-                               \r
-                       } else if("/".equals(op)) {\r
-                               if(result == null) {\r
-                                       result = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftValue);\r
-                                       if(result == null)\r
-                                               return FormulaError2.handleErrorCall(leftValue);\r
-                               }\r
-                               Number other = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(rightValue);\r
-                               if(other==null) return FormulaError2.handleErrorCall(rightValue);\r
-                               if(other.doubleValue()==0.0) return FormulaError2.DIV0.getString();\r
-                               \r
-                               result = new Double(result.doubleValue() / other.doubleValue());        \r
-                       }\r
-               }\r
-               if(result == null) result = SpreadsheetGraphUtils.asNumber(exp.left.accept(this));\r
-               return result;\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstFactor exp) {\r
-               Object result = null;\r
-               for(int i=0;i<exp.rightCount();i++) {\r
-                       String op = exp.rightOp(i);\r
-                       AstValue value = exp.rightValue(i);\r
-                       if("^".equals(op)) {\r
-                               if(result == null) {\r
-                                       Object leftValue = exp.left.accept(this);\r
-\r
-                                       FormulaError2 err = FormulaError2.forObject(leftValue);\r
-                                       if(err!=null) return err.getString();\r
-                                       \r
-                                       if(leftValue instanceof Variant){\r
-                                               Object leftTemp = ((Variant)leftValue).getValue();\r
-                                               Double leftV = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftTemp);\r
-                                               if(leftV==null) leftValue = leftTemp.toString();\r
-                                               else leftValue = leftV;\r
-                                       }\r
-                                       \r
-                                       if(leftValue instanceof String){\r
-                                               if((leftValue.toString()).isEmpty())\r
-                                                       result = 0;\r
-                                                else \r
-                                                       return FormulaError2.VALUE.getString();\r
-                                       }\r
-                                       else if(leftValue instanceof SpreadsheetMatrix) \r
-                                               result = leftValue;\r
-                                       else \r
-                                               result = SpreadsheetGraphUtils.asNumber(leftValue);\r
-                               }\r
-                               Object otherValue = value.accept(this);\r
-                               \r
-                               FormulaError2 err2 = FormulaError2.forObject(otherValue);\r
-                               if(err2!=null) return err2.getString();\r
-                               \r
-                               if(otherValue instanceof Variant){\r
-                                       Object otherTemp = ((Variant)otherValue).getValue();\r
-                                       Double otherV = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(otherTemp);\r
-                                       if(otherV==null) otherValue = otherTemp.toString();\r
-                                       else otherValue = otherV;\r
-                               }\r
-                               \r
-                               if(otherValue instanceof String){\r
-                                       if((otherValue.toString()).isEmpty())\r
-                                               otherValue = 0;\r
-                                       else \r
-                                               return FormulaError2.VALUE.getString();\r
-                               }\r
-                               \r
-                               if(result instanceof SpreadsheetMatrix) {\r
-                                       result = ((SpreadsheetMatrix)result).pow(otherValue);\r
-                               } else {\r
-                                       if(otherValue instanceof SpreadsheetMatrix) {\r
-                                               throw new IllegalStateException();\r
-                                       } else {\r
-                                               Double base = ((Number)result).doubleValue();\r
-                                               Double exponent = SpreadsheetGraphUtils.asNumber(otherValue);\r
-                                               if(exponent==0 && base==0)\r
-                                                       return FormulaError2.NUM.getString();\r
-                                               if(exponent<0 && base==0)\r
-                                                       return FormulaError2.DIV0.getString();\r
-                                               result = Math.pow(base, exponent);\r
-                                               if(result instanceof Double && Double.isInfinite((Double)result)){\r
-                                                       return FormulaError2.NUM.getString();\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               if(result == null) result = SpreadsheetGraphUtils.asNumber(exp.left.accept(this));\r
-               return result;\r
-       }\r
-\r
-       @Override\r
-       public Object visit(AstIdentifier id) {\r
-               throw new IllegalStateException();\r
-       }\r
-       \r
-       @Override\r
-       public Object visit(AstArray array) {\r
-               SpreadsheetMatrix m = new SpreadsheetMatrix(array.values.size(), 1);\r
-               for(int i=0;i<array.values.size();i++) {\r
-                       m.values[i] = array.values.get(i).accept(this);\r
-               }\r
-               return m; \r
-       }\r
-       \r
-       @Override\r
-       public Object visit(AstNothing array) {\r
-               return AstNothing.NOTHING;\r
-       }\r
-       \r
-       @Override\r
-       public Object visit(AstArrayFormulaReference ref) {\r
-               \r
-               Range thisRange = SpreadsheetUtils.decodeRange(thisCell.getName());\r
-               Range arrayRange = SpreadsheetUtils.decodeRange(ref.range);\r
-               int x = thisRange.startColumn - arrayRange.startColumn;\r
-               int y = thisRange.startRow - arrayRange.startRow;\r
-               \r
-               SpreadsheetMatrix m = (SpreadsheetMatrix)ref.value.accept(this);\r
-               return m.get(y, x);\r
-               \r
-       }\r
-\r
-}\r
+package org.simantics.spreadsheet.graph;
+
+import org.simantics.databoard.binding.mutable.Variant;
+import org.simantics.spreadsheet.Range;
+import org.simantics.spreadsheet.graph.formula.FormulaError2;
+import org.simantics.spreadsheet.graph.formula.SpreadsheetEvaluationEnvironment;
+import org.simantics.spreadsheet.graph.parser.ast.AstApply;
+import org.simantics.spreadsheet.graph.parser.ast.AstArgList;
+import org.simantics.spreadsheet.graph.parser.ast.AstArithmeticExpression;
+import org.simantics.spreadsheet.graph.parser.ast.AstArray;
+import org.simantics.spreadsheet.graph.parser.ast.AstArrayFormulaReference;
+import org.simantics.spreadsheet.graph.parser.ast.AstBoolean;
+import org.simantics.spreadsheet.graph.parser.ast.AstDouble;
+import org.simantics.spreadsheet.graph.parser.ast.AstFactor;
+import org.simantics.spreadsheet.graph.parser.ast.AstIdentifier;
+import org.simantics.spreadsheet.graph.parser.ast.AstInteger;
+import org.simantics.spreadsheet.graph.parser.ast.AstNothing;
+import org.simantics.spreadsheet.graph.parser.ast.AstNull;
+import org.simantics.spreadsheet.graph.parser.ast.AstRange;
+import org.simantics.spreadsheet.graph.parser.ast.AstRelation;
+import org.simantics.spreadsheet.graph.parser.ast.AstString;
+import org.simantics.spreadsheet.graph.parser.ast.AstTerm;
+import org.simantics.spreadsheet.graph.parser.ast.AstValue;
+import org.simantics.spreadsheet.graph.parser.ast.AstValueVisitor;
+import org.simantics.spreadsheet.util.SpreadsheetUtils;
+
+import it.unimi.dsi.fastutil.longs.AbstractLongList;
+import it.unimi.dsi.fastutil.longs.LongArrayList;
+
+public class CellValueVisitor implements AstValueVisitor<Object> {
+
+       final public SpreadsheetBook book;
+       final private SpreadsheetEvaluationEnvironment env;
+       final private SpreadsheetCell thisCell;
+       final private LongArrayList references = new LongArrayList();
+       
+       public CellValueVisitor(SpreadsheetEvaluationEnvironment env, SpreadsheetCell thisCell) {
+               this.book = env.getBook();
+               this.env = env;
+               this.thisCell = thisCell;
+       }
+       
+       public void addReference(long ref) {
+               references.add(ref);
+       }
+       
+       public AbstractLongList getReferences() {
+               return references;
+       }
+       
+       @Override
+       public Object visit(AstBoolean astBoolean) {
+               return astBoolean.value;
+       }
+
+       @Override
+       public Object visit(AstDouble astFloat) {
+               return astFloat.value;
+       }
+
+       @Override
+       public Object visit(AstInteger astInteger) {
+               return astInteger.value;
+       }
+
+       @Override
+       public Object visit(AstNull astNull) {
+               throw new IllegalStateException();
+       }
+
+       @Override
+       public Object visit(AstString astString) {
+               return astString.value;
+       }
+
+       @Override
+       public Object visit(AstRange astRange) {
+               
+               if(astRange.isRef()){
+                       return FormulaError2.REF.getString();
+               }
+               
+               if(astRange.isCell()) {
+                       String ref = astRange.first;
+                       Range r = SpreadsheetUtils.decodeCell(ref, 0, 0);
+                       String sheetName = astRange.sheetName != null ? astRange.sheetName : thisCell.getEngine().getName();
+                       SpreadsheetCell cell = thisCell.getBook().get(sheetName, r.startRow, r.startColumn);
+                       if(cell == null) {
+                           SpreadsheetEngine eng = thisCell.getBook().getEngine(sheetName);
+                           SpreadsheetLine line = eng.getLine(r.startRow);
+                           
+                           if (line == null) {
+                               line = new SpreadsheetLine(eng.lines, r.startRow);
+                               eng.lines.lines.put(-r.startRow, line);
+                           }
+                           cell = SpreadsheetCell.empty(line, r.startColumn);
+                       }
+                       return cell.evaluate(env, this);
+                       
+               } else {
+                       
+                       Object cached = thisCell.getEngine().getCachedRange(astRange);
+                       if(cached != null) {
+                               
+                               Range r_ = SpreadsheetUtils.decodeRange(astRange.first + ":" + astRange.second);
+                               String sheetName = astRange.sheetName != null ? astRange.sheetName : thisCell.getEngine().getName();
+                               SpreadsheetEngine eng = thisCell.getBook().getEngine(sheetName);
+                               Range r = eng.actualRange(r_);
+                               for(int row=0; row < r.height();row++) {
+                                       SpreadsheetLine line = eng.getLine(r.startRow + row);
+                                       if(line != null) {
+                                               for(int column=0; column < r.width();column++) {
+                                                       int col = r.startColumn + column;
+                                                       if(line.cells.size() > col) {
+                                                               SpreadsheetCell cell = line.cells.get(r.startColumn + column);
+                                                               //Add references, but do not evaluate if there exists a cached range.
+                                                               addReference(cell.makeReferenceKey());
+                                                       }
+                                               }
+                                       }
+                               }       
+                               return cached;
+                       }
+                       
+                       Range r_ = SpreadsheetUtils.decodeRange(astRange.first + ":" + astRange.second);
+                       String sheetName = astRange.sheetName != null ? astRange.sheetName : thisCell.getEngine().getName();
+                       SpreadsheetEngine eng = thisCell.getBook().getEngine(sheetName);
+                       // Full ranges are resolved here
+                       Range r = eng.actualRange(r_);
+                       SpreadsheetMatrix result = new SpreadsheetMatrix(r.width(), r.height());
+                       for(int row=0; row < r.height();row++) {
+                               SpreadsheetLine line = eng.getLine(r.startRow + row);
+                               if(line != null) {
+                                       for(int column=0; column < r.width();column++) {
+                                               int col = r.startColumn + column;
+                                               if(line.cells.size() > col) {
+                                                       SpreadsheetCell cell = line.cells.get(r.startColumn + column);
+                                                       result.values[r.width()*row + column] = cell.evaluate(env, this);
+                                               }
+                                       }
+                               }
+                       }
+                       thisCell.getEngine().cacheRange(astRange, result);
+                       return result;
+               }
+       }
+
+       @Override
+       public Object visit(AstArgList astArgList) {
+               throw new IllegalStateException();
+       }
+
+       @Override
+       public Object visit(AstApply astApply) {
+               CellFormulaFunction<?> fn = env.getFunction(astApply.value);
+               if(fn != null) {
+                       return fn.evaluate(this, astApply.args);
+               } else {
+                       return FormulaError2.NAME.getString();
+               }
+       }
+
+       @Override
+       public Object visit(AstRelation astRelation) {
+
+               Object leftResult = astRelation.left.accept(this);
+               Object rightResult = astRelation.right.accept(this);
+               
+               FormulaError2 err = FormulaError2.forObject(leftResult);
+               if(err!=null) return err.getString();
+               FormulaError2 err2 = FormulaError2.forObject(rightResult);
+               if(err2!=null) return err2.getString();
+               
+               if(leftResult instanceof Variant){
+                       Object leftTemp = ((Variant)leftResult).getValue();
+                       Double leftVal = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftTemp);
+                       if(leftVal==null) leftResult = leftTemp.toString();
+                       else leftResult = leftVal;
+               }
+               if(rightResult instanceof Variant){
+                       Object rightTemp = ((Variant)rightResult).getValue();
+                       Double rightVal = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(rightTemp);
+                       if(rightVal==null) rightResult = rightTemp.toString();
+                       else rightResult = rightVal;
+               }
+               if ((leftResult instanceof String) && (rightResult instanceof String)) {
+                       String leftString = (leftResult.toString()).toLowerCase();
+                       String rightString = (rightResult.toString()).toLowerCase();
+                       if("<".equals(astRelation.op.trim())) return leftString.compareTo(rightString) < 0;
+                       else if(">".equals(astRelation.op.trim())) return leftString.compareTo(rightString) > 0;
+                       else if("=".equals(astRelation.op.trim())) return leftString.compareTo(rightString) == 0;
+                       else if("<>".equals(astRelation.op.trim())) return leftString.compareTo(rightString) != 0 ;
+                       else if("<=".equals(astRelation.op.trim())) return leftString.compareTo(rightString) <= 0 ;
+                       else if(">=".equals(astRelation.op.trim())) return leftString.compareTo(rightString) >= 0 ;
+                       else throw new IllegalStateException();
+               } else {
+                       Number leftNumber = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftResult);
+                       Number rightNumber = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(rightResult);
+                       if(leftNumber==null || rightNumber==null) return false;
+                       if("<".equals(astRelation.op.trim())) return leftNumber.doubleValue() < rightNumber.doubleValue();
+                       else if(">".equals(astRelation.op.trim())) return leftNumber.doubleValue() > rightNumber.doubleValue();
+                       else if("=".equals(astRelation.op.trim())) return leftNumber.doubleValue() == rightNumber.doubleValue();
+                       else if("<>".equals(astRelation.op.trim())) return leftNumber.doubleValue() != rightNumber.doubleValue();
+                       else if("<=".equals(astRelation.op.trim())) return leftNumber.doubleValue() <= rightNumber.doubleValue();
+                       else if(">=".equals(astRelation.op.trim())) return leftNumber.doubleValue() >= rightNumber.doubleValue();
+                       else throw new IllegalStateException();
+               }
+       }
+       
+       Object leftValueWithPrefix(Object result, AstValue value, String prefix, boolean forceNumber) {
+               if(result == null) {
+                       Object obj = value.accept(this);
+                       FormulaError2 err = FormulaError2.forObject(obj);
+                       if(err!=null) return err.getString();
+                       
+                       if("-".equals(prefix)) {
+                               result = SpreadsheetGraphUtils.asNumber(obj);
+                               return -((Number)result).doubleValue();
+                       } else {
+                               if(forceNumber) return SpreadsheetGraphUtils.asNumber(obj);
+                               else return obj;
+                       }
+               }
+               try{
+                       return (Number)Double.parseDouble(result.toString());
+               } catch (NumberFormatException e){
+                       return result;
+               }
+       }
+
+       @Override
+       public Object visit(AstArithmeticExpression exp) {
+               Object result = null;
+               Object other = null;
+               AstValue value = null;
+               Object acceptedValue = null;
+               
+               for(int i=0;i<exp.rightCount();i++) {
+                       String op = exp.rightOp(i);
+                       value = exp.rightValue(i);
+                       acceptedValue = value.accept(this);
+                       if("+".equals(op)) {
+                               result = leftValueWithPrefix(result, exp.left, exp.prefix, false);
+                               
+                               if(!(result instanceof Number)) {
+                                       FormulaError2 err = FormulaError2.forObject(result);
+                                       if(err!=null) return err.getString();
+                                       
+                                       if(result instanceof String && !((String) result).isEmpty()){
+                                               Number num = SpreadsheetGraphUtils.asValidNumber(result);
+                                               if(num == null) {
+                                                       return FormulaError2.VALUE.getString();
+                                               } else {
+                                                       result = num;
+                                               }
+                                       } 
+                                       else if(result instanceof Variant){
+                                               Object val = ((Variant)result).getValue();
+                                               if(val instanceof String && (val.toString().isEmpty())){
+                                                       result = 0.0;
+                                               } else {
+                                                       Number resNum = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(val);
+                                                       if(resNum==null) return FormulaError2.VALUE.getString();
+                                                       else result = resNum;
+                                               }
+                                       } else {
+                                               result = 0.0;
+                                       }
+                               }
+                               
+                               FormulaError2 err2 = FormulaError2.forObject(acceptedValue);
+                               if(err2!=null) return err2.getString();
+                               
+                               other = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(acceptedValue);
+                               if(other==null)
+                                       return FormulaError2.handleErrorCall(acceptedValue);
+                               
+                               result = ((Number)result).doubleValue() + ((Number)other).doubleValue();
+                               
+                       } else if("-".equals(op)) {
+                               result = leftValueWithPrefix(result, exp.left, exp.prefix, false);
+                               
+                               if(!(result instanceof Number)) {
+                                       FormulaError2 err = FormulaError2.forObject(result);
+                                       if(err!=null) return err.getString();
+                                       
+                                       if(result instanceof String && !((String) result).isEmpty()){
+                                               Number num = SpreadsheetGraphUtils.asValidNumber(result);
+                                               if(num == null) {
+                                                       return FormulaError2.VALUE.getString();
+                                               } else {
+                                                       result = num;
+                                               }
+                                       } 
+                                       else if(result instanceof Variant){
+                                               Object val = ((Variant)result).getValue();
+                                               if(val instanceof String && (val.toString().isEmpty())){
+                                                       result = 0.0;
+                                               } else {
+                                                       Number resNum = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(val);
+                                                       if(resNum==null)
+                                                               return FormulaError2.VALUE.getString();
+                                                       else result = resNum;
+                                               }
+                                       } else {
+                                               result = 0.0;
+                                       }
+                               }
+                               FormulaError2 err2 = FormulaError2.forObject(acceptedValue);
+                               if(err2!=null) return err2.getString();
+                               
+                               other = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(acceptedValue);
+                               if(other==null)
+                                       return FormulaError2.handleErrorCall(acceptedValue);
+                               
+                               result = ((Number)result).doubleValue() - ((Number)other).doubleValue();
+                               
+                       } else if("&".equals(op)) {
+                               result = leftValueWithPrefix(result, exp.left, exp.prefix, false);
+                               FormulaError2 err = FormulaError2.forObject(result);
+                               if(err!=null) return err.getString();
+                               FormulaError2 err2 = FormulaError2.forObject(acceptedValue);
+                               if(err2!=null) return err2.getString();
+                               
+                               result = SpreadsheetGraphUtils.asString(result);
+                               other = SpreadsheetGraphUtils.asString(acceptedValue);
+
+                               result += (String)other;
+                       }
+               }
+               return leftValueWithPrefix(result, exp.left, exp.prefix, false);
+               
+       }
+
+       @Override
+       public Object visit(AstTerm exp) {
+               Number result = null;
+               for(int i=0;i<exp.rightCount();i++) {
+                       String op = exp.rightOp(i);
+                       AstValue value = exp.rightValue(i);
+                       Object leftValue = exp.left.accept(this);
+                       Object rightValue = value.accept(this);
+                       if("*".equals(op)) {
+                               if(result == null) {
+                                       result = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftValue);
+                                       if(result == null)
+                                               return FormulaError2.handleErrorCall(leftValue);
+                               }
+                               Number other = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(rightValue);
+                               if(other==null) return FormulaError2.handleErrorCall(rightValue);
+                               
+                               result = new Double(result.doubleValue() * other.doubleValue());
+                               
+                       } else if("/".equals(op)) {
+                               if(result == null) {
+                                       result = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftValue);
+                                       if(result == null)
+                                               return FormulaError2.handleErrorCall(leftValue);
+                               }
+                               Number other = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(rightValue);
+                               if(other==null) return FormulaError2.handleErrorCall(rightValue);
+                               if(other.doubleValue()==0.0) return FormulaError2.DIV0.getString();
+                               
+                               result = new Double(result.doubleValue() / other.doubleValue());        
+                       }
+               }
+               if(result == null) result = SpreadsheetGraphUtils.asNumber(exp.left.accept(this));
+               return result;
+       }
+
+       @Override
+       public Object visit(AstFactor exp) {
+               Object result = null;
+               for(int i=0;i<exp.rightCount();i++) {
+                       String op = exp.rightOp(i);
+                       AstValue value = exp.rightValue(i);
+                       if("^".equals(op)) {
+                               if(result == null) {
+                                       Object leftValue = exp.left.accept(this);
+
+                                       FormulaError2 err = FormulaError2.forObject(leftValue);
+                                       if(err!=null) return err.getString();
+                                       
+                                       if(leftValue instanceof Variant){
+                                               Object leftTemp = ((Variant)leftValue).getValue();
+                                               Double leftV = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(leftTemp);
+                                               if(leftV==null) leftValue = leftTemp.toString();
+                                               else leftValue = leftV;
+                                       }
+                                       
+                                       if(leftValue instanceof String){
+                                               if((leftValue.toString()).isEmpty())
+                                                       result = 0;
+                                                else 
+                                                       return FormulaError2.VALUE.getString();
+                                       }
+                                       else if(leftValue instanceof SpreadsheetMatrix) 
+                                               result = leftValue;
+                                       else 
+                                               result = SpreadsheetGraphUtils.asNumber(leftValue);
+                               }
+                               Object otherValue = value.accept(this);
+                               
+                               FormulaError2 err2 = FormulaError2.forObject(otherValue);
+                               if(err2!=null) return err2.getString();
+                               
+                               if(otherValue instanceof Variant){
+                                       Object otherTemp = ((Variant)otherValue).getValue();
+                                       Double otherV = SpreadsheetGraphUtils.asDoubleWhereEmptyStringIsZero(otherTemp);
+                                       if(otherV==null) otherValue = otherTemp.toString();
+                                       else otherValue = otherV;
+                               }
+                               
+                               if(otherValue instanceof String){
+                                       if((otherValue.toString()).isEmpty())
+                                               otherValue = 0;
+                                       else 
+                                               return FormulaError2.VALUE.getString();
+                               }
+                               
+                               if(result instanceof SpreadsheetMatrix) {
+                                       result = ((SpreadsheetMatrix)result).pow(otherValue);
+                               } else {
+                                       if(otherValue instanceof SpreadsheetMatrix) {
+                                               throw new IllegalStateException();
+                                       } else {
+                                               Double base = ((Number)result).doubleValue();
+                                               Double exponent = SpreadsheetGraphUtils.asNumber(otherValue);
+                                               if(exponent==0 && base==0)
+                                                       return FormulaError2.NUM.getString();
+                                               if(exponent<0 && base==0)
+                                                       return FormulaError2.DIV0.getString();
+                                               result = Math.pow(base, exponent);
+                                               if(result instanceof Double && Double.isInfinite((Double)result)){
+                                                       return FormulaError2.NUM.getString();
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if(result == null) result = SpreadsheetGraphUtils.asNumber(exp.left.accept(this));
+               return result;
+       }
+
+       @Override
+       public Object visit(AstIdentifier id) {
+               return FormulaError2.NAME.getString();
+               //throw new IllegalStateException();
+       }
+       
+       @Override
+       public Object visit(AstArray array) {
+               SpreadsheetMatrix m = new SpreadsheetMatrix(array.values.size(), 1);
+               for(int i=0;i<array.values.size();i++) {
+                       m.values[i] = array.values.get(i).accept(this);
+               }
+               return m; 
+       }
+       
+       @Override
+       public Object visit(AstNothing array) {
+               return AstNothing.NOTHING;
+       }
+       
+       @Override
+       public Object visit(AstArrayFormulaReference ref) {
+               
+               Range thisRange = SpreadsheetUtils.decodeRange(thisCell.getName());
+               Range arrayRange = SpreadsheetUtils.decodeRange(ref.range);
+               int x = thisRange.startColumn - arrayRange.startColumn;
+               int y = thisRange.startRow - arrayRange.startRow;
+               
+               SpreadsheetMatrix m = (SpreadsheetMatrix)ref.value.accept(this);
+               return m.get(y, x);
+               
+       }
+
+}