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.
- 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});"
|