excel_to_code 0.1.20 → 0.1.21
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 +2 -1
- data/src/compile/c/a.out +0 -0
- data/src/compile/c/excel_to_c_runtime.c +18 -0
- 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/isnumber.rb +8 -0
- data/src/excel/formula_peg.rb +6 -2
- data/src/excel/formula_peg.txt +3 -2
- data/src/excel/table.rb +19 -1
- data/src/simplify.rb +1 -0
- data/src/simplify/replace_offsets_with_references.rb +27 -7
- data/src/simplify/replace_string_join_on_ranges.rb +75 -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: e4ebae76600b8d182956b7c1f6a0d98617cb7aeb
|
4
|
+
data.tar.gz: 07751fc9af519871db9f60f6011b8de21ee0e6f8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46b666e419461ce012bf8e2f84e2c6b97996943c4d41590c3260e10bbf3de827b4ca6e96caa10f99d16afa80785fea8c6179dc36b0e7f3c58b1a3886f1853daf
|
7
|
+
data.tar.gz: e694dff8476a31eea15131fadb9fa44ddf8d77839ce3ab5e525d40a4ba4307d97ebbfa485a4b9bb4847a05663cbe2970db576d92ab52d21c327904f4f6df97d4
|
data/src/commands/excel_to_x.rb
CHANGED
@@ -415,7 +415,7 @@ class ExcelToX
|
|
415
415
|
return @named_references if @named_references
|
416
416
|
@named_references = {}
|
417
417
|
i = input('Named references')
|
418
|
-
i.
|
418
|
+
i.each_line do |line|
|
419
419
|
sheet, name, ref = *line.split("\t")
|
420
420
|
key = sheet.size != 0 ? [sheet, name] : name
|
421
421
|
@named_references[key] = eval(ref)
|
@@ -616,6 +616,7 @@ class ExcelToX
|
|
616
616
|
# The result of the indirect might be a range, which we need to simplify
|
617
617
|
replace ReplaceRangesWithArrayLiterals, [name, 'Formulae'], [name, 'Formulae']
|
618
618
|
replace ReplaceArithmeticOnRanges, [name, 'Formulae'], [name, 'Formulae']
|
619
|
+
replace ReplaceStringJoinOnRanges, [name, 'Formulae'], [name, 'Formulae']
|
619
620
|
replace ReplaceArraysWithSingleCells, [name, 'Formulae'], [name, 'Formulae']
|
620
621
|
replace WrapFormulaeThatReturnArraysAndAReNotInArrays, [name, 'Formulae'], [name, 'Formulae']
|
621
622
|
end
|
data/src/compile/c/a.out
CHANGED
Binary file
|
@@ -60,6 +60,7 @@ static ExcelValue hlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, E
|
|
60
60
|
static ExcelValue iferror(ExcelValue value, ExcelValue value_if_error);
|
61
61
|
static ExcelValue excel_index(ExcelValue array_v, ExcelValue row_number_v, ExcelValue column_number_v);
|
62
62
|
static ExcelValue excel_index_2(ExcelValue array_v, ExcelValue row_number_v);
|
63
|
+
static ExcelValue excel_isnumber(ExcelValue number);
|
63
64
|
static ExcelValue large(ExcelValue array_v, ExcelValue k_v);
|
64
65
|
static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v);
|
65
66
|
static ExcelValue left_1(ExcelValue string_v);
|
@@ -503,6 +504,14 @@ static ExcelValue not_equal(ExcelValue a_v, ExcelValue b_v) {
|
|
503
504
|
return result;
|
504
505
|
}
|
505
506
|
|
507
|
+
static ExcelValue excel_isnumber(ExcelValue potential_number) {
|
508
|
+
if(potential_number.type == ExcelNumber) {
|
509
|
+
return TRUE;
|
510
|
+
} else {
|
511
|
+
return FALSE;
|
512
|
+
}
|
513
|
+
}
|
514
|
+
|
506
515
|
static ExcelValue excel_if(ExcelValue condition, ExcelValue true_case, ExcelValue false_case ) {
|
507
516
|
CHECK_FOR_PASSED_ERROR(condition)
|
508
517
|
|
@@ -2588,6 +2597,15 @@ int test_functions() {
|
|
2588
2597
|
assert(rank(THREE, rank_2_v, ZERO).type == ExcelError);
|
2589
2598
|
|
2590
2599
|
|
2600
|
+
// Test the ISNUMBER function
|
2601
|
+
assert(excel_isnumber(ONE).type == ExcelBoolean);
|
2602
|
+
assert(excel_isnumber(ONE).number == 1);
|
2603
|
+
assert(excel_isnumber(BLANK).type == ExcelBoolean);
|
2604
|
+
assert(excel_isnumber(BLANK).number == 0);
|
2605
|
+
assert(excel_isnumber(new_excel_string("Hello")).type == ExcelBoolean);
|
2606
|
+
assert(excel_isnumber(new_excel_string("Hello")).number == 0);
|
2607
|
+
assert(excel_isnumber(TRUE).type == ExcelBoolean);
|
2608
|
+
assert(excel_isnumber(TRUE).number == 0);
|
2591
2609
|
|
2592
2610
|
// Release memory
|
2593
2611
|
free_all_allocated_memory();
|
data/src/excel/formula_peg.rb
CHANGED
@@ -117,13 +117,13 @@ class Formula < RubyPeg
|
|
117
117
|
|
118
118
|
def table_reference
|
119
119
|
node :table_reference do
|
120
|
-
table_name && ignore { terminal("[") } && (range_structured_reference || complex_structured_reference || simple_structured_reference) && ignore { terminal("]") }
|
120
|
+
table_name && ignore { terminal("[") } && (range_structured_reference || short_range_structured_reference || complex_structured_reference || overly_structured_reference || simple_structured_reference) && ignore { terminal("]") }
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
124
|
def local_table_reference
|
125
125
|
node :local_table_reference do
|
126
|
-
ignore { terminal("[") } && (range_structured_reference || complex_structured_reference || overly_structured_reference || simple_structured_reference) && ignore { terminal("]") }
|
126
|
+
ignore { terminal("[") } && (range_structured_reference || short_range_structured_reference || complex_structured_reference || overly_structured_reference || simple_structured_reference) && ignore { terminal("]") }
|
127
127
|
end
|
128
128
|
end
|
129
129
|
|
@@ -135,6 +135,10 @@ class Formula < RubyPeg
|
|
135
135
|
terminal(/\[[^\u005d]*\],\[[^\u005d]*\]:\[[^\u005d]*\]/)
|
136
136
|
end
|
137
137
|
|
138
|
+
def short_range_structured_reference
|
139
|
+
terminal(/\[[^\u005d]*\]:\[[^\u005d]*\]/)
|
140
|
+
end
|
141
|
+
|
138
142
|
def complex_structured_reference
|
139
143
|
terminal(/\[[^\u005d]*\],\[[^\u005d]*\]/)
|
140
144
|
end
|
data/src/excel/formula_peg.txt
CHANGED
@@ -18,10 +18,11 @@ percentage := /[-+]?[0-9]+\.?[0-9]*/ `'%'
|
|
18
18
|
number := /[-+]?[0-9]+\.?[0-9]*([eE][-+]?[0-9]+)?/
|
19
19
|
operator := '+' | '-' | '/' | '*' | '^'
|
20
20
|
external_reference := /\[\d+\]!?/ any_internal_reference
|
21
|
-
table_reference := table_name `'[' (range_structured_reference | complex_structured_reference | simple_structured_reference) `']'
|
22
|
-
local_table_reference := `'[' (range_structured_reference | complex_structured_reference | overly_structured_reference | simple_structured_reference) `']'
|
21
|
+
table_reference := table_name `'[' (range_structured_reference | short_range_structured_reference | complex_structured_reference | overly_structured_reference | simple_structured_reference) `']'
|
22
|
+
local_table_reference := `'[' (range_structured_reference | short_range_structured_reference | complex_structured_reference | overly_structured_reference | simple_structured_reference) `']'
|
23
23
|
table_name = /[.\p{Word}_]+/
|
24
24
|
range_structured_reference = /\[[^\u005d]*\],\[[^\u005d]*\]:\[[^\u005d]*\]/
|
25
|
+
short_range_structured_reference = /\[[^\u005d]*\]:\[[^\u005d]*\]/
|
25
26
|
complex_structured_reference = /\[[^\u005d]*\],\[[^\u005d]*\]/
|
26
27
|
overly_structured_reference = `'[' simple_structured_reference `']'
|
27
28
|
simple_structured_reference = /[^\u005d]*/
|
data/src/excel/table.rb
CHANGED
@@ -14,17 +14,20 @@ class Table
|
|
14
14
|
|
15
15
|
def reference_for(table_name,structured_reference,calling_worksheet,calling_cell)
|
16
16
|
raise NotSupportedException.new("Local table reference not supported in #{structured_reference.inspect}") unless table_name
|
17
|
+
|
17
18
|
case structured_reference
|
18
19
|
when /\[#Headers\],\[(.*?)\]:\[(.*?)\]/io
|
19
20
|
column_number_start = @column_name_array.find_index($1.strip.downcase)
|
20
21
|
column_number_finish = @column_name_array.find_index($2.strip.downcase)
|
21
22
|
return ref_error unless column_number_start && column_number_finish
|
22
23
|
ast_for_area @area.excel_start.offset(0,column_number_start), @area.excel_start.offset(0,column_number_finish)
|
24
|
+
|
23
25
|
when /\[#Totals\],\[(.*?)\]:\[(.*?)\]/io
|
24
26
|
column_number_start = @column_name_array.find_index($1.strip.downcase)
|
25
27
|
column_number_finish = @column_name_array.find_index($2.strip.downcase)
|
26
28
|
return ref_error unless column_number_start && column_number_finish
|
27
29
|
ast_for_area @area.excel_start.offset(@area.height,column_number_start), @area.excel_start.offset(@area.height,column_number_finish)
|
30
|
+
|
28
31
|
when /\[#This Row\],\[(.*?)\]:\[(.*?)\]/io
|
29
32
|
r = Reference.for(calling_cell)
|
30
33
|
r.calculate_excel_variables
|
@@ -32,15 +35,24 @@ class Table
|
|
32
35
|
column_number_start = @column_name_array.find_index($1.strip.downcase)
|
33
36
|
column_number_finish = @column_name_array.find_index($2.strip.downcase)
|
34
37
|
return ref_error unless column_number_start && column_number_finish
|
35
|
-
ast_for_area @area.excel_start.offset(row - @area.excel_start.excel_row_number,column_number_start), @area.excel_start.offset(row - @area.excel_start.excel_row_number,column_number_finish)
|
38
|
+
ast_for_area @area.excel_start.offset(row - @area.excel_start.excel_row_number,column_number_start), @area.excel_start.offset(row - @area.excel_start.excel_row_number,column_number_finish)
|
39
|
+
|
40
|
+
when /\[(.*?)\]:\[(.*?)\]/io
|
41
|
+
column_number_start = @column_name_array.find_index($1.strip.downcase)
|
42
|
+
column_number_finish = @column_name_array.find_index($2.strip.downcase)
|
43
|
+
return ref_error unless column_number_start && column_number_finish
|
44
|
+
ast_for_area @area.excel_start.offset(1,column_number_start), @area.excel_start.offset(@area.height - @number_of_total_rows,column_number_finish)
|
45
|
+
|
36
46
|
when /\[#Headers\],\[(.*?)\]/io
|
37
47
|
column_number = @column_name_array.find_index($1.strip.downcase)
|
38
48
|
return ref_error unless column_number
|
39
49
|
ast_for_cell @area.excel_start.offset(0,column_number)
|
50
|
+
|
40
51
|
when /\[#Totals\],\[(.*?)\]/io
|
41
52
|
column_number = @column_name_array.find_index($1.strip.downcase)
|
42
53
|
return ref_error unless column_number
|
43
54
|
ast_for_cell @area.excel_start.offset(@area.height,column_number)
|
55
|
+
|
44
56
|
when /\[#This Row\],\[(.*?)\]/io
|
45
57
|
r = Reference.for(calling_cell)
|
46
58
|
r.calculate_excel_variables
|
@@ -48,6 +60,7 @@ class Table
|
|
48
60
|
column_number = @column_name_array.find_index($1.strip.downcase)
|
49
61
|
return ref_error unless column_number
|
50
62
|
ast_for_cell @area.excel_start.offset(row - @area.excel_start.excel_row_number,column_number)
|
63
|
+
|
51
64
|
when /#Headers/io
|
52
65
|
if calling_worksheet == @worksheet && @data_area.includes?(calling_cell)
|
53
66
|
r = Reference.for(calling_cell)
|
@@ -56,6 +69,7 @@ class Table
|
|
56
69
|
else
|
57
70
|
ast_for_area @area.excel_start.offset(0,0), @area.excel_start.offset(0,@area.width)
|
58
71
|
end
|
72
|
+
|
59
73
|
when /#Totals/io
|
60
74
|
if calling_worksheet == @worksheet && @data_area.includes?(calling_cell)
|
61
75
|
r = Reference.for(calling_cell)
|
@@ -64,15 +78,19 @@ class Table
|
|
64
78
|
else
|
65
79
|
ast_for_area @area.excel_start.offset(@area.height,0), @area.excel_start.offset(@area.height,@area.width)
|
66
80
|
end
|
81
|
+
|
67
82
|
when /#Data/io, ""
|
68
83
|
ast_for_area @data_area.excel_start, @data_area.excel_finish
|
84
|
+
|
69
85
|
when /#All/io, ""
|
70
86
|
ast_for_area @area.excel_start, @area.excel_finish
|
87
|
+
|
71
88
|
when /#This Row/io
|
72
89
|
r = Reference.for(calling_cell)
|
73
90
|
r.calculate_excel_variables
|
74
91
|
row = r.excel_row_number
|
75
92
|
ast_for_area "#{@area.excel_start.excel_column}#{row}", "#{@area.excel_finish.excel_column}#{row}"
|
93
|
+
|
76
94
|
else
|
77
95
|
if calling_worksheet == @worksheet && @data_area.includes?(calling_cell)
|
78
96
|
r = Reference.for(calling_cell)
|
data/src/simplify.rb
CHANGED
@@ -18,3 +18,4 @@ require_relative "simplify/replace_values_with_constants"
|
|
18
18
|
require_relative "simplify/sort_into_calculation_order"
|
19
19
|
require_relative "simplify/replace_arithmetic_on_ranges"
|
20
20
|
require_relative "simplify/wrap_formulae_that_return_arrays_and_are_not_in_arrays"
|
21
|
+
require_relative "simplify/replace_string_join_on_ranges"
|
@@ -17,19 +17,39 @@ class ReplaceOffsetsWithReferencesAst
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def function(name,*args)
|
20
|
-
if name == "OFFSET"
|
21
|
-
|
22
|
-
elsif name == "OFFSET" && args.size == 3 && args[0][0] == :cell && args[1][0] == :number && args[2][0] == :number
|
23
|
-
replace_offset(args[0][1], args[1][1], args[2][1])
|
20
|
+
if name == "OFFSET"
|
21
|
+
try_to_replace_offset(*args)
|
24
22
|
else
|
25
|
-
puts "offset in #{[:function,name,*args.map { |a| map(a) }].inspect} not replaced" if name == "INDIRECT"
|
26
23
|
[:function,name,*args.map { |a| map(a) }]
|
27
24
|
end
|
28
25
|
end
|
29
26
|
|
30
|
-
def
|
27
|
+
def try_to_replace_offset(reference, row_offset, column_offset, height = [:number, 1], width = [:number, 1])
|
28
|
+
if [row_offset, column_offset, height, width].all? { |a| a.first == :number }
|
29
|
+
if reference.first == :cell
|
30
|
+
offset_cell(reference, row_offset, column_offset, height, width)
|
31
|
+
elsif reference.first == :sheet_reference && reference[2].first == :cell
|
32
|
+
[:sheet_reference, reference[1], offset_cell(reference[2], row_offset, column_offset, height, width)]
|
33
|
+
else
|
34
|
+
puts "#{[:function, "OFFSET", reference, row_offset, column_offset, height, width]} not replaced"
|
35
|
+
[:function, "OFFSET", reference, row_offset, column_offset, height, width]
|
36
|
+
end
|
37
|
+
else
|
38
|
+
puts "#{[:function, "OFFSET", reference, row_offset, column_offset, height, width]} not replaced"
|
39
|
+
[:function, "OFFSET", reference, row_offset, column_offset, height, width]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def offset_cell(reference, row_offset, column_offset, height, width)
|
44
|
+
|
45
|
+
reference = reference[1]
|
46
|
+
row_offset = row_offset[1].to_i
|
47
|
+
column_offset = column_offset[1].to_i
|
48
|
+
height = height[1].to_i
|
49
|
+
width = width[1].to_i
|
50
|
+
|
31
51
|
@replacements_made_in_the_last_pass += 1
|
32
|
-
reference = Reference.for(reference.gsub
|
52
|
+
reference = Reference.for(reference.gsub("$",""))
|
33
53
|
start_reference = reference.offset(row_offset.to_i, column_offset.to_i)
|
34
54
|
end_reference = reference.offset(row_offset.to_i + height.to_i - 1, column_offset.to_i + width.to_i - 1)
|
35
55
|
if start_reference == end_reference
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class ReplaceStringJoinOnRangesAST
|
2
|
+
|
3
|
+
def map(ast)
|
4
|
+
return ast unless ast.is_a?(Array)
|
5
|
+
operator = ast[0]
|
6
|
+
if respond_to?(operator)
|
7
|
+
send(operator,*ast[1..-1])
|
8
|
+
else
|
9
|
+
[operator,*ast[1..-1].map {|a| map(a) }]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def string_join(*strings)
|
14
|
+
# Make sure there is actually a conversion to do
|
15
|
+
return [:string_join, *strings] unless strings.any? { |s| s.first == :array }
|
16
|
+
# Now work out the largest dimensions
|
17
|
+
# Arrays look like this [:array, [:row, 1, 2, 3], [:row, 4, 5, 6]]
|
18
|
+
max_rows = 0
|
19
|
+
max_columns = 0
|
20
|
+
strings.each do |s|
|
21
|
+
next unless s.first == :array
|
22
|
+
r = s.length - 1 # -1 beause first element is :array
|
23
|
+
c = r > 0 ? s[1].length - 1 : 0 # check if rows, if there are, columns is length of that array -1 for initial :row symbol
|
24
|
+
max_columns = c if c > max_columns
|
25
|
+
max_rows = r if r > max_rows
|
26
|
+
end
|
27
|
+
|
28
|
+
result = [:array]
|
29
|
+
(0...max_rows).each do |row_index|
|
30
|
+
row = [:row]
|
31
|
+
(0...max_columns).each do |column_index|
|
32
|
+
column = [:string_join]
|
33
|
+
strings.each do |string|
|
34
|
+
column << select_from(string, row_index, column_index)
|
35
|
+
end
|
36
|
+
row << column
|
37
|
+
end
|
38
|
+
result << row
|
39
|
+
end
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
43
|
+
def select_from(maybe_array, row_index, column_index)
|
44
|
+
return map(maybe_array) unless maybe_array.first == :array
|
45
|
+
row = maybe_array[row_index+1]
|
46
|
+
return [:error, "#VALUE!"] unless row
|
47
|
+
cell = row[column_index+1]
|
48
|
+
return [:error, "#VALUE!"] unless cell
|
49
|
+
map(cell)
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class ReplaceStringJoinOnRanges
|
57
|
+
|
58
|
+
def self.replace(*args)
|
59
|
+
self.new.replace(*args)
|
60
|
+
end
|
61
|
+
|
62
|
+
def replace(input,output)
|
63
|
+
rewriter = ReplaceStringJoinOnRangesAST.new
|
64
|
+
input.each_line do |line|
|
65
|
+
# Looks to match lines with references
|
66
|
+
if line =~ /:string_join/ && line =~ /:array/
|
67
|
+
content = line.split("\t")
|
68
|
+
ast = eval(content.pop)
|
69
|
+
output.puts "#{content.join("\t")}\t#{rewriter.map(ast).inspect}"
|
70
|
+
else
|
71
|
+
output.puts line
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
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.1.
|
4
|
+
version: 0.1.21
|
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: 2013-
|
11
|
+
date: 2013-11-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubypeg
|
@@ -137,6 +137,7 @@ files:
|
|
137
137
|
- src/excel/excel_functions/iferror.rb
|
138
138
|
- src/excel/excel_functions/index.rb
|
139
139
|
- src/excel/excel_functions/int.rb
|
140
|
+
- src/excel/excel_functions/isnumber.rb
|
140
141
|
- src/excel/excel_functions/large.rb
|
141
142
|
- src/excel/excel_functions/left.rb
|
142
143
|
- src/excel/excel_functions/less_than.rb
|
@@ -224,6 +225,7 @@ files:
|
|
224
225
|
- src/simplify/replace_offsets_with_references.rb
|
225
226
|
- src/simplify/replace_ranges_with_array_literals.rb
|
226
227
|
- src/simplify/replace_shared_strings.rb
|
228
|
+
- src/simplify/replace_string_join_on_ranges.rb
|
227
229
|
- src/simplify/replace_table_references.rb
|
228
230
|
- src/simplify/replace_values_with_constants.rb
|
229
231
|
- src/simplify/simplify_arithmetic.rb
|