excel_to_code 0.3.17 → 0.3.18.beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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});"