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.
- checksums.yaml +5 -5
- data/README.md +67 -34
- data/bin/excel_to_c +8 -78
- data/bin/excel_to_go +41 -0
- data/bin/excel_to_ruby +2 -69
- data/src/commands.rb +2 -0
- data/src/commands/common_command_line_options.rb +81 -0
- data/src/commands/excel_to_c.rb +3 -0
- data/src/commands/excel_to_go.rb +91 -0
- data/src/commands/excel_to_x.rb +77 -11
- data/src/compile.rb +1 -0
- data/src/compile/c/a.out +0 -0
- data/src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out +0 -0
- data/src/compile/c/compile_to_c.rb +2 -0
- data/src/compile/c/excel_to_c_runtime.c +691 -145
- data/src/compile/c/excel_to_c_runtime_test.c +226 -20
- data/src/compile/c/map_formulae_to_c.rb +62 -23
- data/src/compile/c/run_c_unit_tests +3 -0
- data/src/compile/cd.rb +6 -0
- data/src/compile/go.rb +3 -0
- data/src/compile/go/compile_to_go.rb +85 -0
- data/src/compile/go/compile_to_go_test.rb +73 -0
- data/src/compile/go/excel.go +171 -0
- data/src/compile/go/excel_test.go +54 -0
- data/src/compile/go/map_values_to_go.rb +67 -0
- data/src/compile/ruby/map_formulae_to_ruby.rb +30 -12
- data/src/excel/excel_functions.rb +26 -1
- data/src/excel/excel_functions/ceiling.rb +23 -0
- data/src/excel/excel_functions/countif.rb +15 -0
- data/src/excel/excel_functions/countifs.rb +10 -0
- data/src/excel/excel_functions/floor.rb +14 -0
- data/src/excel/excel_functions/hyperlink.rb +9 -0
- data/src/excel/excel_functions/na.rb +7 -0
- data/src/excel/excel_functions/not.rb +13 -0
- data/src/excel/excel_functions/or.rb +30 -0
- data/src/excel/excel_functions/product.rb +8 -0
- data/src/excel/excel_functions/rate.rb +16 -0
- data/src/excel/excel_functions/replace.rb +13 -0
- data/src/excel/excel_functions/scurve.rb +73 -0
- data/src/excel/excel_functions/sqrt.rb +11 -0
- data/src/excel/excel_functions/string_argument.rb +37 -0
- data/src/excel/excel_functions/sumifs.rb +19 -8
- data/src/excel/excel_functions/text.rb +3 -3
- data/src/excel/formula_peg.rb +1 -1
- data/src/excel/formula_peg.txt +2 -3
- data/src/excel/table.rb +15 -15
- data/src/excel_to_code.rb +1 -4
- data/src/extract/extract_data_from_worksheet.rb +8 -1
- data/src/rewrite/ast_expand_array_formulae.rb +4 -0
- data/src/rewrite/caching_formula_parser.rb +16 -11
- data/src/simplify.rb +1 -0
- data/src/simplify/inline_formulae.rb +16 -0
- data/src/simplify/replace_arithmetic_on_ranges.rb +14 -1
- data/src/simplify/replace_arrays_with_single_cells.rb +42 -15
- data/src/simplify/replace_cell_addresses_with_references.rb +70 -0
- data/src/simplify/replace_column_with_column_number.rb +8 -1
- data/src/simplify/replace_table_references.rb +40 -19
- data/src/simplify/simplify_arithmetic.rb +15 -10
- data/src/version.rb +4 -0
- metadata +115 -43
- 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{
|
144
|
-
|
145
|
-
|
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});"
|