@@ -63,8 +63,8 @@ type formulaArg struct {
63
63
type formulaFuncs struct {}
64
64
65
65
// 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.
68
68
func (f * File ) CalcCellValue (sheet , cell string ) (result string , err error ) {
69
69
var (
70
70
formula string
@@ -265,6 +265,89 @@ func (f *File) evalInfixExp(sheet string, tokens []efp.Token) (efp.Token, error)
265
265
return opdStack .Peek ().(efp.Token ), err
266
266
}
267
267
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
+
268
351
// calculate evaluate basic arithmetic operations.
269
352
func calculate (opdStack * Stack , opt efp.Token ) error {
270
353
if opt .TValue == "-" && opt .TType == efp .TokenTypeOperatorPrefix {
@@ -279,80 +362,69 @@ func calculate(opdStack *Stack, opt efp.Token) error {
279
362
result := 0 - opdVal
280
363
opdStack .Push (efp.Token {TValue : fmt .Sprintf ("%g" , result ), TType : efp .TokenTypeOperand , TSubType : efp .TokenSubTypeNumber })
281
364
}
365
+
282
366
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 {
290
368
return err
291
369
}
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 })
298
370
}
299
371
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 {
307
373
return err
308
374
}
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 })
315
375
}
316
376
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 {
324
378
return err
325
379
}
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 })
332
380
}
333
381
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 {
341
383
return err
342
384
}
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 })
352
385
}
353
386
return nil
354
387
}
355
388
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
+
356
428
// parseToken parse basic arithmetic operator priority and evaluate based on
357
429
// operators and operands.
358
430
func (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
369
441
token .TType = efp .TokenTypeOperand
370
442
token .TSubType = efp .TokenSubTypeNumber
371
443
}
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
396
447
}
397
448
}
398
449
if token .TType == efp .TokenTypeSubexpression && token .TSubType == efp .TokenSubTypeStart { // (
@@ -461,11 +512,44 @@ func (f *File) parseReference(sheet, reference string) (result []string, matrix
461
512
return
462
513
}
463
514
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
+
464
547
// 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.
467
550
func (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 }
469
553
var sheet string
470
554
filter := map [string ]string {}
471
555
// prepare value range
@@ -476,18 +560,7 @@ func (f *File) rangeResolver(cellRefs, cellRanges *list.List) (result []string,
476
560
}
477
561
rng := []int {cr .From .Col , cr .From .Row , cr .To .Col , cr .To .Row }
478
562
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 )
491
564
if cr .From .Sheet != "" {
492
565
sheet = cr .From .Sheet
493
566
}
@@ -497,24 +570,13 @@ func (f *File) rangeResolver(cellRefs, cellRanges *list.List) (result []string,
497
570
if cr .Sheet != "" {
498
571
sheet = cr .Sheet
499
572
}
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 )
512
574
}
513
575
// extract value from ranges
514
576
if cellRanges .Len () > 0 {
515
- for row := fromRow ; row <= toRow ; row ++ {
577
+ for row := valueRange [ 0 ] ; row <= valueRange [ 1 ] ; row ++ {
516
578
var matrixRow = []string {}
517
- for col := fromCol ; col <= toCol ; col ++ {
579
+ for col := valueRange [ 2 ] ; col <= valueRange [ 3 ] ; col ++ {
518
580
var cell , value string
519
581
if cell , err = CoordinatesToCellName (col , row ); err != nil {
520
582
return
@@ -672,28 +734,15 @@ func (fn *formulaFuncs) ARABIC(argsList *list.List) (result string, err error) {
672
734
err = errors .New ("ARABIC requires 1 numeric argument" )
673
735
return
674
736
}
737
+ charMap := map [rune ]float64 {'I' : 1 , 'V' : 5 , 'X' : 10 , 'L' : 50 , 'C' : 100 , 'D' : 500 , 'M' : 1000 }
675
738
val , last , prefix := 0.0 , 0.0 , 1.0
676
739
for _ , char := range argsList .Front ().Value .(formulaArg ).Value {
677
740
digit := 0.0
678
- switch char {
679
- case '-' :
741
+ if char == '-' {
680
742
prefix = - 1
681
743
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
696
744
}
745
+ digit , _ = charMap [char ]
697
746
val += digit
698
747
switch {
699
748
case last == digit && (last == 5 || last == 50 || last == 500 ):
@@ -850,7 +899,7 @@ func (fn *formulaFuncs) BASE(argsList *list.List) (result string, err error) {
850
899
return
851
900
}
852
901
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" )
854
903
return
855
904
}
856
905
if argsList .Len () > 2 {
0 commit comments