excel_to_code 0.3.18.beta.1 → 0.3.20
Sign up to get free protection for your applications and to get access to all the features.
- 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
|