excel_to_code 0.2.17 → 0.2.18
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 +3 -0
- data/src/compile/c/a.out +0 -0
- data/src/compile/c/excel_to_c_runtime.c +21 -1
- data/src/compile/c/excel_to_c_runtime_test.c +23 -4
- data/src/compile/c/map_formulae_to_c.rb +1 -0
- data/src/compile/ruby/map_formulae_to_ruby.rb +1 -0
- data/src/excel/excel_functions.rb +2 -0
- data/src/excel/excel_functions/sumifs.rb +2 -2
- data/src/excel/excel_functions/value.rb +7 -0
- data/src/excel/formula_peg.rb +1 -1
- data/src/excel/formula_peg.txt +1 -1
- data/src/excel_to_code.rb +1 -1
- data/src/rewrite/caching_formula_parser.rb +7 -1
- data/src/simplify.rb +1 -0
- data/src/simplify/inline_formulae.rb +10 -6
- data/src/simplify/replace_references_to_blanks_with_zeros.rb +43 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 337fc100f3818bf193414bcd8fb3aaec557e1a6b
|
4
|
+
data.tar.gz: 34218ff7c787a63a1e0081b688ff328d1235316e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10b5b04a5fe6ae0b5df092a010b5cbf0cad48025db71b99350da7a040e2992c5301c08f23652040b4eb340fcb2f064aa7bae7c02b765c53c8849e11480a66a71
|
7
|
+
data.tar.gz: 3ec3fbfbad7b341990559ae40d121dfdbd46839aa3f92f5a1b41b58ce597e43606d91de146bc940d5976b682320b593925bea0619463f9e183b98800f0b15a5c
|
data/src/commands/excel_to_x.rb
CHANGED
@@ -838,6 +838,7 @@ class ExcelToX
|
|
838
838
|
@replace_arrays_with_single_cells_replacer ||= ReplaceArraysWithSingleCellsAst.new
|
839
839
|
@replace_string_joins_on_ranges_replacer ||= ReplaceStringJoinOnRangesAST.new
|
840
840
|
@sheetless_cell_reference_replacer ||= RewriteCellReferencesToIncludeSheetAst.new
|
841
|
+
@replace_references_to_blanks_with_zeros ||= ReplaceReferencesToBlanksWithZeros.new(@formulae, nil, inline_ast_decision)
|
841
842
|
|
842
843
|
cells.each do |ref, ast|
|
843
844
|
begin
|
@@ -858,6 +859,8 @@ class ExcelToX
|
|
858
859
|
@replace_arithmetic_on_ranges_replacer.map(ast)
|
859
860
|
@replace_string_joins_on_ranges_replacer.map(ast)
|
860
861
|
@wrap_formulae_that_return_arrays_replacer.map(ast)
|
862
|
+
@replace_references_to_blanks_with_zeros.current_sheet_name = ref.first
|
863
|
+
@replace_references_to_blanks_with_zeros.map(ast)
|
861
864
|
rescue Exception => e
|
862
865
|
log.fatal "Exception when simplifying #{ref}: #{ast}"
|
863
866
|
raise
|
data/src/compile/c/a.out
CHANGED
Binary file
|
@@ -100,6 +100,7 @@ static ExcelValue sumif(ExcelValue check_range_v, ExcelValue criteria_v, ExcelVa
|
|
100
100
|
static ExcelValue sumif_2(ExcelValue check_range_v, ExcelValue criteria_v);
|
101
101
|
static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments);
|
102
102
|
static ExcelValue text(ExcelValue number_v, ExcelValue format_v);
|
103
|
+
static ExcelValue value(ExcelValue string_v);
|
103
104
|
static ExcelValue vlookup_3(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v);
|
104
105
|
static ExcelValue vlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v, ExcelValue match_type_v);
|
105
106
|
|
@@ -1716,6 +1717,11 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1716
1717
|
value_to_be_checked = ((ExcelValue *) ((ExcelValue) criteria_range[i]).array)[j];
|
1717
1718
|
comparison = criteria[i];
|
1718
1719
|
comparator = comparison.comparator;
|
1720
|
+
|
1721
|
+
// For the purposes of comparison, treates a blank criteria as matching zeros.
|
1722
|
+
if(comparator.type == ExcelEmpty) {
|
1723
|
+
comparator = ZERO;
|
1724
|
+
}
|
1719
1725
|
|
1720
1726
|
switch(value_to_be_checked.type) {
|
1721
1727
|
case ExcelError: // Errors match only errors
|
@@ -1737,7 +1743,6 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1737
1743
|
if(strlen(comparator.string) != 0) passed = 0; // Empty strings match blanks.
|
1738
1744
|
break;
|
1739
1745
|
}
|
1740
|
-
break;
|
1741
1746
|
case ExcelNumber:
|
1742
1747
|
if(comparator.type == ExcelNumber) {
|
1743
1748
|
number = comparator.number;
|
@@ -1781,6 +1786,13 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
|
|
1781
1786
|
passed = 0;
|
1782
1787
|
break;
|
1783
1788
|
}
|
1789
|
+
|
1790
|
+
// Special case, empty strings don't match zeros here
|
1791
|
+
if(strlen(value_to_be_checked.string) == 0) {
|
1792
|
+
passed = 0;
|
1793
|
+
break;
|
1794
|
+
}
|
1795
|
+
|
1784
1796
|
number = number_from(value_to_be_checked);
|
1785
1797
|
if(conversion_error == 1) {
|
1786
1798
|
conversion_error = 0;
|
@@ -2080,3 +2092,11 @@ static ExcelValue hlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, E
|
|
2080
2092
|
}
|
2081
2093
|
return NA;
|
2082
2094
|
}
|
2095
|
+
|
2096
|
+
|
2097
|
+
static ExcelValue value(ExcelValue string_v) {
|
2098
|
+
CHECK_FOR_PASSED_ERROR(string_v)
|
2099
|
+
NUMBER(string_v, a)
|
2100
|
+
CHECK_FOR_CONVERSION_ERROR
|
2101
|
+
return new_excel_number(a);
|
2102
|
+
}
|
@@ -492,16 +492,25 @@ int test_functions() {
|
|
492
492
|
ExcelValue sumifs_array_10f[] = { sumifs_array_3_v, new_excel_string(">=3")};
|
493
493
|
assert(sumifs(sumifs_array_3_v,2, sumifs_array_10f).number == 17);
|
494
494
|
|
495
|
-
// ...
|
496
|
-
ExcelValue sumifs_array_11[] = { BLANK, new_excel_number(
|
495
|
+
// ... BLANK in check range should match empty strings, BLANK in criteria should match zero
|
496
|
+
ExcelValue sumifs_array_11[] = { BLANK, new_excel_number(0)};
|
497
497
|
assert(sumifs(new_excel_number(100),2,sumifs_array_11).number == 0);
|
498
498
|
|
499
|
-
ExcelValue
|
499
|
+
ExcelValue sumifs_array_11b[] = { BLANK, new_excel_string("")};
|
500
|
+
assert(sumifs(new_excel_number(100),2,sumifs_array_11b).number == 100);
|
501
|
+
|
502
|
+
ExcelValue sumifs_array_11c[] = { new_excel_string(""), BLANK};
|
503
|
+
assert(sumifs(new_excel_number(100),2,sumifs_array_11c).number == 0);
|
504
|
+
|
505
|
+
ExcelValue sumifs_array_12[] = {new_excel_number(0), BLANK};
|
500
506
|
assert(sumifs(new_excel_number(100),2,sumifs_array_12).number == 100);
|
501
507
|
|
502
508
|
ExcelValue sumifs_array_13[] = {BLANK, BLANK};
|
503
509
|
assert(sumifs(new_excel_number(100),2,sumifs_array_13).number == 0);
|
504
510
|
|
511
|
+
ExcelValue sumifs_array_14[] = {new_excel_number(10), BLANK};
|
512
|
+
assert(sumifs(new_excel_number(100),2,sumifs_array_14).number == 0);
|
513
|
+
|
505
514
|
// ... should return an error if range argument is an error
|
506
515
|
assert(sumifs(REF,2,sumifs_array_13).type == ExcelError);
|
507
516
|
|
@@ -817,7 +826,7 @@ int test_functions() {
|
|
817
826
|
ExcelValue averageifs_array_11[] = { BLANK, new_excel_number(20)};
|
818
827
|
assert(averageifs(new_excel_number(100),2,averageifs_array_11).type == ExcelError);
|
819
828
|
|
820
|
-
ExcelValue averageifs_array_12[] = {
|
829
|
+
ExcelValue averageifs_array_12[] = {new_excel_number(0), BLANK};
|
821
830
|
assert(averageifs(new_excel_number(100),2,averageifs_array_12).number == 100);
|
822
831
|
|
823
832
|
ExcelValue averageifs_array_13[] = {BLANK, BLANK};
|
@@ -881,6 +890,16 @@ int test_functions() {
|
|
881
890
|
assert(len(TRUE).number == 4);
|
882
891
|
assert(len(FALSE).number == 5);
|
883
892
|
|
893
|
+
|
894
|
+
// VALUE(something)
|
895
|
+
assert(value(BLANK).type == ExcelNumber);
|
896
|
+
assert(value(BLANK).number == 0);
|
897
|
+
assert(value(ONE).type == ExcelNumber);
|
898
|
+
assert(value(ONE).number == 1);
|
899
|
+
assert(value(new_excel_string("1")).type == ExcelNumber);
|
900
|
+
assert(value(new_excel_string("1")).number == 1);
|
901
|
+
assert(value(new_excel_string("A1A")).type == ExcelError);
|
902
|
+
|
884
903
|
// Release memory
|
885
904
|
free_all_allocated_memory();
|
886
905
|
|
@@ -31,10 +31,10 @@ module ExcelFunctions
|
|
31
31
|
|
32
32
|
0.step(criteria.length-1,2).each do |i|
|
33
33
|
check_range = criteria[i]
|
34
|
-
required_value = criteria[i+1]
|
34
|
+
required_value = criteria[i+1] || 0
|
35
35
|
return :value if index >= check_range.length
|
36
36
|
check_value = check_range[index]
|
37
|
-
|
37
|
+
|
38
38
|
pass = case check_value
|
39
39
|
when String
|
40
40
|
check_value.downcase == required_value.to_s.downcase
|
data/src/excel/formula_peg.rb
CHANGED
@@ -159,7 +159,7 @@ class Formula < RubyPeg
|
|
159
159
|
|
160
160
|
def sheet_reference
|
161
161
|
node :sheet_reference do
|
162
|
-
(single_quoted_string || terminal(/[\p{word}][\p{word}_.]+/)) && ignore { terminal("!") } && (sheetless_reference || named_reference)
|
162
|
+
(single_quoted_string || terminal(/[\p{word}][\p{word}_.]+/)) && ignore { terminal("!") } && (sheetless_reference || error || named_reference)
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
data/src/excel/formula_peg.txt
CHANGED
@@ -27,7 +27,7 @@ complex_structured_reference = /\[[^\u005d]*\],\[[^\u005d]*\]/
|
|
27
27
|
overly_structured_reference = `'[' simple_structured_reference `']'
|
28
28
|
simple_structured_reference = /[^\u005d]*/
|
29
29
|
named_reference := /[#\p{word}][\p{word}_.!]+/
|
30
|
-
sheet_reference := (single_quoted_string | /[\p{word}][\p{word}_.]+/) `'!' (sheetless_reference | named_reference)
|
30
|
+
sheet_reference := (single_quoted_string | /[\p{word}][\p{word}_.]+/) `'!' (sheetless_reference | error | named_reference)
|
31
31
|
single_quoted_string = `"'" /[^']*/ `"'"
|
32
32
|
sheetless_reference = column_range | row_range | area | cell
|
33
33
|
column_range := column `':' column
|
data/src/excel_to_code.rb
CHANGED
@@ -64,7 +64,13 @@ class CachingFormulaParser
|
|
64
64
|
def sheet_reference(ast)
|
65
65
|
ast[1] = ast[1].to_sym
|
66
66
|
ast[2] = map(ast[2])
|
67
|
-
|
67
|
+
# We do this to deal with Control!#REF! style rerferences
|
68
|
+
# that occasionally pop up in named references
|
69
|
+
if ast[2].first == :error
|
70
|
+
return ast[2]
|
71
|
+
else
|
72
|
+
@sheet_reference_cache[ast] ||= ast
|
73
|
+
end
|
68
74
|
end
|
69
75
|
|
70
76
|
def cell(ast)
|
data/src/simplify.rb
CHANGED
@@ -21,3 +21,4 @@ require_relative "simplify/wrap_formulae_that_return_arrays_and_are_not_in_array
|
|
21
21
|
require_relative "simplify/replace_string_join_on_ranges"
|
22
22
|
require_relative "simplify/emergency_array_formula_replace_indirect_bodge.rb"
|
23
23
|
require_relative "simplify/replace_transpose_function"
|
24
|
+
require_relative "simplify/replace_references_to_blanks_with_zeros"
|
@@ -2,8 +2,6 @@ module BlankCell; end
|
|
2
2
|
|
3
3
|
class InlineFormulaeAst
|
4
4
|
|
5
|
-
BLANK = [:inlined_blank]
|
6
|
-
|
7
5
|
attr_accessor :references, :current_sheet_name, :inline_ast
|
8
6
|
attr_accessor :count_replaced
|
9
7
|
|
@@ -48,10 +46,9 @@ class InlineFormulaeAst
|
|
48
46
|
ref = ast[2][1].to_s.upcase.gsub('$','').to_sym
|
49
47
|
# FIXME: Need to check if valid worksheet and return [:error, "#REF!"] if not
|
50
48
|
# Now check user preference on this
|
49
|
+
ast_to_inline = ast_to_inline(sheet, ref)
|
51
50
|
return unless inline_ast.call(sheet,ref, references)
|
52
51
|
@count_replaced += 1
|
53
|
-
ast_to_inline = references[[sheet, ref]]
|
54
|
-
return ast.replace(BLANK) unless ast_to_inline
|
55
52
|
current_sheet_name.push(sheet)
|
56
53
|
map(ast_to_inline)
|
57
54
|
current_sheet_name.pop
|
@@ -62,10 +59,9 @@ class InlineFormulaeAst
|
|
62
59
|
def cell(ast)
|
63
60
|
sheet = current_sheet_name.last
|
64
61
|
ref = ast[1].to_s.upcase.gsub('$', '').to_sym
|
62
|
+
ast_to_inline = ast_to_inline(sheet, ref)
|
65
63
|
if inline_ast.call(sheet, ref, references)
|
66
64
|
@count_replaced += 1
|
67
|
-
ast_to_inline = references[[sheet, ref]]
|
68
|
-
return ast.replace(BLANK) unless ast_to_inline
|
69
65
|
map(ast_to_inline)
|
70
66
|
ast.replace(ast_to_inline)
|
71
67
|
# FIXME: Check - is this right? does it work recursively enough?
|
@@ -73,6 +69,14 @@ class InlineFormulaeAst
|
|
73
69
|
ast.replace([:sheet_reference, sheet, ast.dup])
|
74
70
|
end
|
75
71
|
end
|
72
|
+
|
73
|
+
def ast_to_inline(sheet, ref)
|
74
|
+
ast_to_inline = references[[sheet, ref]]
|
75
|
+
return ast_to_inline if ast_to_inline
|
76
|
+
# Need to add a new blank cell and return ast for an inlined blank
|
77
|
+
references[[sheet, ref]] = [:blank]
|
78
|
+
[:inlined_blank]
|
79
|
+
end
|
76
80
|
|
77
81
|
end
|
78
82
|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class ReplaceReferencesToBlanksWithZeros
|
2
|
+
|
3
|
+
attr_accessor :references, :current_sheet_name, :inline_ast
|
4
|
+
attr_accessor :count_replaced
|
5
|
+
|
6
|
+
def initialize(references = nil, current_sheet_name = nil, inline_ast = nil)
|
7
|
+
@references, @current_sheet_name, @inline_ast = references, [current_sheet_name], inline_ast
|
8
|
+
@count_replaced = 0
|
9
|
+
@inline_ast ||= lambda { |sheet, ref, references| true } # Default is to always inline
|
10
|
+
end
|
11
|
+
|
12
|
+
def map(ast)
|
13
|
+
return ast unless ast.is_a?(Array)
|
14
|
+
|
15
|
+
sheet = nil
|
16
|
+
ref = nil
|
17
|
+
|
18
|
+
case ast.first
|
19
|
+
when :sheet_reference
|
20
|
+
return ast unless ast[2][0] == :cell
|
21
|
+
sheet = ast[1].to_sym
|
22
|
+
ref = ast[2][1].to_s.upcase.gsub('$','').to_sym
|
23
|
+
when :cell
|
24
|
+
sheet = current_sheet_name.last
|
25
|
+
ref = ast[1].to_s.upcase.gsub('$', '').to_sym
|
26
|
+
else
|
27
|
+
# We aren't interested
|
28
|
+
return ast
|
29
|
+
end
|
30
|
+
|
31
|
+
ast_to_inline = references[[sheet, ref]] || [:blank]
|
32
|
+
|
33
|
+
return ast unless ast_to_inline == [:blank]
|
34
|
+
|
35
|
+
if inline_ast.call(sheet, ref, references)
|
36
|
+
ast.replace([:number, 0])
|
37
|
+
else
|
38
|
+
reference = [:sheet_reference, sheet, [:cell, ref]]
|
39
|
+
ast.replace([:function, :IF, [:function, :ISBLANK, reference], [:number, 0], reference])
|
40
|
+
end
|
41
|
+
ast
|
42
|
+
end
|
43
|
+
end
|
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.2.
|
4
|
+
version: 0.2.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Counsell, Green on Black Ltd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-02
|
11
|
+
date: 2014-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubypeg
|
@@ -199,6 +199,7 @@ files:
|
|
199
199
|
- src/excel/excel_functions/sumproduct.rb
|
200
200
|
- src/excel/excel_functions/text.rb
|
201
201
|
- src/excel/excel_functions/trim.rb
|
202
|
+
- src/excel/excel_functions/value.rb
|
202
203
|
- src/excel/excel_functions/vlookup.rb
|
203
204
|
- src/excel/formula_peg.rb
|
204
205
|
- src/excel/formula_peg.txt
|
@@ -244,6 +245,7 @@ files:
|
|
244
245
|
- src/simplify/replace_named_references.rb
|
245
246
|
- src/simplify/replace_offsets_with_references.rb
|
246
247
|
- src/simplify/replace_ranges_with_array_literals.rb
|
248
|
+
- src/simplify/replace_references_to_blanks_with_zeros.rb
|
247
249
|
- src/simplify/replace_shared_strings.rb
|
248
250
|
- src/simplify/replace_string_join_on_ranges.rb
|
249
251
|
- src/simplify/replace_table_references.rb
|