-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
- return FormulaError2.NAME.getString();\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);
+
+ }
+
+}