-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);
-
- }
-
-}