excel_to_code 0.3.17 → 0.3.18.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +67 -34
  3. data/bin/excel_to_c +8 -78
  4. data/bin/excel_to_go +41 -0
  5. data/bin/excel_to_ruby +2 -69
  6. data/src/commands.rb +2 -0
  7. data/src/commands/common_command_line_options.rb +81 -0
  8. data/src/commands/excel_to_c.rb +3 -0
  9. data/src/commands/excel_to_go.rb +91 -0
  10. data/src/commands/excel_to_x.rb +77 -11
  11. data/src/compile.rb +1 -0
  12. data/src/compile/c/a.out +0 -0
  13. data/src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out +0 -0
  14. data/src/compile/c/compile_to_c.rb +2 -0
  15. data/src/compile/c/excel_to_c_runtime.c +691 -145
  16. data/src/compile/c/excel_to_c_runtime_test.c +226 -20
  17. data/src/compile/c/map_formulae_to_c.rb +62 -23
  18. data/src/compile/c/run_c_unit_tests +3 -0
  19. data/src/compile/cd.rb +6 -0
  20. data/src/compile/go.rb +3 -0
  21. data/src/compile/go/compile_to_go.rb +85 -0
  22. data/src/compile/go/compile_to_go_test.rb +73 -0
  23. data/src/compile/go/excel.go +171 -0
  24. data/src/compile/go/excel_test.go +54 -0
  25. data/src/compile/go/map_values_to_go.rb +67 -0
  26. data/src/compile/ruby/map_formulae_to_ruby.rb +30 -12
  27. data/src/excel/excel_functions.rb +26 -1
  28. data/src/excel/excel_functions/ceiling.rb +23 -0
  29. data/src/excel/excel_functions/countif.rb +15 -0
  30. data/src/excel/excel_functions/countifs.rb +10 -0
  31. data/src/excel/excel_functions/floor.rb +14 -0
  32. data/src/excel/excel_functions/hyperlink.rb +9 -0
  33. data/src/excel/excel_functions/na.rb +7 -0
  34. data/src/excel/excel_functions/not.rb +13 -0
  35. data/src/excel/excel_functions/or.rb +30 -0
  36. data/src/excel/excel_functions/product.rb +8 -0
  37. data/src/excel/excel_functions/rate.rb +16 -0
  38. data/src/excel/excel_functions/replace.rb +13 -0
  39. data/src/excel/excel_functions/scurve.rb +73 -0
  40. data/src/excel/excel_functions/sqrt.rb +11 -0
  41. data/src/excel/excel_functions/string_argument.rb +37 -0
  42. data/src/excel/excel_functions/sumifs.rb +19 -8
  43. data/src/excel/excel_functions/text.rb +3 -3
  44. data/src/excel/formula_peg.rb +1 -1
  45. data/src/excel/formula_peg.txt +2 -3
  46. data/src/excel/table.rb +15 -15
  47. data/src/excel_to_code.rb +1 -4
  48. data/src/extract/extract_data_from_worksheet.rb +8 -1
  49. data/src/rewrite/ast_expand_array_formulae.rb +4 -0
  50. data/src/rewrite/caching_formula_parser.rb +16 -11
  51. data/src/simplify.rb +1 -0
  52. data/src/simplify/inline_formulae.rb +16 -0
  53. data/src/simplify/replace_arithmetic_on_ranges.rb +14 -1
  54. data/src/simplify/replace_arrays_with_single_cells.rb +42 -15
  55. data/src/simplify/replace_cell_addresses_with_references.rb +70 -0
  56. data/src/simplify/replace_column_with_column_number.rb +8 -1
  57. data/src/simplify/replace_table_references.rb +40 -19
  58. data/src/simplify/simplify_arithmetic.rb +15 -10
  59. data/src/version.rb +4 -0
  60. metadata +115 -43
  61. data/TODO +0 -25
@@ -34,6 +34,23 @@ int test_functions() {
34
34
  // assert(excel_and(1,error_array1).type == ExcelError); // Not implemented
35
35
  assert(excel_and(2,error_array2).type == ExcelError);
36
36
 
37
+ // Test OR
38
+ assert(excel_or(2,true_array1).number == 1);
39
+ assert(excel_or(1,true_array2).number == 1);
40
+ assert(excel_or(2,false_array1).number == 0);
41
+ assert(excel_or(2,false_array2).number == 1);
42
+ //assert(excel_or(2,error_array2).type == ExcelError); // Not implemented
43
+
44
+ // Test NOT
45
+ assert(excel_not(TRUE).number == false);
46
+ assert(excel_not(FALSE).number == true);
47
+ assert(excel_not(ZERO).number == true);
48
+ assert(excel_not(ONE).number == false);
49
+ assert(excel_not(TWO).number == false);
50
+ assert(excel_not(BLANK).number == true);
51
+ assert(excel_not(NA).type == ExcelError);
52
+ assert(excel_not(EXCEL_STRING("hello world")).type == ExcelError);
53
+
37
54
  // Test AVERAGE
38
55
  ExcelValue array1[] = { EXCEL_NUMBER(10), EXCEL_NUMBER(5), TRUE, FALSE};
39
56
  ExcelValue array1_v = EXCEL_RANGE(array1,2,2);
@@ -48,7 +65,7 @@ int test_functions() {
48
65
  assert(choose(EXCEL_NUMBER(4),4,array1).type == ExcelBoolean);
49
66
  assert(choose(EXCEL_NUMBER(0),4,array1).type == ExcelError);
50
67
  assert(choose(EXCEL_NUMBER(5),4,array1).type == ExcelError);
51
- assert(choose(ONE,4,array3).type == ExcelError);
68
+ assert(choose(ONE,4,array3).type == ExcelError);
52
69
 
53
70
  // Test COUNT
54
71
  assert(count(4,array1).number == 2);
@@ -123,13 +140,15 @@ int test_functions() {
123
140
  ExcelValue excel_match_array_4_v = EXCEL_RANGE(excel_match_array_4,1,3);
124
141
  ExcelValue excel_match_array_5[] = { ONE, EXCEL_NUMBER(0), BLANK };
125
142
  ExcelValue excel_match_array_5_v = EXCEL_RANGE(excel_match_array_5,1,3);
143
+ ExcelValue excel_match_array_6[] = { EXCEL_STRING(""), ONE, TWO, THREE, FOUR };
144
+ ExcelValue excel_match_array_6_v = EXCEL_RANGE(excel_match_array_6,5,1);
126
145
 
127
146
  // Two argument version
128
147
  assert(excel_match_2(EXCEL_NUMBER(14),excel_match_array_1_v).number == 1);
129
148
  assert(excel_match_2(EXCEL_NUMBER(110),excel_match_array_1_v).number == 2);
130
149
  assert(excel_match_2(EXCEL_NUMBER(-10),excel_match_array_1_v).type == ExcelError);
131
150
 
132
- // Three argument version
151
+ // Three argument version
133
152
  assert(excel_match(EXCEL_NUMBER(10.0), excel_match_array_1_v, EXCEL_NUMBER(0) ).number == 1);
134
153
  assert(excel_match(EXCEL_NUMBER(100.0), excel_match_array_1_v, EXCEL_NUMBER(0) ).number == 2);
135
154
  assert(excel_match(EXCEL_NUMBER(1000.0), excel_match_array_1_v, EXCEL_NUMBER(0) ).type == ExcelError);
@@ -139,6 +158,8 @@ int test_functions() {
139
158
  assert(excel_match(EXCEL_STRING("Care"), excel_match_array_2_v, EXCEL_NUMBER(-1) ).number == 1 );
140
159
  assert(excel_match(EXCEL_STRING("Zebra"), excel_match_array_2_v, EXCEL_NUMBER(-1) ).type == ExcelError);
141
160
  assert(excel_match(EXCEL_STRING("a"), excel_match_array_2_v, EXCEL_NUMBER(-1) ).number == 2);
161
+ // EMPTY STRINGS
162
+ assert(excel_match(EXCEL_NUMBER(1), excel_match_array_6_v, ONE).number == 2);
142
163
 
143
164
  // When not given a range
144
165
  assert(excel_match(EXCEL_NUMBER(10.0), EXCEL_NUMBER(10), EXCEL_NUMBER(0.0)).number == 1);
@@ -156,7 +177,7 @@ int test_functions() {
156
177
  assert(more_than(TRUE,FALSE).number == true);
157
178
  assert(more_than(TRUE,TRUE).number == false);
158
179
  // ..strings
159
- assert(more_than(EXCEL_STRING("HELLO"),EXCEL_STRING("Ardvark")).number == true);
180
+ assert(more_than(EXCEL_STRING("HELLO"),EXCEL_STRING("Ardvark")).number == true);
160
181
  assert(more_than(EXCEL_STRING("HELLO"),EXCEL_STRING("world")).number == false);
161
182
  assert(more_than(EXCEL_STRING("HELLO"),EXCEL_STRING("hello")).number == false);
162
183
  // ..blanks
@@ -183,7 +204,7 @@ int test_functions() {
183
204
  assert(less_than(TRUE,FALSE).number == false);
184
205
  assert(less_than(TRUE,TRUE).number == false);
185
206
  // ..strings
186
- assert(less_than(EXCEL_STRING("HELLO"),EXCEL_STRING("Ardvark")).number == false);
207
+ assert(less_than(EXCEL_STRING("HELLO"),EXCEL_STRING("Ardvark")).number == false);
187
208
  assert(less_than(EXCEL_STRING("HELLO"),EXCEL_STRING("world")).number == true);
188
209
  assert(less_than(EXCEL_STRING("HELLO"),EXCEL_STRING("hello")).number == false);
189
210
  // ..blanks
@@ -229,7 +250,7 @@ int test_functions() {
229
250
 
230
251
  // Test the IFERROR function
231
252
  assert(iferror(EXCEL_STRING("ok"),ONE).type == ExcelString);
232
- assert(iferror(VALUE,ONE).type == ExcelNumber);
253
+ assert(iferror(VALUE,ONE).type == ExcelNumber);
233
254
 
234
255
  // Test the ISERR function
235
256
  assert(iserr(NA).type == ExcelBoolean);
@@ -252,7 +273,7 @@ int test_functions() {
252
273
  assert(iserr(ONE).number == 0);
253
274
  assert(iserr(EXCEL_STRING("Hello")).number == 0);
254
275
  assert(iserr(EXCEL_STRING("Hello")).number == 0);
255
-
276
+
256
277
  // Test the ISERROR function
257
278
  assert_equal(iserror(NA), TRUE, "ISERROR(NA)");
258
279
  assert_equal(iserror(DIV0), TRUE, "ISERROR(DIV0)");
@@ -347,7 +368,7 @@ int test_functions() {
347
368
  assert(less_than_or_equal(TRUE,FALSE).number == false);
348
369
  assert(less_than_or_equal(TRUE,TRUE).number == true);
349
370
  // ..strings
350
- assert(less_than_or_equal(EXCEL_STRING("HELLO"),EXCEL_STRING("Ardvark")).number == false);
371
+ assert(less_than_or_equal(EXCEL_STRING("HELLO"),EXCEL_STRING("Ardvark")).number == false);
351
372
  assert(less_than_or_equal(EXCEL_STRING("HELLO"),EXCEL_STRING("world")).number == true);
352
373
  assert(less_than_or_equal(EXCEL_STRING("HELLO"),EXCEL_STRING("hello")).number == true);
353
374
  // ..blanks
@@ -377,7 +398,7 @@ int test_functions() {
377
398
  assert(mod(EXCEL_NUMBER(10),BLANK).type == ExcelError);
378
399
  assert(mod(BLANK,BLANK).type == ExcelError);
379
400
  // ... should treat true as 1 and FALSE as 0
380
- assert((mod(EXCEL_NUMBER(1.1),TRUE).number - 0.1) < 0.001);
401
+ assert((mod(EXCEL_NUMBER(1.1),TRUE).number - 0.1) < 0.001);
381
402
  assert(mod(EXCEL_NUMBER(1.1),FALSE).type == ExcelError);
382
403
  assert(mod(FALSE,EXCEL_NUMBER(10)).number == 0);
383
404
  // ... should return an error when given inappropriate arguments
@@ -398,7 +419,7 @@ int test_functions() {
398
419
  assert(more_than_or_equal(TRUE,FALSE).number == true);
399
420
  assert(more_than_or_equal(TRUE,TRUE).number == true);
400
421
  // ..strings
401
- assert(more_than_or_equal(EXCEL_STRING("HELLO"),EXCEL_STRING("Ardvark")).number == true);
422
+ assert(more_than_or_equal(EXCEL_STRING("HELLO"),EXCEL_STRING("Ardvark")).number == true);
402
423
  assert(more_than_or_equal(EXCEL_STRING("HELLO"),EXCEL_STRING("world")).number == false);
403
424
  assert(more_than_or_equal(EXCEL_STRING("HELLO"),EXCEL_STRING("hello")).number == true);
404
425
  // ..blanks
@@ -406,7 +427,7 @@ int test_functions() {
406
427
  assert(more_than_or_equal(BLANK,ONE).number == false);
407
428
  assert(more_than_or_equal(BLANK,EXCEL_NUMBER(-1)).number == true);
408
429
  assert(more_than_or_equal(ONE,BLANK).number == true);
409
- assert(more_than_or_equal(EXCEL_NUMBER(-1),BLANK).number == false);
430
+ assert(more_than_or_equal(EXCEL_NUMBER(-1),BLANK).number == false);
410
431
 
411
432
  // Test negative
412
433
  // ... should return the negative of its arguments
@@ -444,7 +465,7 @@ int test_functions() {
444
465
  assert(rounddown(EXCEL_NUMBER(1.1), EXCEL_NUMBER(0)).number == 1.0);
445
466
  assert(rounddown(EXCEL_NUMBER(1.5), EXCEL_NUMBER(0)).number == 1.0);
446
467
  assert(rounddown(EXCEL_NUMBER(1.56),EXCEL_NUMBER(1)).number == 1.5);
447
- assert(rounddown(EXCEL_NUMBER(-1.56),EXCEL_NUMBER(1)).number == -1.5);
468
+ assert(rounddown(EXCEL_NUMBER(-1.56),EXCEL_NUMBER(1)).number == -1.5);
448
469
 
449
470
  // Test int
450
471
  assert(excel_int(EXCEL_NUMBER(8.9)).number == 8.0);
@@ -454,14 +475,14 @@ int test_functions() {
454
475
  assert(roundup(EXCEL_NUMBER(1.1), EXCEL_NUMBER(0)).number == 2.0);
455
476
  assert(roundup(EXCEL_NUMBER(1.5), EXCEL_NUMBER(0)).number == 2.0);
456
477
  assert(roundup(EXCEL_NUMBER(1.56),EXCEL_NUMBER(1)).number == 1.6);
457
- assert(roundup(EXCEL_NUMBER(-1.56),EXCEL_NUMBER(1)).number == -1.6);
478
+ assert(roundup(EXCEL_NUMBER(-1.56),EXCEL_NUMBER(1)).number == -1.6);
458
479
 
459
480
  // Test string joining
460
481
  ExcelValue string_join_array_1[] = {EXCEL_STRING("Hello "), EXCEL_STRING("world")};
461
482
  ExcelValue string_join_array_2[] = {EXCEL_STRING("Hello "), EXCEL_STRING("world"), EXCEL_STRING("!")};
462
483
  ExcelValue string_join_array_3[] = {EXCEL_STRING("Top "), EXCEL_NUMBER(10.0)};
463
- ExcelValue string_join_array_4[] = {EXCEL_STRING("Top "), EXCEL_NUMBER(10.5)};
464
- ExcelValue string_join_array_5[] = {EXCEL_STRING("Top "), TRUE, FALSE};
484
+ ExcelValue string_join_array_4[] = {EXCEL_STRING("Top "), EXCEL_NUMBER(10.5)};
485
+ ExcelValue string_join_array_5[] = {EXCEL_STRING("Top "), TRUE, FALSE};
465
486
  // ... should return a string by combining its arguments
466
487
  // inspect_excel_value(string_join(2, string_join_array_1));
467
488
  assert(string_join(2, string_join_array_1).string[6] == 'w');
@@ -498,10 +519,10 @@ int test_functions() {
498
519
  ExcelValue subtotal_array_1_v = EXCEL_RANGE(subtotal_array_1,3,1);
499
520
  ExcelValue subtotal_array_2[] = {EXCEL_NUMBER(1),EXCEL_STRING("two"),subtotal_array_1_v};
500
521
 
501
- // EXCEL_NUMBER(1.0);
502
- // inspect_excel_value(EXCEL_NUMBER(1.0));
503
- // inspect_excel_value(EXCEL_RANGE(subtotal_array_2,3,1));
504
- // inspect_excel_value(subtotal(EXCEL_NUMBER(1.0),3,subtotal_array_2));
522
+ // EXCEL_NUMBER(1.0);
523
+ // inspect_excel_value(EXCEL_NUMBER(1.0));
524
+ // inspect_excel_value(EXCEL_RANGE(subtotal_array_2,3,1));
525
+ // inspect_excel_value(subtotal(EXCEL_NUMBER(1.0),3,subtotal_array_2));
505
526
 
506
527
  assert(subtotal(EXCEL_NUMBER(1.0),3,subtotal_array_2).number == 111.0/3.0);
507
528
  assert(subtotal(EXCEL_NUMBER(2.0),3,subtotal_array_2).number == 3);
@@ -588,6 +609,76 @@ int test_functions() {
588
609
  ExcelValue sumifs_array_15[] = {ONE, ONE};
589
610
  assert(sumifs(REF,2,sumifs_array_15).type == ExcelError);
590
611
 
612
+ // Test COUNTIFS function
613
+ ExcelValue countifs_array_1[] = {EXCEL_NUMBER(10),EXCEL_NUMBER(100),BLANK};
614
+ ExcelValue countifs_array_1_v = EXCEL_RANGE(countifs_array_1,3,1);
615
+ ExcelValue countifs_array_2[] = {EXCEL_STRING("pear"),EXCEL_STRING("bear"),EXCEL_STRING("apple")};
616
+ ExcelValue countifs_array_2_v = EXCEL_RANGE(countifs_array_2,3,1);
617
+ ExcelValue countifs_array_3[] = {EXCEL_NUMBER(1),EXCEL_NUMBER(2),EXCEL_NUMBER(3),EXCEL_NUMBER(4),EXCEL_NUMBER(5),EXCEL_NUMBER(5)};
618
+ ExcelValue countifs_array_3_v = EXCEL_RANGE(countifs_array_3,6,1);
619
+ ExcelValue countifs_array_4[] = {EXCEL_STRING("CO2"),EXCEL_STRING("CH4"),EXCEL_STRING("N2O"),EXCEL_STRING("CH4"),EXCEL_STRING("N2O"),EXCEL_STRING("CO2")};
620
+ ExcelValue countifs_array_4_v = EXCEL_RANGE(countifs_array_4,6,1);
621
+ ExcelValue countifs_array_5[] = {EXCEL_STRING("1A"),EXCEL_STRING("1A"),EXCEL_STRING("1A"),EXCEL_NUMBER(4),EXCEL_NUMBER(4),EXCEL_NUMBER(5)};
622
+ ExcelValue countifs_array_5_v = EXCEL_RANGE(countifs_array_5,6,1);
623
+
624
+ // ... should only sum values that meet all of the criteria
625
+ ExcelValue countifs_array_6[] = { countifs_array_1_v, EXCEL_NUMBER(10), countifs_array_2_v, EXCEL_STRING("Bear") };
626
+ assert(countifs(4,countifs_array_6).number == 0.0);
627
+
628
+ ExcelValue countifs_array_7[] = { countifs_array_1_v, EXCEL_NUMBER(10), countifs_array_2_v, EXCEL_STRING("Pear") };
629
+ assert(countifs(4,countifs_array_7).number == 1.0);
630
+
631
+ // ... should work when single cells are given where ranges expected
632
+ ExcelValue countifs_array_8[] = { EXCEL_STRING("CAR"), EXCEL_STRING("CAR"), EXCEL_STRING("FCV"), EXCEL_STRING("FCV")};
633
+ assert(countifs(4, countifs_array_8).number == 1.0);
634
+
635
+ // ... should match numbers with strings that contain numbers
636
+ ExcelValue countifs_array_9[] = { EXCEL_NUMBER(10), EXCEL_STRING("10.0")};
637
+ assert(countifs(2,countifs_array_9).number == 1.0);
638
+
639
+ ExcelValue countifs_array_9b[] = { EXCEL_STRING("10"), EXCEL_NUMBER(10.0)};
640
+ assert(countifs(2,countifs_array_9b).number == 1.0);
641
+
642
+ ExcelValue countifs_array_10[] = { countifs_array_4_v, EXCEL_STRING("CO2"), countifs_array_5_v, EXCEL_NUMBER(2)};
643
+ assert(countifs(4, countifs_array_10).number == 0.0);
644
+
645
+ // ... should match with strings that contain criteria
646
+ ExcelValue countifs_array_10a[] = { countifs_array_3_v, EXCEL_STRING("=5")};
647
+ assert(countifs(2, countifs_array_10a).number == 2.0);
648
+
649
+ ExcelValue countifs_array_10b[] = { countifs_array_3_v, EXCEL_STRING("<>3")};
650
+ assert(countifs(2, countifs_array_10b).number == 5.0);
651
+
652
+ ExcelValue countifs_array_10c[] = { countifs_array_3_v, EXCEL_STRING("<3")};
653
+ assert(countifs(2, countifs_array_10c).number == 2.0);
654
+
655
+ ExcelValue countifs_array_10d[] = { countifs_array_3_v, EXCEL_STRING("<=3")};
656
+ assert(countifs(2, countifs_array_10d).number == 3.0);
657
+
658
+ ExcelValue countifs_array_10e[] = { countifs_array_3_v, EXCEL_STRING(">3")};
659
+ assert(countifs(2, countifs_array_10e).number == 3.0);
660
+
661
+ ExcelValue countifs_array_10f[] = { countifs_array_3_v, EXCEL_STRING(">=3")};
662
+ assert(countifs(2, countifs_array_10f).number == 4.0);
663
+
664
+ // ... BLANK in check range should match empty strings, BLANK in criteria should match zero
665
+ ExcelValue countifs_array_11[] = { BLANK, EXCEL_NUMBER(0)};
666
+ assert(countifs(2,countifs_array_11).number == 0);
667
+
668
+ ExcelValue countifs_array_11b[] = { BLANK, EXCEL_STRING("")};
669
+ assert(countifs(2,countifs_array_11b).number == 1);
670
+
671
+ ExcelValue countifs_array_11c[] = { EXCEL_STRING(""), BLANK};
672
+ assert(countifs(2,countifs_array_11c).number == 0);
673
+
674
+ ExcelValue countifs_array_12[] = {EXCEL_NUMBER(0), BLANK};
675
+ assert(countifs(2,countifs_array_12).number == 1);
676
+
677
+ ExcelValue countifs_array_13[] = {BLANK, BLANK};
678
+ assert(countifs(2,countifs_array_13).number == 0);
679
+
680
+ ExcelValue countifs_array_14[] = {EXCEL_NUMBER(10), BLANK};
681
+ assert(countifs(2,countifs_array_14).number == 0);
591
682
 
592
683
  // Test SUMIF
593
684
  // ... where there is only a check range
@@ -654,6 +745,61 @@ int test_functions() {
654
745
  ExcelValue sumproducta_8[] = {VALUE};
655
746
  assert(sumproduct(1,sumproducta_8).type == ExcelError);
656
747
 
748
+ // Test PRODUCT
749
+ ExcelValue product_1[] = { EXCEL_NUMBER(10), EXCEL_NUMBER(100), BLANK};
750
+ ExcelValue product_2[] = { BLANK, EXCEL_NUMBER(100), EXCEL_NUMBER(10), BLANK};
751
+ ExcelValue product_3[] = { BLANK };
752
+ ExcelValue product_4[] = { EXCEL_NUMBER(10), EXCEL_NUMBER(100), EXCEL_NUMBER(1000)};
753
+ ExcelValue product_5[] = { EXCEL_NUMBER(1), EXCEL_NUMBER(2), EXCEL_NUMBER(3)};
754
+ ExcelValue product_6[] = { EXCEL_NUMBER(1), EXCEL_NUMBER(2), EXCEL_NUMBER(4), EXCEL_NUMBER(5)};
755
+ ExcelValue product_7[] = { EXCEL_NUMBER(10), EXCEL_NUMBER(20), EXCEL_NUMBER(40), EXCEL_NUMBER(50)};
756
+ ExcelValue product_8[] = { EXCEL_NUMBER(11), EXCEL_NUMBER(21), EXCEL_NUMBER(41), EXCEL_NUMBER(51)};
757
+ ExcelValue product_9[] = { BLANK, BLANK };
758
+
759
+ ExcelValue product_1_v = EXCEL_RANGE( product_1, 3, 1);
760
+ ExcelValue product_2_v = EXCEL_RANGE( product_2, 3, 1);
761
+ ExcelValue product_3_v = EXCEL_RANGE( product_3, 1, 1);
762
+ // ExcelValue product_4_v = EXCEL_RANGE( product_4, 1, 3); // Unused
763
+ ExcelValue product_5_v = EXCEL_RANGE( product_5, 3, 1);
764
+ ExcelValue product_6_v = EXCEL_RANGE( product_6, 2, 2);
765
+ ExcelValue product_7_v = EXCEL_RANGE( product_7, 2, 2);
766
+ ExcelValue product_8_v = EXCEL_RANGE( product_8, 2, 2);
767
+ ExcelValue product_9_v = EXCEL_RANGE( product_9, 2, 1);
768
+
769
+ // ... should multiply together the elements in row or column areas given as arguments
770
+ ExcelValue producta_1[] = {product_1_v, product_2_v};
771
+ assert(product(2,producta_1).number == 10*100*100*10);
772
+
773
+ // ... should work when miss-matched array sizes
774
+ ExcelValue producta_2[] = {product_1_v, product_3_v};
775
+ assert(product(2,producta_2).number == 10 * 100);
776
+
777
+ // ... if all its arguments are single values, should multiply them together
778
+ // ExcelValue *producta_3 = product_4;
779
+ assert(product(3,product_4).number == 10*100*1000);
780
+
781
+ // ... if it only has one range as an argument, should multiply its elements together
782
+ ExcelValue producta_4[] = {product_5_v};
783
+ assert(product(1,producta_4).number == 1 * 2 * 3);
784
+
785
+ // ... if given multi row and column areas as arguments, should multipy the corresponding cell in each area
786
+ // NB: Repeating this test from SUMPRODUCT, doesn't matter really with multiplication
787
+ ExcelValue producta_5[] = {product_6_v, product_7_v, product_8_v};
788
+ // NB: The 1.0 at the start is important, otherwise RHS will be an int with does not equal the double
789
+ assert(product(3,producta_5).number == (1.0*2*4*5)*(10*20*40*50)*(11*21*41*51));
790
+
791
+ // ... should ignore BLANK values outside of an array
792
+ ExcelValue producta_6[] = {BLANK,EXCEL_NUMBER(1)};
793
+ assert(product(2,producta_6).type == 1);
794
+
795
+ // ... should ignore non-numeric values within an array
796
+ ExcelValue producta_7[] = {product_9_v, product_9_v};
797
+ assert(product(2,producta_7).number == 0);
798
+
799
+ // ... should return an error if an argument is an error
800
+ ExcelValue producta_8[] = {VALUE};
801
+ assert(product(1,producta_8).type == ExcelError);
802
+
657
803
  // Test VLOOKUP
658
804
  ExcelValue vlookup_a1[] = {EXCEL_NUMBER(1),EXCEL_NUMBER(10),EXCEL_NUMBER(2),EXCEL_NUMBER(20),EXCEL_NUMBER(3),EXCEL_NUMBER(30)};
659
805
  ExcelValue vlookup_a2[] = {EXCEL_STRING("hello"),EXCEL_NUMBER(10),EXCEL_NUMBER(2),EXCEL_NUMBER(20),EXCEL_NUMBER(3),EXCEL_NUMBER(30)};
@@ -761,6 +907,28 @@ int test_functions() {
761
907
  assert(ln(EXCEL_NUMBER(0)).type == ExcelError);
762
908
  assert(ln(EXCEL_NUMBER(-1)).type == ExcelError);
763
909
 
910
+ // Test excel_sqrt
911
+ assert(excel_sqrt(EXCEL_NUMBER(1)).number == 1.0);
912
+ assert(excel_sqrt(EXCEL_NUMBER(4)).number == 2.0);
913
+ assert(excel_sqrt(EXCEL_NUMBER(1.6)).number == 1.2649110640673518);
914
+ assert(excel_sqrt(BLANK).number == 0);
915
+ assert(excel_sqrt(EXCEL_STRING("Hello world")).type == ExcelError);
916
+ assert(excel_sqrt(EXCEL_NUMBER(-1)).type == ExcelError);
917
+
918
+ // Test excel_floor
919
+ assert(excel_floor(EXCEL_NUMBER(1990), EXCEL_NUMBER(100)).number == 1900.0);
920
+ assert(excel_floor(EXCEL_NUMBER(10.99), EXCEL_NUMBER(0.1)).number == 10.9);
921
+ assert(excel_floor(BLANK, ONE).number == 0);
922
+ assert(excel_floor(EXCEL_NUMBER(10.99), ZERO).type == ExcelError);
923
+ assert(excel_floor(EXCEL_NUMBER(10.99), EXCEL_NUMBER(-1.0)).type == ExcelError);
924
+ assert(excel_floor(EXCEL_STRING("Hello world"), ONE).type == ExcelError);
925
+ assert(excel_floor(ONE, EXCEL_STRING("Hello world")).type == ExcelError);
926
+ assert(excel_floor(NA, ONE).type == ExcelError);
927
+ assert(excel_floor(ONE, NA).type == ExcelError);
928
+
929
+ // Test partial implementation of rate
930
+ assert(excel_round(multiply(rate(EXCEL_NUMBER(12), ZERO, EXCEL_NUMBER(-69999), EXCEL_NUMBER(64786)), EXCEL_NUMBER(1000)),ONE).number == -6.4);
931
+
764
932
  // Test MMULT (Matrix multiplication)
765
933
  ExcelValue mmult_1[] = { ONE, TWO, THREE, FOUR};
766
934
  ExcelValue mmult_2[] = { FOUR, THREE, TWO, ONE};
@@ -955,7 +1123,7 @@ int test_functions() {
955
1123
  assert(ensure_is_number(EXCEL_STRING("1.3")).number == 1.3);
956
1124
  assert(ensure_is_number(EXCEL_STRING("BASDASD")).type == ExcelError);
957
1125
  assert(ensure_is_number(DIV0).type == ExcelError);
958
-
1126
+
959
1127
  // Tests ther NUMBER_OR_ZERO function
960
1128
  assert_equal(ZERO, number_or_zero(ZERO), "number_or_zero 0");
961
1129
  assert_equal(ONE, number_or_zero(ONE), "number_or_zero 1");
@@ -965,7 +1133,7 @@ int test_functions() {
965
1133
  assert_equal(ZERO, number_or_zero(BLANK), "number_or_zero blank");
966
1134
  assert_equal(ZERO, number_or_zero(EXCEL_STRING("1.3")), "number_or_zero '1.3'");
967
1135
  assert_equal(ZERO, number_or_zero(EXCEL_STRING("Aasdfadsf")), "number_or_zero 'Asdfad'");
968
-
1136
+
969
1137
  // RIGHT(string,[characters])
970
1138
  // ... should return the right n characters from a string
971
1139
  assert(strcmp(right_1(EXCEL_STRING("ONE")).string,"E") == 0);
@@ -1034,6 +1202,44 @@ int test_functions() {
1034
1202
  assert_equal(EXCEL_STRING("a"), excel_char(EXCEL_NUMBER(97)), "excel_char(97) == 'a'");
1035
1203
  assert_equal(EXCEL_STRING("a"), excel_char(EXCEL_NUMBER(97.5)), "excel_char(97.5) == 'a'");
1036
1204
 
1205
+ // NA()
1206
+ assert_equal(NA, na(), "na() == NA");
1207
+
1208
+ // CEILING.MATH
1209
+ assert(excel_ceiling_math(EXCEL_NUMBER(0.1),EXCEL_NUMBER(0.1), ZERO).number == 0.1);
1210
+ assert(excel_ceiling_math(EXCEL_NUMBER(-0.1), EXCEL_NUMBER(0.1), ZERO).number == -0.1);
1211
+ assert(excel_ceiling_math(EXCEL_NUMBER(-0.1), EXCEL_NUMBER(0.1), ONE).number == -0.1);
1212
+ assert(excel_ceiling_math(EXCEL_NUMBER(136), EXCEL_NUMBER(10), ZERO).number == 140);
1213
+ assert(excel_ceiling_math(EXCEL_NUMBER(-136), EXCEL_NUMBER(10), ZERO).number == -130);
1214
+ assert(excel_ceiling_math(EXCEL_NUMBER(-136), EXCEL_NUMBER(10), ONE).number == -140);
1215
+
1216
+ // curve (a custom climact function)
1217
+ assert_equal(
1218
+ EXCEL_NUMBER(4.99),
1219
+ curve_5(
1220
+ EXCEL_STRING("s"),
1221
+ EXCEL_NUMBER(2023),
1222
+ EXCEL_NUMBER(0),
1223
+ EXCEL_NUMBER(10),
1224
+ EXCEL_NUMBER(10)
1225
+ ),
1226
+ "curve_5('s', 2023, 0, 10, 10) == 4.99"
1227
+ );
1228
+
1229
+ // If blank, defaults to lcurve
1230
+ assert_equal(
1231
+ EXCEL_NUMBER(5.0),
1232
+ curve_5(
1233
+ BLANK,
1234
+ EXCEL_NUMBER(2023),
1235
+ EXCEL_NUMBER(0),
1236
+ EXCEL_NUMBER(10),
1237
+ EXCEL_NUMBER(10)
1238
+ ),
1239
+ "curve_5(blank, 2023, 0, 10, 10) == 5"
1240
+ );
1241
+
1242
+
1037
1243
  // Release memory
1038
1244
  free_all_allocated_memory();
1039
1245
 
@@ -1,21 +1,22 @@
1
1
  require_relative 'map_values_to_c'
2
2
 
3
3
  class MapFormulaeToC < MapValuesToC
4
-
4
+
5
5
  attr_accessor :sheet_names
6
6
  attr_accessor :worksheet
7
7
  attr_reader :initializers
8
8
  attr_reader :counter
9
-
9
+ attr_accessor :allow_unknown_functions
10
+
10
11
  def initialize
11
12
  reset
12
13
  end
13
-
14
+
14
15
  def reset
15
16
  @initializers = []
16
17
  @counter = 0
17
18
  end
18
-
19
+
19
20
  FUNCTIONS = {
20
21
  :'*' => 'multiply',
21
22
  :'+' => 'add',
@@ -31,17 +32,23 @@ class MapFormulaeToC < MapValuesToC
31
32
  :'AND' => 'excel_and',
32
33
  :'AVERAGE' => 'average',
33
34
  :'AVERAGEIFS' => 'averageifs',
35
+ :'CEILING' => 'ceiling_2',
36
+ :'_xlfn.CEILING.MATH2' => 'excel_ceiling_math_2',
37
+ :'_xlfn.CEILING.MATH3' => 'excel_ceiling_math',
34
38
  :'CHAR' => 'excel_char',
35
39
  :'CHOOSE' => 'choose',
36
40
  :'CONCATENATE' => 'string_join',
37
41
  :'COSH' => 'cosh',
38
42
  :'COUNT' => 'count',
39
43
  :'COUNTA' => 'counta',
44
+ :'COUNTIFS' => 'countifs',
40
45
  :'ENSURE_IS_NUMBER' => 'ensure_is_number',
41
46
  :'EXP' => 'excel_exp',
42
47
  :'FIND2' => 'find_2',
43
48
  :'FIND3' => 'find',
49
+ :'FLOOR' => 'excel_floor',
44
50
  :'FORECAST' => 'forecast',
51
+ :'_xlfn.FORECAST.LINEAR' => 'forecast',
45
52
  :'HLOOKUP3' => 'hlookup_3',
46
53
  :'HLOOKUP4' => 'hlookup',
47
54
  :'IF2' => 'excel_if_2',
@@ -68,14 +75,19 @@ class MapFormulaeToC < MapValuesToC
68
75
  :'MIN' => 'min',
69
76
  :'MMULT' => 'mmult',
70
77
  :'MOD' => 'mod',
78
+ :'NA' => 'na',
79
+ :'NOT' => 'excel_not',
80
+ :'OR' => 'excel_or',
71
81
  :'NPV' => 'npv',
72
82
  :'NUMBER_OR_ZERO' => 'number_or_zero',
73
83
  :'PMT3' => 'pmt',
74
84
  :'PMT4' => 'pmt_4',
75
85
  :'PMT5' => 'pmt_5',
86
+ :'PRODUCT' => 'product',
76
87
  :'PV3' => 'pv_3',
77
88
  :'PV4' => 'pv_4',
78
89
  :'PV5' => 'pv_5',
90
+ :'RATE' => 'rate',
79
91
  :'RANK2' => 'rank_2',
80
92
  :'RANK3' => 'rank',
81
93
  :'RIGHT1' => 'right_1',
@@ -95,30 +107,39 @@ class MapFormulaeToC < MapValuesToC
95
107
  :'VLOOKUP3' => 'vlookup_3',
96
108
  :'VLOOKUP4' => 'vlookup',
97
109
  :'^' => 'power',
98
- :'POWER' => 'power'
110
+ :'POWER' => 'power',
111
+ :'SQRT' => 'excel_sqrt',
112
+ :'curve5' => 'curve_5',
113
+ :'curve' => 'curve',
114
+ :'scurve4' => 'scurve_4',
115
+ :'scurve' => 'scurve',
116
+ :'halfscurve4' => 'halfscurve_4',
117
+ :'halfscurve' => 'halfscurve',
118
+ :'lcurve4' => 'lcurve_4',
119
+ :'lcurve' => 'lcurve',
99
120
  }
100
-
121
+
101
122
  def prefix(symbol,ast)
102
123
  return map(ast) if symbol == "+"
103
124
  return "negative(#{map(ast)})"
104
125
  end
105
-
126
+
106
127
  def brackets(*contents)
107
128
  "(#{contents.map { |a| map(a) }.join(',')})"
108
129
  end
109
-
130
+
110
131
  def arithmetic(left,operator,right)
111
132
  "#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
112
133
  end
113
-
134
+
114
135
  def string_join(*strings)
115
136
  any_number_of_argument_function('string_join',strings)
116
137
  end
117
-
138
+
118
139
  def comparison(left,operator,right)
119
140
  "#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
120
141
  end
121
-
142
+
122
143
  def function(function_name,*arguments)
123
144
  # Some functions are special cases
124
145
  if self.respond_to?("function_#{function_name.to_s.downcase}")
@@ -135,21 +156,39 @@ class MapFormulaeToC < MapValuesToC
135
156
  elsif FUNCTIONS.has_key?(function_name.to_sym)
136
157
  "#{FUNCTIONS[function_name.to_sym]}(#{arguments.map { |a| map(a) }.join(",")})"
137
158
 
159
+ # Optionally, can dump unknown functions
160
+ elsif self.allow_unknown_functions
161
+ "#{function_name.to_s.downcase}(#{arguments.map { |a| map(a) }.join(",")})"
162
+
163
+ # But default is to raise an error
138
164
  else
139
165
  raise NotSupportedException.new("Function #{function_name} with #{arguments.size} arguments not supported")
140
166
  end
141
167
  end
142
-
143
- FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS = %w{SUM AND AVERAGE COUNT COUNTA MAX MIN SUMPRODUCT CONCATENATE}
144
-
145
- def function_pi()
168
+
169
+ FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS = %w{
170
+ SUM
171
+ PRODUCT
172
+ AND
173
+ OR
174
+ AVERAGE
175
+ COUNT
176
+ COUNTA
177
+ MAX
178
+ MIN
179
+ SUMPRODUCT
180
+ COUNTIFS
181
+ CONCATENATE
182
+ }
183
+
184
+ def function_pi()
146
185
  "M_PI"
147
186
  end
148
-
187
+
149
188
  def function_choose(index,*arguments)
150
189
  "#{FUNCTIONS[:CHOOSE]}(#{map(index)}, #{map_arguments_to_array(arguments)})"
151
190
  end
152
-
191
+
153
192
  def function_subtotal(type,*arguments)
154
193
  "#{FUNCTIONS[:SUBTOTAL]}(#{map(type)}, #{map_arguments_to_array(arguments)})"
155
194
  end
@@ -205,11 +244,11 @@ class MapFormulaeToC < MapValuesToC
205
244
 
206
245
  return result_name
207
246
  end
208
-
209
- def any_number_of_argument_function(function_name,arguments)
247
+
248
+ def any_number_of_argument_function(function_name,arguments)
210
249
  "#{FUNCTIONS[function_name.to_sym]}(#{map_arguments_to_array(arguments)})"
211
250
  end
212
-
251
+
213
252
  def map_arguments_to_array(arguments)
214
253
  # First we have to create an excel array
215
254
  array_name = "array#{@counter}"
@@ -219,7 +258,7 @@ class MapFormulaeToC < MapValuesToC
219
258
  initializers << "ExcelValue #{array_name}[] = {#{arguments}};"
220
259
  "#{arguments_size}, #{array_name}"
221
260
  end
222
-
261
+
223
262
  def cell(reference)
224
263
  # FIXME: What a cludge.
225
264
  if reference =~ /common\d+/
@@ -228,7 +267,7 @@ class MapFormulaeToC < MapValuesToC
228
267
  reference.to_s.downcase.gsub('$','')
229
268
  end
230
269
  end
231
-
270
+
232
271
  def sheet_reference(sheet,reference)
233
272
  "#{sheet_names[sheet]}_#{map(reference).to_s.downcase}()"
234
273
  end
@@ -252,7 +291,7 @@ class MapFormulaeToC < MapValuesToC
252
291
  i += 1
253
292
  end
254
293
  end
255
-
294
+
256
295
  # Then we need to assign it to an excel value
257
296
  range_name = array_name+"_ev"
258
297
  initializers << "ExcelValue #{range_name} = EXCEL_RANGE(#{array_name},#{number_of_rows},#{number_of_columns});"