X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.spreadsheet%2Fsrc%2Forg%2Fsimantics%2Fspreadsheet%2Fsolver%2Fformula%2FCellValueVisitor.java;fp=bundles%2Forg.simantics.spreadsheet%2Fsrc%2Forg%2Fsimantics%2Fspreadsheet%2Fsolver%2Fformula%2FCellValueVisitor.java;h=fd5ecd167992c74fe87003888e56f249c945712c;hb=c07a3818f0024e932a27eb85cbfd3f2291475a65;hp=0000000000000000000000000000000000000000;hpb=6c99e980d250fb9201aba93be7dcb1f55564dccd;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/formula/CellValueVisitor.java b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/formula/CellValueVisitor.java new file mode 100644 index 000000000..fd5ecd167 --- /dev/null +++ b/bundles/org.simantics.spreadsheet/src/org/simantics/spreadsheet/solver/formula/CellValueVisitor.java @@ -0,0 +1,481 @@ +package org.simantics.spreadsheet.solver.formula; + +import org.simantics.databoard.binding.mutable.Variant; +import org.simantics.spreadsheet.Range; +import org.simantics.spreadsheet.SpreadsheetMatrix; +import org.simantics.spreadsheet.Spreadsheets; +import org.simantics.spreadsheet.solver.SpreadsheetBook; +import org.simantics.spreadsheet.solver.SpreadsheetCell; +import org.simantics.spreadsheet.solver.SpreadsheetEngine; +import org.simantics.spreadsheet.solver.SpreadsheetLine; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstApply; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstArgList; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstArithmeticExpression; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstArray; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstArrayFormulaReference; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstBoolean; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstDouble; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstFactor; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstIdentifier; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstInteger; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstNothing; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstNull; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstRange; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstRelation; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstString; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstTerm; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstValue; +import org.simantics.spreadsheet.solver.formula.parser.ast.AstValueVisitor; + +import it.unimi.dsi.fastutil.longs.AbstractLongList; +import it.unimi.dsi.fastutil.longs.LongArrayList; + +public class CellValueVisitor implements AstValueVisitor { + + 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 = Spreadsheets.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_ = Spreadsheets.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_ = Spreadsheets.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 = Spreadsheets.asDoubleWhereEmptyStringIsZero(leftTemp); + if(leftVal==null) leftResult = leftTemp.toString(); + else leftResult = leftVal; + } + if(rightResult instanceof Variant){ + Object rightTemp = ((Variant)rightResult).getValue(); + Double rightVal = Spreadsheets.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 = Spreadsheets.asDoubleWhereEmptyStringIsZero(leftResult); + Number rightNumber = Spreadsheets.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 = Spreadsheets.asNumber(obj); + return -((Number)result).doubleValue(); + } else { + if(forceNumber) return Spreadsheets.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