excel_to_code 0.3.18.beta.1 → 0.3.20
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 +4 -4
- data/src/commands/excel_to_x.rb +13 -4
- data/src/compile/c/excel_to_c_runtime.c +255 -3
- data/src/compile/c/excel_to_c_runtime_test.c +38 -0
- data/src/compile/c/map_formulae_to_c.rb +3 -0
- data/src/compile/ruby/map_formulae_to_ruby.rb +2 -1
- data/src/excel/excel_functions/mround.rb +19 -0
- data/src/excel/excel_functions/sumifs.rb +1 -1
- data/src/excel/excel_functions/text.rb +4 -1
- data/src/excel/excel_functions.rb +2 -0
- data/src/excel/reference.rb +1 -1
- data/src/rewrite/ast_expand_array_formulae.rb +4 -0
- data/src/rewrite/rewrite_array_formulae.rb +2 -2
- data/src/simplify/replace_arrays_with_single_cells.rb +30 -0
- data/src/simplify/replace_common_elements_in_formulae.rb +1 -1
- data/src/simplify/replace_named_references.rb +16 -1
- data/src/simplify/replace_offsets_with_references.rb +39 -7
- data/src/util.rb +1 -2
- data/src/version.rb +1 -1
- metadata +9 -13
- data/src/compile/c/a.out +0 -0
- data/src/compile/c/a.out.dSYM/Contents/Info.plist +0 -20
- data/src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out +0 -0
- data/src/util/try.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6fe18bdd631dff8de227380800892b66163f2fe7f130891440c7f2e12818a28f
|
4
|
+
data.tar.gz: f0087a3035784f3fedee75f30064beb7f359e7e0f6d79ff0789f6a23aa5ad908
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95f10de60d4ab71095c011ef1857d3467d2d1c88993e75aa560dd16293ee7448c98677715e9fca7fdb937c2793f64a74d20f746cfcfa30d0a636cc9c2eb31587
|
7
|
+
data.tar.gz: 945373d97eb9523d8e6c3151249822af8bc55f3453ded5182d6979dbd5392b35ad1a4919fff367211330304e02164f59b640c6758e3978926b346ef9c7a6df0a
|
data/src/commands/excel_to_x.rb
CHANGED
@@ -342,7 +342,7 @@ class ExcelToX
|
|
342
342
|
begin
|
343
343
|
parsed = CachingFormulaParser.parse(reference, treat_external_references_as_local)
|
344
344
|
if parsed
|
345
|
-
@named_references[name] = parsed
|
345
|
+
@named_references[name] = deep_copy(parsed)
|
346
346
|
else
|
347
347
|
$stderr.puts "Named reference #{name} #{reference} not parsed"
|
348
348
|
exit
|
@@ -363,6 +363,15 @@ class ExcelToX
|
|
363
363
|
|
364
364
|
end
|
365
365
|
|
366
|
+
def deep_copy(ast)
|
367
|
+
return ast if ast.is_a?(Symbol)
|
368
|
+
return ast if ast.is_a?(Numeric)
|
369
|
+
return ast.dup unless ast.is_a?(Array)
|
370
|
+
ast.map do |a|
|
371
|
+
deep_copy(a)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
366
375
|
# Named references can be simple cell references,
|
367
376
|
# or they can be ranges, or errors, or table references
|
368
377
|
# this function converts all the different types into
|
@@ -375,7 +384,7 @@ class ExcelToX
|
|
375
384
|
@named_references.each do |name, reference|
|
376
385
|
reference = table_reference_replacer.map(reference)
|
377
386
|
reference = @replace_ranges_with_array_literals_replacer.map(reference)
|
378
|
-
@named_references[name] = reference
|
387
|
+
@named_references[name] = deep_copy(reference)
|
379
388
|
end
|
380
389
|
|
381
390
|
end
|
@@ -613,7 +622,7 @@ class ExcelToX
|
|
613
622
|
end
|
614
623
|
|
615
624
|
def check_all_functions_implemented
|
616
|
-
functions_that_are_removed_during_compilation = [:INDIRECT, :OFFSET, :ROW, :COLUMN, :TRANSPOSE]
|
625
|
+
functions_that_are_removed_during_compilation = [:INDIRECT, :OFFSET, :ROW, :COLUMN, :TRANSPOSE, :'_xlfn.SINGLE']
|
617
626
|
functions_used = CachingFormulaParser.instance.functions_used.keys
|
618
627
|
functions_used.delete_if do |f|
|
619
628
|
MapFormulaeToRuby::FUNCTIONS[f]
|
@@ -1133,7 +1142,7 @@ class ExcelToX
|
|
1133
1142
|
replacements_made_in_the_last_pass += indirect_replacement.count_replaced
|
1134
1143
|
|
1135
1144
|
log.info "Pass #{number_of_passes}: Made #{replacements_made_in_the_last_pass} replacements"
|
1136
|
-
end while replacements_made_in_the_last_pass > 0 && number_of_passes <
|
1145
|
+
end while replacements_made_in_the_last_pass > 0 && number_of_passes < 50
|
1137
1146
|
end
|
1138
1147
|
|
1139
1148
|
|
@@ -86,6 +86,7 @@ static ExcelValue max(int number_of_arguments, ExcelValue *arguments);
|
|
86
86
|
static ExcelValue min(int number_of_arguments, ExcelValue *arguments);
|
87
87
|
static ExcelValue mmult(ExcelValue a_v, ExcelValue b_v);
|
88
88
|
static ExcelValue mod(ExcelValue a_v, ExcelValue b_v);
|
89
|
+
static ExcelValue mround(ExcelValue value_v, ExcelValue multiple_v);
|
89
90
|
static ExcelValue na();
|
90
91
|
static ExcelValue negative(ExcelValue a_v);
|
91
92
|
static ExcelValue excel_not(ExcelValue a_v);
|
@@ -107,6 +108,9 @@ static ExcelValue rounddown(ExcelValue number_v, ExcelValue decimal_places_v);
|
|
107
108
|
static ExcelValue roundup(ExcelValue number_v, ExcelValue decimal_places_v);
|
108
109
|
static ExcelValue excel_int(ExcelValue number_v);
|
109
110
|
static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments);
|
111
|
+
static ExcelValue substitute_3(ExcelValue string_v, ExcelValue old_string_v, ExcelValue new_string_v);
|
112
|
+
static ExcelValue substitute_4(ExcelValue string_v, ExcelValue old_string_v, ExcelValue new_string_v, ExcelValue occurrence_number_v);
|
113
|
+
static ExcelValue substitute(ExcelValue string_v, ExcelValue old_string_v, ExcelValue new_string_v, int occurrence);
|
110
114
|
static ExcelValue subtotal(ExcelValue type, int number_of_arguments, ExcelValue *arguments);
|
111
115
|
static ExcelValue sumifs(ExcelValue sum_range_v, int number_of_arguments, ExcelValue *arguments);
|
112
116
|
static ExcelValue sumif(ExcelValue check_range_v, ExcelValue criteria_v, ExcelValue sum_range_v );
|
@@ -305,7 +309,50 @@ static double number_from(ExcelValue v) {
|
|
305
309
|
return 0;
|
306
310
|
}
|
307
311
|
|
308
|
-
|
312
|
+
static char* string_from(ExcelValue v) {
|
313
|
+
char *string;
|
314
|
+
switch (v.type) {
|
315
|
+
case ExcelString:
|
316
|
+
return v.string;
|
317
|
+
break;
|
318
|
+
case ExcelNumber:
|
319
|
+
string = malloc(20);
|
320
|
+
if(string == 0) {
|
321
|
+
printf("Out of memory in string_from");
|
322
|
+
exit(-1);
|
323
|
+
}
|
324
|
+
snprintf(string,20,"%g",v.number);
|
325
|
+
free_later(string);
|
326
|
+
return string;
|
327
|
+
break;
|
328
|
+
case ExcelBoolean:
|
329
|
+
if(v.number == true) {
|
330
|
+
string = "TRUE";
|
331
|
+
free_later(string);
|
332
|
+
return string;
|
333
|
+
} else {
|
334
|
+
string = "FALSE";
|
335
|
+
free_later(string);
|
336
|
+
return string;
|
337
|
+
}
|
338
|
+
break;
|
339
|
+
case ExcelEmpty:
|
340
|
+
string = "";
|
341
|
+
free_later(string);
|
342
|
+
break;
|
343
|
+
case ExcelError:
|
344
|
+
conversion_error = 1;
|
345
|
+
return 0;
|
346
|
+
case ExcelRange:
|
347
|
+
conversion_error = 1;
|
348
|
+
return 0;
|
349
|
+
}
|
350
|
+
conversion_error = 1;
|
351
|
+
return 0;
|
352
|
+
}
|
353
|
+
|
354
|
+
#define NUMBER(value_name, name) double name; if(value_name.type == ExcelError) { conversion_error = 0; return value_name; }; name = number_from(value_name);
|
355
|
+
#define STRING(value_name, name) char *name; if(value_name.type == ExcelError) { conversion_error = 0; return value_name; }; name = string_from(value_name);
|
309
356
|
#define CHECK_FOR_CONVERSION_ERROR if(conversion_error) { conversion_error = 0; return VALUE; };
|
310
357
|
#define CHECK_FOR_PASSED_ERROR(name) if(name.type == ExcelError) return name;
|
311
358
|
|
@@ -465,6 +512,7 @@ static ExcelValue rate(ExcelValue periods_v, ExcelValue payment_v, ExcelValue pr
|
|
465
512
|
NUMBER(payment_v, payment)
|
466
513
|
NUMBER(presentValue_v, presentValue)
|
467
514
|
NUMBER(finalValue_v, finalValue)
|
515
|
+
CHECK_FOR_CONVERSION_ERROR;
|
468
516
|
|
469
517
|
// FIXME: Only implemented the case where payment is zero
|
470
518
|
if(payment != 0) {
|
@@ -474,6 +522,29 @@ static ExcelValue rate(ExcelValue periods_v, ExcelValue payment_v, ExcelValue pr
|
|
474
522
|
return EXCEL_NUMBER(pow((finalValue/(-presentValue)),(1.0/periods))-1.0);
|
475
523
|
}
|
476
524
|
|
525
|
+
static ExcelValue mround(ExcelValue value_v, ExcelValue multiple_v) {
|
526
|
+
CHECK_FOR_PASSED_ERROR(value_v)
|
527
|
+
CHECK_FOR_PASSED_ERROR(multiple_v)
|
528
|
+
|
529
|
+
NUMBER(value_v, value)
|
530
|
+
NUMBER(multiple_v, multiple)
|
531
|
+
CHECK_FOR_CONVERSION_ERROR;
|
532
|
+
|
533
|
+
if( (value < 0) != (multiple < 0)) {
|
534
|
+
return NUM;
|
535
|
+
}
|
536
|
+
|
537
|
+
if(value == 0) {
|
538
|
+
return ZERO;
|
539
|
+
}
|
540
|
+
|
541
|
+
if(multiple == 0) {
|
542
|
+
return ZERO;
|
543
|
+
}
|
544
|
+
|
545
|
+
return EXCEL_NUMBER(round(value / multiple) * multiple);
|
546
|
+
}
|
547
|
+
|
477
548
|
static ExcelValue excel_and(int array_size, ExcelValue *array) {
|
478
549
|
int i;
|
479
550
|
ExcelValue current_excel_value, array_result;
|
@@ -1777,12 +1848,11 @@ static ExcelValue rank(ExcelValue number_v, ExcelValue range_v, ExcelValue order
|
|
1777
1848
|
|
1778
1849
|
NUMBER(number_v, number)
|
1779
1850
|
NUMBER(order_v, order)
|
1851
|
+
CHECK_FOR_CONVERSION_ERROR
|
1780
1852
|
|
1781
1853
|
ExcelValue *array;
|
1782
1854
|
int size;
|
1783
1855
|
|
1784
|
-
CHECK_FOR_CONVERSION_ERROR
|
1785
|
-
|
1786
1856
|
if(range_v.type != ExcelRange) {
|
1787
1857
|
array = new_excel_value_array(1);
|
1788
1858
|
array[0] = range_v;
|
@@ -1934,6 +2004,129 @@ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
|
|
1934
2004
|
return EXCEL_STRING(string);
|
1935
2005
|
}
|
1936
2006
|
|
2007
|
+
static ExcelValue substitute_3(ExcelValue string_v, ExcelValue old_string_v, ExcelValue new_string_v) {
|
2008
|
+
// -1 means all occurrences
|
2009
|
+
return substitute(string_v, old_string_v, new_string_v, -1);
|
2010
|
+
}
|
2011
|
+
|
2012
|
+
static ExcelValue substitute_4(ExcelValue string_v, ExcelValue old_string_v, ExcelValue new_string_v, ExcelValue occurrence_number_v) {
|
2013
|
+
CHECK_FOR_PASSED_ERROR(occurrence_number_v)
|
2014
|
+
NUMBER(occurrence_number_v,occurrence_number)
|
2015
|
+
CHECK_FOR_CONVERSION_ERROR
|
2016
|
+
return substitute(string_v, old_string_v, new_string_v, occurrence_number);
|
2017
|
+
}
|
2018
|
+
|
2019
|
+
// Pass < 0 to occurrence_n to replace all occurrences
|
2020
|
+
static ExcelValue substitute(ExcelValue string_v, ExcelValue old_string_v, ExcelValue new_string_v, int occurrence_n) {
|
2021
|
+
STRING(string_v, original)
|
2022
|
+
STRING(old_string_v, from_string)
|
2023
|
+
STRING(new_string_v, to_string)
|
2024
|
+
CHECK_FOR_CONVERSION_ERROR
|
2025
|
+
|
2026
|
+
char *new_string = 0; // Allocated below
|
2027
|
+
int original_length = strlen(original);
|
2028
|
+
int from_string_length = strlen(from_string);
|
2029
|
+
int to_string_length = strlen(to_string);
|
2030
|
+
int extra_space_per_replacement = (from_string_length < to_string_length) ? (to_string_length - from_string_length) : 0;
|
2031
|
+
|
2032
|
+
if(from_string_length == 0) {
|
2033
|
+
return string_v;
|
2034
|
+
}
|
2035
|
+
|
2036
|
+
int allocated_length = 0; // Adjusted below
|
2037
|
+
int space_for_number_of_replacements = 0; // Adjusted below
|
2038
|
+
int replacement_made = 0;
|
2039
|
+
int number_of_matches = 0;
|
2040
|
+
int insertion_point_offset = 0;
|
2041
|
+
char *insertion_point = 0;
|
2042
|
+
char *from_point = original;
|
2043
|
+
char *match_point = 0;
|
2044
|
+
|
2045
|
+
if(extra_space_per_replacement > 0) {
|
2046
|
+
space_for_number_of_replacements = 5;
|
2047
|
+
// Arbitrarily assume 5 replacements as a starting point, plus one for terminator
|
2048
|
+
allocated_length = original_length + (space_for_number_of_replacements * extra_space_per_replacement) + 1;
|
2049
|
+
} else {
|
2050
|
+
// Should be shorter or the same length
|
2051
|
+
allocated_length = original_length + 1;
|
2052
|
+
}
|
2053
|
+
|
2054
|
+
new_string = malloc(allocated_length);
|
2055
|
+
insertion_point = new_string;
|
2056
|
+
|
2057
|
+
if(new_string == 0) {
|
2058
|
+
printf("Out of memory in substitute");
|
2059
|
+
exit(-1);
|
2060
|
+
}
|
2061
|
+
|
2062
|
+
while((from_point-original) < original_length) {
|
2063
|
+
match_point = strstr(from_point, from_string);
|
2064
|
+
|
2065
|
+
// No match found
|
2066
|
+
if(match_point == NULL) {
|
2067
|
+
// No match ever found? return the original
|
2068
|
+
if(number_of_matches == 0) {
|
2069
|
+
break;
|
2070
|
+
}
|
2071
|
+
// Copy the remaining string into the target. We should always have space.
|
2072
|
+
replacement_made = 1;
|
2073
|
+
strcpy(insertion_point, from_point);
|
2074
|
+
break;
|
2075
|
+
}
|
2076
|
+
|
2077
|
+
number_of_matches = number_of_matches + 1;
|
2078
|
+
|
2079
|
+
// We may only want to replace a single occurrence
|
2080
|
+
if(occurrence_n > 0 && occurrence_n != number_of_matches) {
|
2081
|
+
// Copy the bit before
|
2082
|
+
memcpy(insertion_point, from_point, match_point - from_point);
|
2083
|
+
insertion_point = insertion_point + (match_point - from_point);
|
2084
|
+
|
2085
|
+
// Copy the original
|
2086
|
+
memcpy(insertion_point, from_string, from_string_length);
|
2087
|
+
insertion_point = insertion_point + from_string_length;
|
2088
|
+
|
2089
|
+
from_point = match_point + from_string_length;
|
2090
|
+
continue;
|
2091
|
+
}
|
2092
|
+
|
2093
|
+
// We want to replace this occurrence
|
2094
|
+
|
2095
|
+
// Check we hvae enough space for the replacement
|
2096
|
+
if(extra_space_per_replacement > 0 && (number_of_matches > space_for_number_of_replacements)) {
|
2097
|
+
space_for_number_of_replacements = space_for_number_of_replacements * 2;
|
2098
|
+
allocated_length = original_length + (space_for_number_of_replacements * extra_space_per_replacement) + 1;
|
2099
|
+
insertion_point_offset = insertion_point - new_string;
|
2100
|
+
new_string = realloc(new_string,allocated_length);
|
2101
|
+
insertion_point = new_string + insertion_point_offset;
|
2102
|
+
if(!new_string) {
|
2103
|
+
printf("Out of memory in string substitute realloc trying to increase length to %d", allocated_length);
|
2104
|
+
exit(-1);
|
2105
|
+
}
|
2106
|
+
}
|
2107
|
+
|
2108
|
+
replacement_made = 1;
|
2109
|
+
|
2110
|
+
// Copy up to the match
|
2111
|
+
memcpy(insertion_point, from_point, match_point - from_point);
|
2112
|
+
insertion_point = insertion_point + (match_point - from_point);
|
2113
|
+
|
2114
|
+
// Copy the replacement
|
2115
|
+
memcpy(insertion_point, to_string, to_string_length);
|
2116
|
+
insertion_point = insertion_point + to_string_length;
|
2117
|
+
|
2118
|
+
from_point = match_point + from_string_length;
|
2119
|
+
}
|
2120
|
+
|
2121
|
+
if(replacement_made == 1) {
|
2122
|
+
free_later(new_string);
|
2123
|
+
return EXCEL_STRING(new_string);
|
2124
|
+
} else {
|
2125
|
+
free(new_string);
|
2126
|
+
return string_v;
|
2127
|
+
}
|
2128
|
+
}
|
2129
|
+
|
1937
2130
|
static ExcelValue subtotal(ExcelValue subtotal_type_v, int number_of_arguments, ExcelValue *arguments) {
|
1938
2131
|
CHECK_FOR_PASSED_ERROR(subtotal_type_v)
|
1939
2132
|
NUMBER(subtotal_type_v,subtotal_type)
|
@@ -2022,18 +2215,30 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
2022
2215
|
|
2023
2216
|
if(current_value.type == ExcelString) {
|
2024
2217
|
s = current_value.string;
|
2218
|
+
while(s[0] == ' ') {
|
2219
|
+
s = s + 1;
|
2220
|
+
}
|
2025
2221
|
if(s[0] == '<') {
|
2026
2222
|
if( s[1] == '>') {
|
2223
|
+
while(s[2] == ' ') {
|
2224
|
+
s = s + 1;
|
2225
|
+
}
|
2027
2226
|
new_comparator = strndup(s+2,strlen(s)-2);
|
2028
2227
|
free_later(new_comparator);
|
2029
2228
|
criteria[i].type = NotEqual;
|
2030
2229
|
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
2031
2230
|
} else if(s[1] == '=') {
|
2231
|
+
while(s[2] == ' ') {
|
2232
|
+
s = s + 1;
|
2233
|
+
}
|
2032
2234
|
new_comparator = strndup(s+2,strlen(s)-2);
|
2033
2235
|
free_later(new_comparator);
|
2034
2236
|
criteria[i].type = LessThanOrEqual;
|
2035
2237
|
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
2036
2238
|
} else {
|
2239
|
+
while(s[1] == ' ') {
|
2240
|
+
s = s + 1;
|
2241
|
+
}
|
2037
2242
|
new_comparator = strndup(s+1,strlen(s)-1);
|
2038
2243
|
free_later(new_comparator);
|
2039
2244
|
criteria[i].type = LessThan;
|
@@ -2041,17 +2246,26 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
2041
2246
|
}
|
2042
2247
|
} else if(s[0] == '>') {
|
2043
2248
|
if(s[1] == '=') {
|
2249
|
+
while(s[2] == ' ') {
|
2250
|
+
s = s + 1;
|
2251
|
+
}
|
2044
2252
|
new_comparator = strndup(s+2,strlen(s)-2);
|
2045
2253
|
free_later(new_comparator);
|
2046
2254
|
criteria[i].type = MoreThanOrEqual;
|
2047
2255
|
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
2048
2256
|
} else {
|
2257
|
+
while(s[1] == ' ') {
|
2258
|
+
s = s + 1;
|
2259
|
+
}
|
2049
2260
|
new_comparator = strndup(s+1,strlen(s)-1);
|
2050
2261
|
free_later(new_comparator);
|
2051
2262
|
criteria[i].type = MoreThan;
|
2052
2263
|
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
2053
2264
|
}
|
2054
2265
|
} else if(s[0] == '=') {
|
2266
|
+
while(s[1] == ' ') {
|
2267
|
+
s = s + 1;
|
2268
|
+
}
|
2055
2269
|
new_comparator = strndup(s+1,strlen(s)-1);
|
2056
2270
|
free_later(new_comparator);
|
2057
2271
|
criteria[i].type = Equal;
|
@@ -2273,18 +2487,30 @@ static ExcelValue countifs(int number_of_arguments, ExcelValue *arguments) {
|
|
2273
2487
|
|
2274
2488
|
if(current_value.type == ExcelString) {
|
2275
2489
|
s = current_value.string;
|
2490
|
+
while(s[0] == ' ') {
|
2491
|
+
s = s + 1;
|
2492
|
+
}
|
2276
2493
|
if(s[0] == '<') {
|
2277
2494
|
if( s[1] == '>') {
|
2495
|
+
while(s[2] == ' ') {
|
2496
|
+
s = s + 1;
|
2497
|
+
}
|
2278
2498
|
new_comparator = strndup(s+2,strlen(s)-2);
|
2279
2499
|
free_later(new_comparator);
|
2280
2500
|
criteria[i].type = NotEqual;
|
2281
2501
|
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
2282
2502
|
} else if(s[1] == '=') {
|
2503
|
+
while(s[2] == ' ') {
|
2504
|
+
s = s + 1;
|
2505
|
+
}
|
2283
2506
|
new_comparator = strndup(s+2,strlen(s)-2);
|
2284
2507
|
free_later(new_comparator);
|
2285
2508
|
criteria[i].type = LessThanOrEqual;
|
2286
2509
|
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
2287
2510
|
} else {
|
2511
|
+
while(s[1] == ' ') {
|
2512
|
+
s = s + 1;
|
2513
|
+
}
|
2288
2514
|
new_comparator = strndup(s+1,strlen(s)-1);
|
2289
2515
|
free_later(new_comparator);
|
2290
2516
|
criteria[i].type = LessThan;
|
@@ -2292,17 +2518,26 @@ static ExcelValue countifs(int number_of_arguments, ExcelValue *arguments) {
|
|
2292
2518
|
}
|
2293
2519
|
} else if(s[0] == '>') {
|
2294
2520
|
if(s[1] == '=') {
|
2521
|
+
while(s[2] == ' ') {
|
2522
|
+
s = s + 1;
|
2523
|
+
}
|
2295
2524
|
new_comparator = strndup(s+2,strlen(s)-2);
|
2296
2525
|
free_later(new_comparator);
|
2297
2526
|
criteria[i].type = MoreThanOrEqual;
|
2298
2527
|
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
2299
2528
|
} else {
|
2529
|
+
while(s[1] == ' ') {
|
2530
|
+
s = s + 1;
|
2531
|
+
}
|
2300
2532
|
new_comparator = strndup(s+1,strlen(s)-1);
|
2301
2533
|
free_later(new_comparator);
|
2302
2534
|
criteria[i].type = MoreThan;
|
2303
2535
|
criteria[i].comparator = EXCEL_STRING(new_comparator);
|
2304
2536
|
}
|
2305
2537
|
} else if(s[0] == '=') {
|
2538
|
+
while(s[1] == ' ') {
|
2539
|
+
s = s + 1;
|
2540
|
+
}
|
2306
2541
|
new_comparator = strndup(s+1,strlen(s)-1);
|
2307
2542
|
free_later(new_comparator);
|
2308
2543
|
criteria[i].type = Equal;
|
@@ -2678,6 +2913,8 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
|
|
2678
2913
|
snprintf(s, 99, "%'0.3f",number_v.number);
|
2679
2914
|
} else if(strcmp(format_v.string,"0000") == 0) {
|
2680
2915
|
snprintf(s, 99, "%04.0f",number_v.number);
|
2916
|
+
} else if(strcmp(format_v.string,"#,000") == 0) {
|
2917
|
+
snprintf(s, 99, "%'03.0f",number_v.number);
|
2681
2918
|
} else {
|
2682
2919
|
snprintf(s, 99, "Text format not recognised");
|
2683
2920
|
}
|
@@ -2821,6 +3058,11 @@ static ExcelValue curve_5(ExcelValue curveType, ExcelValue currentYear, ExcelVal
|
|
2821
3058
|
}
|
2822
3059
|
|
2823
3060
|
static ExcelValue scurve(ExcelValue currentYear_v, ExcelValue startValue_v, ExcelValue endValue_v, ExcelValue duration_v, ExcelValue startYear_v) {
|
3061
|
+
CHECK_FOR_PASSED_ERROR(currentYear_v)
|
3062
|
+
CHECK_FOR_PASSED_ERROR(startValue_v)
|
3063
|
+
CHECK_FOR_PASSED_ERROR(endValue_v)
|
3064
|
+
CHECK_FOR_PASSED_ERROR(duration_v)
|
3065
|
+
CHECK_FOR_PASSED_ERROR(startYear_v)
|
2824
3066
|
|
2825
3067
|
NUMBER(currentYear_v, currentYear)
|
2826
3068
|
NUMBER(startValue_v, startValue)
|
@@ -2844,6 +3086,11 @@ static ExcelValue scurve(ExcelValue currentYear_v, ExcelValue startValue_v, Exce
|
|
2844
3086
|
}
|
2845
3087
|
|
2846
3088
|
static ExcelValue halfscurve(ExcelValue currentYear_v, ExcelValue startValue_v, ExcelValue endValue_v, ExcelValue duration_v, ExcelValue startYear_v) {
|
3089
|
+
CHECK_FOR_PASSED_ERROR(currentYear_v)
|
3090
|
+
CHECK_FOR_PASSED_ERROR(startValue_v)
|
3091
|
+
CHECK_FOR_PASSED_ERROR(endValue_v)
|
3092
|
+
CHECK_FOR_PASSED_ERROR(duration_v)
|
3093
|
+
CHECK_FOR_PASSED_ERROR(startYear_v)
|
2847
3094
|
|
2848
3095
|
NUMBER(currentYear_v, currentYear)
|
2849
3096
|
NUMBER(startValue_v, startValue)
|
@@ -2867,6 +3114,11 @@ static ExcelValue halfscurve(ExcelValue currentYear_v, ExcelValue startValue_v,
|
|
2867
3114
|
}
|
2868
3115
|
|
2869
3116
|
static ExcelValue lcurve(ExcelValue currentYear_v, ExcelValue startValue_v, ExcelValue endValue_v, ExcelValue duration_v, ExcelValue startYear_v) {
|
3117
|
+
CHECK_FOR_PASSED_ERROR(currentYear_v)
|
3118
|
+
CHECK_FOR_PASSED_ERROR(startValue_v)
|
3119
|
+
CHECK_FOR_PASSED_ERROR(endValue_v)
|
3120
|
+
CHECK_FOR_PASSED_ERROR(duration_v)
|
3121
|
+
CHECK_FOR_PASSED_ERROR(startYear_v)
|
2870
3122
|
|
2871
3123
|
NUMBER(currentYear_v, currentYear)
|
2872
3124
|
NUMBER(startValue_v, startValue)
|
@@ -585,6 +585,8 @@ int test_functions() {
|
|
585
585
|
|
586
586
|
ExcelValue sumifs_array_10f[] = { sumifs_array_3_v, EXCEL_STRING(">=3")};
|
587
587
|
assert(sumifs(sumifs_array_3_v,2, sumifs_array_10f).number == 17);
|
588
|
+
ExcelValue sumifs_array_10g[] = { sumifs_array_3_v, EXCEL_STRING(" >= 3")};
|
589
|
+
assert(sumifs(sumifs_array_3_v,2, sumifs_array_10g).number == 17);
|
588
590
|
|
589
591
|
// ... BLANK in check range should match empty strings, BLANK in criteria should match zero
|
590
592
|
ExcelValue sumifs_array_11[] = { BLANK, EXCEL_NUMBER(0)};
|
@@ -658,6 +660,9 @@ int test_functions() {
|
|
658
660
|
ExcelValue countifs_array_10e[] = { countifs_array_3_v, EXCEL_STRING(">3")};
|
659
661
|
assert(countifs(2, countifs_array_10e).number == 3.0);
|
660
662
|
|
663
|
+
ExcelValue countifs_array_10e2[] = { countifs_array_3_v, EXCEL_STRING("> 3")};
|
664
|
+
assert(countifs(2, countifs_array_10e2).number == 3.0);
|
665
|
+
|
661
666
|
ExcelValue countifs_array_10f[] = { countifs_array_3_v, EXCEL_STRING(">=3")};
|
662
667
|
assert(countifs(2, countifs_array_10f).number == 4.0);
|
663
668
|
|
@@ -890,6 +895,8 @@ int test_functions() {
|
|
890
895
|
assert(strcmp(text(EXCEL_NUMBER(123456789.123456), EXCEL_STRING("#,##")).string, "123,456,789") == 0);
|
891
896
|
assert(strcmp(text(EXCEL_NUMBER(123456789.123456), EXCEL_STRING("#,##0")).string, "123,456,789") == 0);
|
892
897
|
assert(strcmp(text(EXCEL_NUMBER(123456789.123456), EXCEL_STRING("#,##0.0")).string, "123,456,789.1") == 0);
|
898
|
+
assert(strcmp(text(EXCEL_NUMBER(3.1), EXCEL_STRING("#,000")).string, "003") == 0);
|
899
|
+
assert(strcmp(text(EXCEL_NUMBER(1000.3), EXCEL_STRING("#,000")).string, "1,000") == 0);
|
893
900
|
assert(strcmp(text(EXCEL_NUMBER(123456789.123456), EXCEL_STRING("!#,##0.0")).string, "Text format not recognised") == 0);
|
894
901
|
|
895
902
|
// Test LOG
|
@@ -1212,6 +1219,21 @@ int test_functions() {
|
|
1212
1219
|
assert(excel_ceiling_math(EXCEL_NUMBER(136), EXCEL_NUMBER(10), ZERO).number == 140);
|
1213
1220
|
assert(excel_ceiling_math(EXCEL_NUMBER(-136), EXCEL_NUMBER(10), ZERO).number == -130);
|
1214
1221
|
assert(excel_ceiling_math(EXCEL_NUMBER(-136), EXCEL_NUMBER(10), ONE).number == -140);
|
1222
|
+
|
1223
|
+
// MROUND
|
1224
|
+
assert(mround(EXCEL_NUMBER(1), ZERO).number == 0.0);
|
1225
|
+
assert(mround(ZERO, EXCEL_NUMBER(1)).number == 0.0);
|
1226
|
+
assert(mround(EXCEL_NUMBER(1), EXCEL_NUMBER(1)).number == 1.0);
|
1227
|
+
assert(mround(EXCEL_NUMBER(105), EXCEL_NUMBER(10)).number == 110);
|
1228
|
+
assert(mround(EXCEL_NUMBER(1.05), EXCEL_NUMBER(0.1)).number == 1.10);
|
1229
|
+
assert(mround(EXCEL_NUMBER(-1.05), EXCEL_NUMBER(-0.1)).number == -1.10);
|
1230
|
+
assert(mround(EXCEL_NUMBER(-1.05), EXCEL_NUMBER(0.1)).type == ExcelError);
|
1231
|
+
|
1232
|
+
// SUBSTITUTE 3
|
1233
|
+
assert_equal(EXCEL_STRING("Hello Bob, Dear Bob"), substitute_3(EXCEL_STRING("Hello Bob, Dear Bob"), EXCEL_STRING("Bill"), EXCEL_STRING("Frank")), "substitute('Hello Bob, Dear Bob', 'Bill', 'Frank') = 'Hello Bob, Dear Bob')");
|
1234
|
+
assert_equal(EXCEL_STRING("Hello Frank, Dear Frank"), substitute_3(EXCEL_STRING("Hello Bob, Dear Bob"), EXCEL_STRING("Bob"), EXCEL_STRING("Frank")), "substitute('Hello Bob, Dear Bob', 'Bob', 'Frank') = 'Hello Frank, Dear Frank')");
|
1235
|
+
assert_equal(EXCEL_STRING("Hello Bob, Dear Frank"), substitute_4(EXCEL_STRING("Hello Bob, Dear Bob"), EXCEL_STRING("Bob"), EXCEL_STRING("Frank"), TWO), "substitute('Hello Bob, Dear Bob', 'Bob', 'Frank', 2) = 'Hello Bob, Dear Frank')");
|
1236
|
+
assert_equal(EXCEL_STRING("Hello Bob, Dear Bob"), substitute_4(EXCEL_STRING("Hello Bob, Dear Bob"), EXCEL_STRING("Bob"), EXCEL_STRING("Frank"), THREE), "substitute('Hello Bob, Dear Bob', 'Bob', 'Frank', 3) = 'Hello Bob, Dear Bob')");
|
1215
1237
|
|
1216
1238
|
// curve (a custom climact function)
|
1217
1239
|
assert_equal(
|
@@ -1239,6 +1261,20 @@ int test_functions() {
|
|
1239
1261
|
"curve_5(blank, 2023, 0, 10, 10) == 5"
|
1240
1262
|
);
|
1241
1263
|
|
1264
|
+
// CONVERSION ERROR RESET
|
1265
|
+
assert(conversion_error == 0);
|
1266
|
+
assert_equal(
|
1267
|
+
VALUE,
|
1268
|
+
curve_5(
|
1269
|
+
EXCEL_STRING("s"),
|
1270
|
+
EXCEL_STRING("Should be a number"),
|
1271
|
+
VALUE,
|
1272
|
+
EXCEL_NUMBER(10),
|
1273
|
+
EXCEL_NUMBER(10)
|
1274
|
+
),
|
1275
|
+
"A messed up curve call"
|
1276
|
+
);
|
1277
|
+
assert(conversion_error == 0);
|
1242
1278
|
|
1243
1279
|
// Release memory
|
1244
1280
|
free_all_allocated_memory();
|
@@ -1249,6 +1285,8 @@ int test_functions() {
|
|
1249
1285
|
return 0;
|
1250
1286
|
}
|
1251
1287
|
|
1288
|
+
|
1289
|
+
|
1252
1290
|
int main() {
|
1253
1291
|
return test_functions();
|
1254
1292
|
}
|
@@ -75,6 +75,7 @@ class MapFormulaeToC < MapValuesToC
|
|
75
75
|
:'MIN' => 'min',
|
76
76
|
:'MMULT' => 'mmult',
|
77
77
|
:'MOD' => 'mod',
|
78
|
+
:'MROUND' => 'mround',
|
78
79
|
:'NA' => 'na',
|
79
80
|
:'NOT' => 'excel_not',
|
80
81
|
:'OR' => 'excel_or',
|
@@ -97,6 +98,8 @@ class MapFormulaeToC < MapValuesToC
|
|
97
98
|
:'ROUNDUP' => 'roundup',
|
98
99
|
:'string_join' => 'string_join',
|
99
100
|
:'SUBTOTAL' => 'subtotal',
|
101
|
+
:'SUBSTITUTE3' => 'substitute_3',
|
102
|
+
:'SUBSTITUTE4' => 'substitute_4',
|
100
103
|
:'SUM' => 'sum',
|
101
104
|
:'SUMIF2' => 'sumif_2',
|
102
105
|
:'SUMIF3' => 'sumif',
|
@@ -22,7 +22,6 @@ class MapFormulaeToRuby < MapValuesToRuby
|
|
22
22
|
:'AVERAGE' => 'average',
|
23
23
|
:'AVERAGEIFS' => 'averageifs',
|
24
24
|
:'CEILING' => 'ceiling',
|
25
|
-
:'_xlfn.CEILING.MATH' => 'ceiling',
|
26
25
|
:'CELL' => 'cell',
|
27
26
|
:'CHAR' => 'char',
|
28
27
|
:'CHOOSE' => 'choose',
|
@@ -60,6 +59,7 @@ class MapFormulaeToRuby < MapValuesToRuby
|
|
60
59
|
:'MIN' => 'min',
|
61
60
|
:'MMULT' => 'mmult',
|
62
61
|
:'MOD' => 'mod',
|
62
|
+
:'MROUND' => 'mround',
|
63
63
|
:'NA' => 'na',
|
64
64
|
:'NOT' => 'excel_not',
|
65
65
|
:'NPV' => 'npv',
|
@@ -89,6 +89,7 @@ class MapFormulaeToRuby < MapValuesToRuby
|
|
89
89
|
:'VALUE' => 'value',
|
90
90
|
:'VLOOKUP' => 'vlookup',
|
91
91
|
:'^' => 'power',
|
92
|
+
:'_xlfn.CEILING.MATH' => 'ceiling',
|
92
93
|
:'_xlfn.FORECAST.LINEAR' => 'forecast',
|
93
94
|
:'curve' => 'curve',
|
94
95
|
:'halfscurve' => 'halfscurve',
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ExcelFunctions
|
2
|
+
|
3
|
+
def mround(value, multiple)
|
4
|
+
value = number_argument(value)
|
5
|
+
multiple = number_argument(multiple)
|
6
|
+
return value if value.is_a?(Symbol)
|
7
|
+
return multiple if multiple.is_a?(Symbol)
|
8
|
+
|
9
|
+
# Must both have the same sign
|
10
|
+
return :num unless (value < 0) == (multiple < 0)
|
11
|
+
|
12
|
+
# Zeros just return zero
|
13
|
+
return 0 if value == 0
|
14
|
+
return 0 if multiple == 0
|
15
|
+
|
16
|
+
(value.to_f / multiple.to_f).round * multiple.to_f
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -69,7 +69,7 @@ module ExcelFunctions
|
|
69
69
|
when Numeric
|
70
70
|
check_value == required_value
|
71
71
|
when String
|
72
|
-
required_value =~
|
72
|
+
required_value =~ /^\s*(<=|>=|<|>)?\s*([-+]?[0-9]+\.?[0-9]*([eE][-+]?[0-9]+)?)\s*$/
|
73
73
|
if $1 && $2
|
74
74
|
check_value.send($1,$2.to_f)
|
75
75
|
elsif $2
|
@@ -20,9 +20,12 @@ module ExcelFunctions
|
|
20
20
|
text(number*100, $1)+"%"
|
21
21
|
when /^(0+)$/
|
22
22
|
sprintf("%0#{$1.length}.0f", number)
|
23
|
-
when
|
23
|
+
when /^#[,.]#*(0[.,]0+)?(0*)$/
|
24
24
|
formated_with_decimals = text(number, $1 || "0")
|
25
25
|
parts = formated_with_decimals.split('.')
|
26
|
+
if $2 && parts[0].length < $2.length
|
27
|
+
parts[0] = ("0"*($2.length - parts[0].length))+parts[0]
|
28
|
+
end
|
26
29
|
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")
|
27
30
|
parts.join('.')
|
28
31
|
when /0[.,](0+)/
|
data/src/excel/reference.rb
CHANGED
@@ -99,6 +99,10 @@ class AstExpandArrayFormulae
|
|
99
99
|
def map_match(ast)
|
100
100
|
array_map(ast, false, true, false)
|
101
101
|
end
|
102
|
+
|
103
|
+
def map_offset(ast)
|
104
|
+
array_map(ast, true, false, false, false, false)
|
105
|
+
end
|
102
106
|
|
103
107
|
def map_subtotal(ast)
|
104
108
|
array_map ast, false, *Array.new(ast.length-3,true)
|
@@ -34,11 +34,11 @@ class ExtractArrayFormulaForCell
|
|
34
34
|
ast[@row_offset+1][@column_offset+1] # plus ones to skip tthe [:array,[:row,"cell"]] symbols
|
35
35
|
end
|
36
36
|
|
37
|
-
FUNCTIONS_THAT_CAN_RETURN_ARRAYS = { INDEX: true, MMULT: true}
|
37
|
+
FUNCTIONS_THAT_CAN_RETURN_ARRAYS = { INDEX: true, MMULT: true, OFFSET: true}
|
38
38
|
|
39
39
|
def map_function(ast)
|
40
40
|
return ast unless FUNCTIONS_THAT_CAN_RETURN_ARRAYS.has_key?(ast[1])
|
41
|
-
[:function, :INDEX, ast, @fc.map([:number, (@row_offset+1)]), @fc.map([:number, (column_offset+1)])]
|
41
|
+
[:function, :INDEX, ast.dup, @fc.map([:number, (@row_offset+1)]), @fc.map([:number, (column_offset+1)])]
|
42
42
|
end
|
43
43
|
|
44
44
|
end
|
@@ -67,8 +67,12 @@ class ReplaceArraysWithSingleCellsAst
|
|
67
67
|
# Replacement made in check_match function
|
68
68
|
elsif ast[1] == :INDIRECT && check_indirect(ast)
|
69
69
|
# Replacement made in check function
|
70
|
+
elsif ast[1] == :OFFSET && check_offset(ast)
|
71
|
+
# Replacement made in check function
|
70
72
|
elsif ast[0] == :function && ast[1] == :INDEX && check_index(ast)
|
71
73
|
# Replacement made in check
|
74
|
+
elsif ast[1] == :'_xlfn.SINGLE'
|
75
|
+
ast.replace(try_and_convert_array(ast[2]))
|
72
76
|
end
|
73
77
|
end
|
74
78
|
end
|
@@ -147,6 +151,32 @@ class ReplaceArraysWithSingleCellsAst
|
|
147
151
|
true
|
148
152
|
end
|
149
153
|
|
154
|
+
def check_offset(ast)
|
155
|
+
replacement_made = false
|
156
|
+
#We ALWAYS leave the reference unchanged
|
157
|
+
#if ast[2] && ast[2].first == :array
|
158
|
+
# replacement_made = true
|
159
|
+
# ast[2] = try_and_convert_array(ast[2])
|
160
|
+
#end
|
161
|
+
if ast[3] && ast[3].first == :array
|
162
|
+
replacement_made = true
|
163
|
+
ast[3] = try_and_convert_array(ast[3])
|
164
|
+
end
|
165
|
+
if ast[4] && ast[4].first == :array
|
166
|
+
replacement_made = true
|
167
|
+
ast[4] = try_and_convert_array(ast[4])
|
168
|
+
end
|
169
|
+
if ast[5] && ast[5].first == :array
|
170
|
+
replacement_made = true
|
171
|
+
ast[5] = try_and_convert_array(ast[5])
|
172
|
+
end
|
173
|
+
if ast[6] && ast[6].first == :array
|
174
|
+
replacement_made = true
|
175
|
+
ast[6] = try_and_convert_array(ast[6])
|
176
|
+
end
|
177
|
+
replacement_made
|
178
|
+
end
|
179
|
+
|
150
180
|
def check_sumifs(ast)
|
151
181
|
replacement_made = false
|
152
182
|
i = 4
|
@@ -16,7 +16,7 @@ class ReplaceCommonElementsInFormulae
|
|
16
16
|
input
|
17
17
|
end
|
18
18
|
|
19
|
-
VALUES = {:number => true, :string => true, :blank => true, :null => true, :error => true, :boolean_true => true, :boolean_false => true, :sheet_reference => true, :cell => true, :row => true}
|
19
|
+
VALUES = {:number => true, :string => true, :blank => true, :null => true, :error => true, :boolean_true => true, :boolean_false => true, :sheet_reference => true, :cell => true, :row => true, :comparator => true}
|
20
20
|
|
21
21
|
def replace_repeated_formulae(ast)
|
22
22
|
return ast unless ast.is_a?(Array)
|
@@ -5,16 +5,31 @@ class NamedReferences
|
|
5
5
|
def initialize(refs, tables = {})
|
6
6
|
@named_references = refs
|
7
7
|
@table_data = tables
|
8
|
+
@deepCopyCache = {}
|
8
9
|
end
|
9
10
|
|
10
11
|
def reference_for(sheet,named_reference)
|
11
12
|
sheet = sheet.downcase
|
12
13
|
named_reference = named_reference.downcase.to_sym
|
13
|
-
@named_references[[sheet, named_reference]] ||
|
14
|
+
ref = @named_references[[sheet, named_reference]] ||
|
14
15
|
@named_references[named_reference] ||
|
15
16
|
@table_data[named_reference] ||
|
16
17
|
[:error, :"#NAME?"]
|
18
|
+
return @deepCopyCache[ref] if @deepCopyCache.key?(ref)
|
19
|
+
copy = deep_copy(ref)
|
20
|
+
@deepCopyCache[ref] = copy
|
21
|
+
return copy
|
17
22
|
end
|
23
|
+
|
24
|
+
def deep_copy(ast)
|
25
|
+
return ast if ast.is_a?(Symbol)
|
26
|
+
return ast if ast.is_a?(Numeric)
|
27
|
+
return ast.dup unless ast.is_a?(Array)
|
28
|
+
ast.map do |a|
|
29
|
+
deep_copy(a)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
18
33
|
|
19
34
|
end
|
20
35
|
|
@@ -27,22 +27,49 @@ class ReplaceOffsetsWithReferencesAst
|
|
27
27
|
reference = ast[2]
|
28
28
|
row_offset = ast[3]
|
29
29
|
column_offset = ast[4]
|
30
|
-
height = ast[5]
|
31
|
-
width = ast[6]
|
30
|
+
height = ast[5]
|
31
|
+
width = ast[6]
|
32
|
+
|
33
|
+
reference = reference.original unless %i{cell sheet_reference array}.include?(reference.first)
|
34
|
+
|
35
|
+
unless height
|
36
|
+
if reference.first != :array
|
37
|
+
height = [:number, 1.0]
|
38
|
+
else
|
39
|
+
height = [:number, reference.length - 1]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
unless width
|
44
|
+
if reference.first != :array
|
45
|
+
width = [:number, 1.0]
|
46
|
+
else
|
47
|
+
width = [:number, reference[1].length - 1]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if reference.first == :array
|
52
|
+
reference = reference[1][1].original
|
53
|
+
end
|
54
|
+
|
32
55
|
[row_offset, column_offset, height, width].each do |arg|
|
33
56
|
next unless arg.first == :error
|
34
57
|
ast.replace(arg)
|
35
58
|
return
|
36
59
|
end
|
60
|
+
|
37
61
|
return unless [row_offset, column_offset, height, width].all? { |a| a.first == :number }
|
62
|
+
|
38
63
|
if reference.first == :cell
|
39
|
-
ast.replace(offset_cell(reference, row_offset, column_offset, height, width))
|
64
|
+
ast.replace(offset_cell(reference, row_offset, column_offset, height, width, nil))
|
40
65
|
elsif reference.first == :sheet_reference && reference[2].first == :cell
|
41
|
-
ast.replace(
|
66
|
+
ast.replace(offset_cell(reference[2], row_offset, column_offset, height, width, reference[1]))
|
67
|
+
else
|
68
|
+
p "OFFSET reference is #{reference} from #{ast}, so not replacing"
|
42
69
|
end
|
43
70
|
end
|
44
71
|
|
45
|
-
def offset_cell(reference, row_offset, column_offset, height, width)
|
72
|
+
def offset_cell(reference, row_offset, column_offset, height, width, sheet)
|
46
73
|
|
47
74
|
reference = reference[1]
|
48
75
|
row_offset = row_offset[1].to_i
|
@@ -57,9 +84,14 @@ class ReplaceOffsetsWithReferencesAst
|
|
57
84
|
start_reference = reference.offset(row_offset.to_i, column_offset.to_i)
|
58
85
|
end_reference = reference.offset(row_offset.to_i + height.to_i - 1, column_offset.to_i + width.to_i - 1)
|
59
86
|
if start_reference == end_reference
|
60
|
-
|
87
|
+
if sheet
|
88
|
+
return [:sheet_reference, sheet, [:cell, start_reference]]
|
89
|
+
else
|
90
|
+
return [:cell, start_reference]
|
91
|
+
end
|
61
92
|
else
|
62
|
-
|
93
|
+
area = Area.for("#{start_reference}:#{end_reference}")
|
94
|
+
return area.to_array_literal(sheet)
|
63
95
|
end
|
64
96
|
end
|
65
97
|
|
data/src/util.rb
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
require_relative "util/not_supported_exception"
|
2
|
-
require_relative "util/try"
|
1
|
+
require_relative "util/not_supported_exception"
|
data/src/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: excel_to_code
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Counsell, Green on Black Ltd
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubypeg
|
@@ -174,9 +174,6 @@ files:
|
|
174
174
|
- src/commands/excel_to_x.rb
|
175
175
|
- src/compile.rb
|
176
176
|
- src/compile/c.rb
|
177
|
-
- src/compile/c/a.out
|
178
|
-
- src/compile/c/a.out.dSYM/Contents/Info.plist
|
179
|
-
- src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out
|
180
177
|
- src/compile/c/compile_named_reference_setters.rb
|
181
178
|
- src/compile/c/compile_to_c.rb
|
182
179
|
- src/compile/c/compile_to_c_header.rb
|
@@ -254,6 +251,7 @@ files:
|
|
254
251
|
- src/excel/excel_functions/mod.rb
|
255
252
|
- src/excel/excel_functions/more_than.rb
|
256
253
|
- src/excel/excel_functions/more_than_or_equal.rb
|
254
|
+
- src/excel/excel_functions/mround.rb
|
257
255
|
- src/excel/excel_functions/multiply.rb
|
258
256
|
- src/excel/excel_functions/na.rb
|
259
257
|
- src/excel/excel_functions/negative.rb
|
@@ -347,13 +345,12 @@ files:
|
|
347
345
|
- src/simplify/wrap_formulae_that_return_arrays_and_are_not_in_arrays.rb
|
348
346
|
- src/util.rb
|
349
347
|
- src/util/not_supported_exception.rb
|
350
|
-
- src/util/try.rb
|
351
348
|
- src/version.rb
|
352
349
|
homepage: http://github.com/tamc/excel_to_code
|
353
350
|
licenses:
|
354
351
|
- MIT
|
355
352
|
metadata: {}
|
356
|
-
post_install_message:
|
353
|
+
post_install_message:
|
357
354
|
rdoc_options: []
|
358
355
|
require_paths:
|
359
356
|
- src
|
@@ -364,13 +361,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
364
361
|
version: 2.3.0
|
365
362
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
366
363
|
requirements:
|
367
|
-
- - "
|
364
|
+
- - ">="
|
368
365
|
- !ruby/object:Gem::Version
|
369
|
-
version:
|
366
|
+
version: '0'
|
370
367
|
requirements: []
|
371
|
-
|
372
|
-
|
373
|
-
signing_key:
|
368
|
+
rubygems_version: 3.2.22
|
369
|
+
signing_key:
|
374
370
|
specification_version: 4
|
375
371
|
summary: Convert many .xlsx and .xlsm files into equivalent Ruby or C code that can
|
376
372
|
be executed without Excel
|
data/src/compile/c/a.out
DELETED
Binary file
|
@@ -1,20 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
-
<plist version="1.0">
|
4
|
-
<dict>
|
5
|
-
<key>CFBundleDevelopmentRegion</key>
|
6
|
-
<string>English</string>
|
7
|
-
<key>CFBundleIdentifier</key>
|
8
|
-
<string>com.apple.xcode.dsym.a.out</string>
|
9
|
-
<key>CFBundleInfoDictionaryVersion</key>
|
10
|
-
<string>6.0</string>
|
11
|
-
<key>CFBundlePackageType</key>
|
12
|
-
<string>dSYM</string>
|
13
|
-
<key>CFBundleSignature</key>
|
14
|
-
<string>????</string>
|
15
|
-
<key>CFBundleShortVersionString</key>
|
16
|
-
<string>1.0</string>
|
17
|
-
<key>CFBundleVersion</key>
|
18
|
-
<string>1</string>
|
19
|
-
</dict>
|
20
|
-
</plist>
|
Binary file
|