evalInfixExp evaluate syntax analysis by given infix expression after lexical analysis. Evaluate an infix expression containing formulas by stacks: opd - Operand opt - Operator opf - Operation formula opfd - Operand of the operation formula opft - Operator of the operation formula args - A
(ctx *calcContext, sheet, cell string, tokens []efp.Token)
| 977 | // |
| 978 | // TODO: handle subtypes: Nothing, Text, Logical, Error, Concatenation, Intersection, Union |
| 979 | func (f *File) evalInfixExp(ctx *calcContext, sheet, cell string, tokens []efp.Token) (formulaArg, error) { |
| 980 | var ( |
| 981 | err error |
| 982 | inArray, inArrayRow bool |
| 983 | formulaArray [][]formulaArg |
| 984 | formulaArrayRow []formulaArg |
| 985 | opdStack, optStack, opfStack = NewStack(), NewStack(), NewStack() |
| 986 | opfdStack, opftStack, argsStack = NewStack(), NewStack(), NewStack() |
| 987 | ) |
| 988 | for i := 0; i < len(tokens); i++ { |
| 989 | token := tokens[i] |
| 990 | |
| 991 | // out of function stack |
| 992 | if opfStack.Len() == 0 { |
| 993 | if err = f.parseToken(ctx, sheet, token, opdStack, optStack); err != nil { |
| 994 | return newEmptyFormulaArg(), err |
| 995 | } |
| 996 | } |
| 997 | |
| 998 | // function start |
| 999 | if isFunctionStartToken(token) { |
| 1000 | if token.TValue == "ARRAY" { |
| 1001 | inArray, formulaArray = true, [][]formulaArg{} |
| 1002 | continue |
| 1003 | } |
| 1004 | if token.TValue == "ARRAYROW" { |
| 1005 | inArrayRow, formulaArrayRow = true, []formulaArg{} |
| 1006 | continue |
| 1007 | } |
| 1008 | opfStack.Push(token) |
| 1009 | argsStack.Push(list.New().Init()) |
| 1010 | opftStack.Push(token) // to know which operators belong to a function use the function as a separator |
| 1011 | continue |
| 1012 | } |
| 1013 | |
| 1014 | // in function stack, walk 2 token at once |
| 1015 | if opfStack.Len() > 0 { |
| 1016 | var nextToken efp.Token |
| 1017 | if i+1 < len(tokens) { |
| 1018 | nextToken = tokens[i+1] |
| 1019 | } |
| 1020 | |
| 1021 | // current token is args or range, skip next token, order required: parse reference first |
| 1022 | if token.TSubType == efp.TokenSubTypeRange { |
| 1023 | if opftStack.Peek().(efp.Token) != opfStack.Peek().(efp.Token) { |
| 1024 | refTo := f.getDefinedNameRefTo(token.TValue, sheet) |
| 1025 | if refTo != "" { |
| 1026 | token.TValue = refTo |
| 1027 | } |
| 1028 | // parse reference: must reference at here |
| 1029 | result, err := f.parseReference(ctx, sheet, token.TValue) |
| 1030 | if err != nil { |
| 1031 | return result, err |
| 1032 | } |
| 1033 | opfdStack.Push(result) |
| 1034 | continue |
| 1035 | } |
| 1036 | if nextToken.TType == efp.TokenTypeArgument || nextToken.TType == efp.TokenTypeFunction { |