Skip to content

Commit

Permalink
Excel spreadsheet functions, part 3 (unidoc#351)
Browse files Browse the repository at this point in the history
* fixed IF and statistical functions
* Issue unidoc#347
* DATETIME
* DAY, DAYS, Cells() fix
* MONTH
* MINUTE
* EDATE
* EOMONTH
  • Loading branch information
zgordan-vv authored and gunnsth committed Dec 2, 2019
1 parent dd7713e commit 055ebf0
Show file tree
Hide file tree
Showing 11 changed files with 904 additions and 65 deletions.
92 changes: 92 additions & 0 deletions spreadsheet/formula/binaryexpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ func (b BinaryExpr) Eval(ctx Context, ev Evaluator) Result {
return listOp(b.op, lhs.ValueList, rhs.ValueList)
}

} else if lhs.Type == ResultTypeArray && (rhs.Type == ResultTypeNumber || rhs.Type == ResultTypeString) {
return arrayValueOp(b.op, lhs.ValueArray, rhs)
} else if lhs.Type == ResultTypeList && (rhs.Type == ResultTypeNumber || rhs.Type == ResultTypeString) {
return listValueOp(b.op, lhs.ValueList, rhs)
}

// TODO: check for and add support for binary operators on boolean values
Expand Down Expand Up @@ -235,3 +239,91 @@ func listOp(op BinOpType, lhs, rhs []Result) Result {
}
return MakeListResult(res)
}

func arrayValueOp(op BinOpType, lhs [][]Result, rhs Result) Result {
// compare every item of array with a value
res := [][]Result{}
for i := range lhs {
lst := listValueOp(op, lhs[i], rhs)
if lst.Type == ResultTypeError {
return lst
}
res = append(res, lst.ValueList)
}
return MakeArrayResult(res)
}

func listValueOp(op BinOpType, lhs []Result, rhs Result) Result {
res := []Result{}
// we can assume the arrays are the same size here
switch rhs.Type {
case ResultTypeNumber:
rv := rhs.ValueNumber
for i := range lhs {
l := lhs[i].AsNumber()
if l.Type != ResultTypeNumber {
return MakeErrorResult("non-nunmeric value in binary operation")
}
switch op {
case BinOpTypePlus:
res = append(res, MakeNumberResult(l.ValueNumber+rv))
case BinOpTypeMinus:
res = append(res, MakeNumberResult(l.ValueNumber-rv))
case BinOpTypeMult:
res = append(res, MakeNumberResult(l.ValueNumber*rv))
case BinOpTypeDiv:
if rv == 0 {
return MakeErrorResultType(ErrorTypeDivideByZero, "")
}
res = append(res, MakeNumberResult(l.ValueNumber/rv))
case BinOpTypeExp:
res = append(res, MakeNumberResult(math.Pow(l.ValueNumber, rv)))
case BinOpTypeLT:
res = append(res, MakeBoolResult(l.ValueNumber < rv))
case BinOpTypeGT:
res = append(res, MakeBoolResult(l.ValueNumber > rv))
case BinOpTypeEQ:
res = append(res, MakeBoolResult(l.ValueNumber == rv))
case BinOpTypeLEQ:
res = append(res, MakeBoolResult(l.ValueNumber <= rv))
case BinOpTypeGEQ:
res = append(res, MakeBoolResult(l.ValueNumber >= rv))
case BinOpTypeNE:
res = append(res, MakeBoolResult(l.ValueNumber != rv))
// TODO: support concat here
// case BinOpTypeConcat:
default:
return MakeErrorResult(fmt.Sprintf("unsupported list binary op %s", op))
}
}
case ResultTypeString:
rv := rhs.ValueString
for i := range lhs {
l := lhs[i].AsString()
if l.Type != ResultTypeString {
return MakeErrorResult("non-nunmeric value in binary operation")
}
switch op {
case BinOpTypeLT:
res = append(res, MakeBoolResult(l.ValueString < rv))
case BinOpTypeGT:
res = append(res, MakeBoolResult(l.ValueString > rv))
case BinOpTypeEQ:
res = append(res, MakeBoolResult(l.ValueString == rv))
case BinOpTypeLEQ:
res = append(res, MakeBoolResult(l.ValueString <= rv))
case BinOpTypeGEQ:
res = append(res, MakeBoolResult(l.ValueString >= rv))
case BinOpTypeNE:
res = append(res, MakeBoolResult(l.ValueString != rv))
// TODO: support concat here
// case BinOpTypeConcat:
default:
return MakeErrorResult(fmt.Sprintf("unsupported list binary op %s", op))
}
}
default:
return MakeErrorResult("non-nunmeric and non-string value in binary operation")
}
return MakeListResult(res)
}
15 changes: 4 additions & 11 deletions spreadsheet/formula/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ func NewEvaluator() Evaluator {

type defEval struct {
isRef bool
booleans []bool
}

func (d *defEval) Eval(ctx Context, formula string) Result {
Expand Down Expand Up @@ -63,15 +62,6 @@ func (d *defEval) addInfo(ctx Context, expr Expression) {
}
}
}
case "CONCAT", "_xlfn.CONCAT", "CONCATENATE":
d.booleans = []bool{}
for _, arg := range expr.(FunctionCall).args {
switch arg.(type) {
case CellRef:
cr := arg.(CellRef).s
d.booleans = append(d.booleans, ctx.IsBool(cr))
}
}
}
}
}
Expand All @@ -81,7 +71,10 @@ var refRegexp *regexp.Regexp = regexp.MustCompile(`^([a-z]+)([0-9]+)$`)
func validateRef(cr CellRef) bool {
if submatch := refRegexp.FindStringSubmatch(strings.ToLower(cr.s)); len(submatch) > 2 {
col := submatch[1]
row, _ := strconv.Atoi(submatch[2])
row, err := strconv.Atoi(submatch[2])
if err != nil { // for the case if the row number is bigger then int capacity
return false
}
return row <= 1048576 && col <= "zz"
}
return false
Expand Down
Loading

0 comments on commit 055ebf0

Please sign in to comment.