From 1c167b96a35a58990f777025914283b492d0785f Mon Sep 17 00:00:00 2001 From: xuri <xuri.me@gmail.com> Date: Thu, 26 May 2022 00:15:28 +0800 Subject: Improves the calculation engine, docs update, and adds the dependabot - Initialize array formula support for the formula calculation engine - Update example and unit test of `AddPivotTable` - Update the supported hash algorithm of ProtectSheet --- calc.go | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) (limited to 'calc.go') diff --git a/calc.go b/calc.go index 8a80fb5..f636d7f 100644 --- a/calc.go +++ b/calc.go @@ -829,6 +829,8 @@ func newEmptyFormulaArg() formulaArg { func (f *File) evalInfixExp(sheet, cell string, tokens []efp.Token) (formulaArg, error) { var err error opdStack, optStack, opfStack, opfdStack, opftStack, argsStack := NewStack(), NewStack(), NewStack(), NewStack(), NewStack(), NewStack() + var inArray, inArrayRow bool + var arrayRow []formulaArg for i := 0; i < len(tokens); i++ { token := tokens[i] @@ -841,6 +843,14 @@ func (f *File) evalInfixExp(sheet, cell string, tokens []efp.Token) (formulaArg, // function start if isFunctionStartToken(token) { + if token.TValue == "ARRAY" { + inArray = true + continue + } + if token.TValue == "ARRAYROW" { + inArrayRow = true + continue + } opfStack.Push(token) argsStack.Push(list.New().Init()) opftStack.Push(token) // to know which operators belong to a function use the function as a separator @@ -922,7 +932,19 @@ func (f *File) evalInfixExp(sheet, cell string, tokens []efp.Token) (formulaArg, if token.TType == efp.TokenTypeOperand && token.TSubType == efp.TokenSubTypeLogical { argsStack.Peek().(*list.List).PushBack(newStringFormulaArg(token.TValue)) } - + if inArrayRow && isOperand(token) { + arrayRow = append(arrayRow, tokenToFormulaArg(token)) + continue + } + if inArrayRow && isFunctionStopToken(token) { + inArrayRow = false + continue + } + if inArray && isFunctionStopToken(token) { + argsStack.Peek().(*list.List).PushBack(opfdStack.Pop()) + arrayRow, inArray = []formulaArg{}, false + continue + } if err = f.evalInfixExpFunc(sheet, cell, token, nextToken, opfStack, opdStack, opftStack, opfdStack, argsStack); err != nil { return newEmptyFormulaArg(), err } @@ -1274,6 +1296,15 @@ func isOperand(token efp.Token) bool { return token.TType == efp.TokenTypeOperand && (token.TSubType == efp.TokenSubTypeNumber || token.TSubType == efp.TokenSubTypeText) } +// tokenToFormulaArg create a formula argument by given token. +func tokenToFormulaArg(token efp.Token) formulaArg { + if token.TSubType == efp.TokenSubTypeNumber { + num, _ := strconv.ParseFloat(token.TValue, 64) + return newNumberFormulaArg(num) + } + return newStringFormulaArg(token.TValue) +} + // parseToken parse basic arithmetic operator priority and evaluate based on // operators and operands. func (f *File) parseToken(sheet string, token efp.Token, opdStack, optStack *Stack) error { @@ -1318,12 +1349,7 @@ func (f *File) parseToken(sheet string, token efp.Token, opdStack, optStack *Sta } // opd if isOperand(token) { - if token.TSubType == efp.TokenSubTypeNumber { - num, _ := strconv.ParseFloat(token.TValue, 64) - opdStack.Push(newNumberFormulaArg(num)) - } else { - opdStack.Push(newStringFormulaArg(token.TValue)) - } + opdStack.Push(tokenToFormulaArg(token)) } return nil } -- cgit v1.2.1