@@ -63,8 +63,8 @@ type formulaArg struct {
6363type formulaFuncs struct {}
6464
6565// CalcCellValue provides a function to get calculated cell value. This
66- // feature is currently in beta . Array formula, table formula and some other
67- // formulas are not supported currently.
66+ // feature is currently in working processing . Array formula, table formula
67+ // and some other formulas are not supported currently.
6868func (f * File ) CalcCellValue (sheet , cell string ) (result string , err error ) {
6969 var (
7070 formula string
@@ -265,6 +265,89 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
265265 return opdStack .Peek ().(efp.Token ), err
266266}
267267
268+ // calcAdd evaluate addition arithmetic operations.
269+ func calcAdd (opdStack * Stack ) error {
270+ if opdStack .Len () < 2 {
271+ return errors .New ("formula not valid" )
272+ }
273+ rOpd := opdStack .Pop ().(efp.Token )
274+ lOpd := opdStack .Pop ().(efp.Token )
275+ lOpdVal , err := strconv .ParseFloat (lOpd .TValue , 64 )
276+ if err != nil {
277+ return err
278+ }
279+ rOpdVal , err := strconv .ParseFloat (rOpd .TValue , 64 )
280+ if err != nil {
281+ return err
282+ }
283+ result := lOpdVal + rOpdVal
284+ opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
285+ return nil
286+ }
287+
288+ // calcAdd evaluate subtraction arithmetic operations.
289+ func calcSubtract (opdStack * Stack ) error {
290+ if opdStack .Len () < 2 {
291+ return errors .New ("formula not valid" )
292+ }
293+ rOpd := opdStack .Pop ().(efp.Token )
294+ lOpd := opdStack .Pop ().(efp.Token )
295+ lOpdVal , err := strconv .ParseFloat (lOpd .TValue , 64 )
296+ if err != nil {
297+ return err
298+ }
299+ rOpdVal , err := strconv .ParseFloat (rOpd .TValue , 64 )
300+ if err != nil {
301+ return err
302+ }
303+ result := lOpdVal - rOpdVal
304+ opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
305+ return nil
306+ }
307+
308+ // calcAdd evaluate multiplication arithmetic operations.
309+ func calcMultiply (opdStack * Stack ) error {
310+ if opdStack .Len () < 2 {
311+ return errors .New ("formula not valid" )
312+ }
313+ rOpd := opdStack .Pop ().(efp.Token )
314+ lOpd := opdStack .Pop ().(efp.Token )
315+ lOpdVal , err := strconv .ParseFloat (lOpd .TValue , 64 )
316+ if err != nil {
317+ return err
318+ }
319+ rOpdVal , err := strconv .ParseFloat (rOpd .TValue , 64 )
320+ if err != nil {
321+ return err
322+ }
323+ result := lOpdVal * rOpdVal
324+ opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
325+ return nil
326+ }
327+
328+ // calcAdd evaluate division arithmetic operations.
329+ func calcDivide (opdStack * Stack ) error {
330+ if opdStack .Len () < 2 {
331+ return errors .New ("formula not valid" )
332+ }
333+ rOpd := opdStack .Pop ().(efp.Token )
334+ lOpd := opdStack .Pop ().(efp.Token )
335+ lOpdVal , err := strconv .ParseFloat (lOpd .TValue , 64 )
336+ if err != nil {
337+ return err
338+ }
339+ rOpdVal , err := strconv .ParseFloat (rOpd .TValue , 64 )
340+ if err != nil {
341+ return err
342+ }
343+ result := lOpdVal / rOpdVal
344+ if rOpdVal == 0 {
345+ return errors .New (formulaErrorDIV )
346+ }
347+ opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
348+ return nil
349+ }
350+
268351// calculate evaluate basic arithmetic operations.
269352func calculate (opdStack * Stack , opt efp.Token ) error {
270353 if opt .TValue == "-" && opt .TType == efp .TokenTypeOperatorPrefix {
@@ -279,80 +362,69 @@ func calculate(opdStack *Stack, opt efp.Token) error {
279362 result := 0 - opdVal
280363 opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
281364 }
365+
282366 if opt .TValue == "+" {
283- if opdStack .Len () < 2 {
284- return errors .New ("formula not valid" )
285- }
286- rOpd := opdStack .Pop ().(efp.Token )
287- lOpd := opdStack .Pop ().(efp.Token )
288- lOpdVal , err := strconv .ParseFloat (lOpd .TValue , 64 )
289- if err != nil {
367+ if err := calcAdd (opdStack ); err != nil {
290368 return err
291369 }
292- rOpdVal , err := strconv .ParseFloat (rOpd .TValue , 64 )
293- if err != nil {
294- return err
295- }
296- result := lOpdVal + rOpdVal
297- opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
298370 }
299371 if opt .TValue == "-" && opt .TType == efp .TokenTypeOperatorInfix {
300- if opdStack .Len () < 2 {
301- return errors .New ("formula not valid" )
302- }
303- rOpd := opdStack .Pop ().(efp.Token )
304- lOpd := opdStack .Pop ().(efp.Token )
305- lOpdVal , err := strconv .ParseFloat (lOpd .TValue , 64 )
306- if err != nil {
372+ if err := calcSubtract (opdStack ); err != nil {
307373 return err
308374 }
309- rOpdVal , err := strconv .ParseFloat (rOpd .TValue , 64 )
310- if err != nil {
311- return err
312- }
313- result := lOpdVal - rOpdVal
314- opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
315375 }
316376 if opt .TValue == "*" {
317- if opdStack .Len () < 2 {
318- return errors .New ("formula not valid" )
319- }
320- rOpd := opdStack .Pop ().(efp.Token )
321- lOpd := opdStack .Pop ().(efp.Token )
322- lOpdVal , err := strconv .ParseFloat (lOpd .TValue , 64 )
323- if err != nil {
377+ if err := calcMultiply (opdStack ); err != nil {
324378 return err
325379 }
326- rOpdVal , err := strconv .ParseFloat (rOpd .TValue , 64 )
327- if err != nil {
328- return err
329- }
330- result := lOpdVal * rOpdVal
331- opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
332380 }
333381 if opt .TValue == "/" {
334- if opdStack .Len () < 2 {
335- return errors .New ("formula not valid" )
336- }
337- rOpd := opdStack .Pop ().(efp.Token )
338- lOpd := opdStack .Pop ().(efp.Token )
339- lOpdVal , err := strconv .ParseFloat (lOpd .TValue , 64 )
340- if err != nil {
382+ if err := calcDivide (opdStack ); err != nil {
341383 return err
342384 }
343- rOpdVal , err := strconv .ParseFloat (rOpd .TValue , 64 )
344- if err != nil {
345- return err
346- }
347- result := lOpdVal / rOpdVal
348- if rOpdVal == 0 {
349- return errors .New (formulaErrorDIV )
350- }
351- opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
352385 }
353386 return nil
354387}
355388
389+ // parseOperatorPrefixToken parse operator prefix token.
390+ func (f * File ) parseOperatorPrefixToken (optStack , opdStack * Stack , token efp.Token ) (err error ) {
391+ if optStack .Len () == 0 {
392+ optStack .Push (token )
393+ } else {
394+ tokenPriority := getPriority (token )
395+ topOpt := optStack .Peek ().(efp.Token )
396+ topOptPriority := getPriority (topOpt )
397+ if tokenPriority > topOptPriority {
398+ optStack .Push (token )
399+ } else {
400+ for tokenPriority <= topOptPriority {
401+ optStack .Pop ()
402+ if err = calculate (opdStack , topOpt ); err != nil {
403+ return
404+ }
405+ if optStack .Len () > 0 {
406+ topOpt = optStack .Peek ().(efp.Token )
407+ topOptPriority = getPriority (topOpt )
408+ continue
409+ }
410+ break
411+ }
412+ optStack .Push (token )
413+ }
414+ }
415+ return
416+ }
417+
418+ // isOperatorPrefixToken determine if the token is parse operator prefix
419+ // token.
420+ func isOperatorPrefixToken (token efp.Token ) bool {
421+ if (token .TValue == "-" && token .TType == efp .TokenTypeOperatorPrefix ) ||
422+ token .TValue == "+" || token .TValue == "-" || token .TValue == "*" || token .TValue == "/" {
423+ return true
424+ }
425+ return false
426+ }
427+
356428// parseToken parse basic arithmetic operator priority and evaluate based on
357429// operators and operands.
358430func (f * File ) parseToken (sheet string , token efp.Token , opdStack , optStack * Stack ) error {
@@ -369,30 +441,9 @@ func (f *File) parseToken(sheet string, token efp.Token, opdStack, optStack *Sta
369441 token .TType = efp .TokenTypeOperand
370442 token .TSubType = efp .TokenSubTypeNumber
371443 }
372- if (token .TValue == "-" && token .TType == efp .TokenTypeOperatorPrefix ) || token .TValue == "+" || token .TValue == "-" || token .TValue == "*" || token .TValue == "/" {
373- if optStack .Len () == 0 {
374- optStack .Push (token )
375- } else {
376- tokenPriority := getPriority (token )
377- topOpt := optStack .Peek ().(efp.Token )
378- topOptPriority := getPriority (topOpt )
379- if tokenPriority > topOptPriority {
380- optStack .Push (token )
381- } else {
382- for tokenPriority <= topOptPriority {
383- optStack .Pop ()
384- if err := calculate (opdStack , topOpt ); err != nil {
385- return err
386- }
387- if optStack .Len () > 0 {
388- topOpt = optStack .Peek ().(efp.Token )
389- topOptPriority = getPriority (topOpt )
390- continue
391- }
392- break
393- }
394- optStack .Push (token )
395- }
444+ if isOperatorPrefixToken (token ) {
445+ if err := f .parseOperatorPrefixToken (optStack , opdStack , token ); err != nil {
446+ return err
396447 }
397448 }
398449 if token .TType == efp .TokenTypeSubexpression && token .TSubType == efp .TokenSubTypeStart { // (
@@ -461,11 +512,44 @@ func (f *File) parseReference(sheet, reference string) (result []string, matrix
461512 return
462513}
463514
515+ // prepareValueRange prepare value range.
516+ func prepareValueRange (cr cellRange , valueRange []int ) {
517+ if cr .From .Row < valueRange [0 ] {
518+ valueRange [0 ] = cr .From .Row
519+ }
520+ if cr .From .Col < valueRange [2 ] {
521+ valueRange [2 ] = cr .From .Col
522+ }
523+ if cr .To .Row > valueRange [0 ] {
524+ valueRange [1 ] = cr .To .Row
525+ }
526+ if cr .To .Col > valueRange [3 ] {
527+ valueRange [3 ] = cr .To .Col
528+ }
529+ }
530+
531+ // prepareValueRef prepare value reference.
532+ func prepareValueRef (cr cellRef , valueRange []int ) {
533+ if cr .Row < valueRange [0 ] {
534+ valueRange [0 ] = cr .Row
535+ }
536+ if cr .Col < valueRange [2 ] {
537+ valueRange [2 ] = cr .Col
538+ }
539+ if cr .Row > valueRange [0 ] {
540+ valueRange [1 ] = cr .Row
541+ }
542+ if cr .Col > valueRange [3 ] {
543+ valueRange [3 ] = cr .Col
544+ }
545+ }
546+
464547// rangeResolver extract value as string from given reference and range list.
465- // This function will not ignore the empty cell. For example,
466- // A1:A2:A2:B3 will be reference A1:B3.
548+ // This function will not ignore the empty cell. For example, A1:A2:A2:B3 will
549+ // be reference A1:B3.
467550func (f * File ) rangeResolver (cellRefs , cellRanges * list.List ) (result []string , matrix [][]string , err error ) {
468- var fromRow , toRow , fromCol , toCol int = 1 , 1 , 1 , 1
551+ // value range order: from row, to row, from column, to column
552+ valueRange := []int {1 , 1 , 1 , 1 }
469553 var sheet string
470554 filter := map [string ]string {}
471555 // prepare value range
@@ -476,18 +560,7 @@ func (f *File) rangeResolver(cellRefs, cellRanges *list.List) (result []string,
476560 }
477561 rng := []int {cr .From .Col , cr .From .Row , cr .To .Col , cr .To .Row }
478562 sortCoordinates (rng )
479- if cr .From .Row < fromRow {
480- fromRow = cr .From .Row
481- }
482- if cr .From .Col < fromCol {
483- fromCol = cr .From .Col
484- }
485- if cr .To .Row > fromRow {
486- toRow = cr .To .Row
487- }
488- if cr .To .Col > toCol {
489- toCol = cr .To .Col
490- }
563+ prepareValueRange (cr , valueRange )
491564 if cr .From .Sheet != "" {
492565 sheet = cr .From .Sheet
493566 }
@@ -497,24 +570,13 @@ func (f *File) rangeResolver(cellRefs, cellRanges *list.List) (result []string,
497570 if cr .Sheet != "" {
498571 sheet = cr .Sheet
499572 }
500- if cr .Row < fromRow {
501- fromRow = cr .Row
502- }
503- if cr .Col < fromCol {
504- fromCol = cr .Col
505- }
506- if cr .Row > fromRow {
507- toRow = cr .Row
508- }
509- if cr .Col > toCol {
510- toCol = cr .Col
511- }
573+ prepareValueRef (cr , valueRange )
512574 }
513575 // extract value from ranges
514576 if cellRanges .Len () > 0 {
515- for row := fromRow ; row <= toRow ; row ++ {
577+ for row := valueRange [ 0 ] ; row <= valueRange [ 1 ] ; row ++ {
516578 var matrixRow = []string {}
517- for col := fromCol ; col <= toCol ; col ++ {
579+ for col := valueRange [ 2 ] ; col <= valueRange [ 3 ] ; col ++ {
518580 var cell , value string
519581 if cell , err = CoordinatesToCellName (col , row ); err != nil {
520582 return
@@ -672,28 +734,15 @@ func (fn *formulaFuncs) ARABIC(argsList *list.List) (result string, err error) {
672734 err = errors .New ("ARABIC requires 1 numeric argument" )
673735 return
674736 }
737+ charMap := map [rune ]float64 {'I' : 1 , 'V' : 5 , 'X' : 10 , 'L' : 50 , 'C' : 100 , 'D' : 500 , 'M' : 1000 }
675738 val , last , prefix := 0.0 , 0.0 , 1.0
676739 for _ , char := range argsList .Front ().Value .(formulaArg ).Value {
677740 digit := 0.0
678- switch char {
679- case '-' :
741+ if char == '-' {
680742 prefix = - 1
681743 continue
682- case 'I' :
683- digit = 1
684- case 'V' :
685- digit = 5
686- case 'X' :
687- digit = 10
688- case 'L' :
689- digit = 50
690- case 'C' :
691- digit = 100
692- case 'D' :
693- digit = 500
694- case 'M' :
695- digit = 1000
696744 }
745+ digit , _ = charMap [char ]
697746 val += digit
698747 switch {
699748 case last == digit && (last == 5 || last == 50 || last == 500 ):
@@ -850,7 +899,7 @@ func (fn *formulaFuncs) BASE(argsList *list.List) (result string, err error) {
850899 return
851900 }
852901 if radix < 2 || radix > 36 {
853- err = errors .New ("radix must be an integer ≥ 2 and ≤ 36" )
902+ err = errors .New ("radix must be an integer >= 2 and <= 36" )
854903 return
855904 }
856905 if argsList .Len () > 2 {
0 commit comments