excel_to_code 0.1.8 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/TODO +0 -1
  3. data/src/commands/excel_to_c.rb +6 -5
  4. data/src/commands/excel_to_ruby.rb +2 -1
  5. data/src/commands/excel_to_x.rb +69 -37
  6. data/src/compile/c/a.out +0 -0
  7. data/src/compile/c/compile_named_reference_setters.rb +1 -1
  8. data/src/compile/c/compile_to_c.rb +1 -1
  9. data/src/compile/c/compile_to_c_header.rb +1 -1
  10. data/src/compile/c/excel_to_c_runtime.c +117 -1
  11. data/src/compile/c/map_formulae_to_c.rb +4 -0
  12. data/src/compile/c/map_sheet_names_to_c_names.rb +1 -1
  13. data/src/compile/c/map_values_to_c.rb +2 -1
  14. data/src/compile/ruby/compile_to_ruby.rb +2 -2
  15. data/src/compile/ruby/compile_to_ruby_unit_test.rb +1 -1
  16. data/src/compile/ruby/map_formulae_to_ruby.rb +5 -0
  17. data/src/compile/ruby/map_values_to_ruby.rb +2 -1
  18. data/src/excel/excel_functions.rb +10 -0
  19. data/src/excel/excel_functions/cell.rb +14 -0
  20. data/src/excel/excel_functions/mid.rb +20 -0
  21. data/src/excel/excel_functions/negative.rb +2 -0
  22. data/src/excel/excel_functions/pv.rb +37 -0
  23. data/src/excel/excel_functions/text.rb +25 -0
  24. data/src/excel/excel_functions/trim.rb +8 -0
  25. data/src/excel/table.rb +1 -0
  26. data/src/extract/check_for_unknown_functions.rb +1 -1
  27. data/src/rewrite/ast_expand_array_formulae.rb +4 -6
  28. data/src/rewrite/rewrite_array_formulae.rb +2 -2
  29. data/src/rewrite/rewrite_array_formulae_to_arrays.rb +1 -1
  30. data/src/rewrite/rewrite_cell_references_to_include_sheet.rb +1 -1
  31. data/src/rewrite/rewrite_formulae_to_ast.rb +1 -1
  32. data/src/rewrite/rewrite_merge_formulae_and_values.rb +2 -2
  33. data/src/rewrite/rewrite_named_reference_names.rb +1 -1
  34. data/src/rewrite/rewrite_relationship_id_to_filename.rb +1 -1
  35. data/src/rewrite/rewrite_shared_formulae.rb +2 -2
  36. data/src/rewrite/rewrite_values_to_ast.rb +1 -1
  37. data/src/rewrite/rewrite_whole_row_column_references_to_areas.rb +2 -2
  38. data/src/rewrite/rewrite_worksheet_names.rb +6 -3
  39. data/src/simplify.rb +2 -0
  40. data/src/simplify/inline_formulae.rb +18 -1
  41. data/src/simplify/map_formulae_to_values.rb +18 -6
  42. data/src/simplify/remove_cells.rb +1 -1
  43. data/src/simplify/replace_arrays_with_single_cells.rb +1 -1
  44. data/src/simplify/replace_column_with_column_number.rb +58 -0
  45. data/src/simplify/replace_common_elements_in_formulae.rb +1 -1
  46. data/src/simplify/replace_formulae_with_calculated_values.rb +7 -1
  47. data/src/simplify/replace_indirects_with_references.rb +16 -3
  48. data/src/simplify/replace_named_references.rb +1 -1
  49. data/src/simplify/replace_offsets_with_references.rb +66 -0
  50. data/src/simplify/replace_ranges_with_array_literals.rb +1 -1
  51. data/src/simplify/replace_shared_strings.rb +1 -1
  52. data/src/simplify/replace_table_references.rb +2 -2
  53. data/src/simplify/replace_values_with_constants.rb +1 -1
  54. data/src/simplify/simplify_arithmetic.rb +1 -1
  55. metadata +9 -2
@@ -4,13 +4,18 @@ require_relative '../util'
4
4
 
5
5
  class FormulaeCalculator
6
6
  include ExcelFunctions
7
+ attr_accessor :original_excel_filename
7
8
  end
8
9
 
9
10
  class MapFormulaeToValues
10
11
 
12
+ attr_accessor :original_excel_filename
13
+ attr_accessor :replacements_made_in_the_last_pass
14
+
11
15
  def initialize
12
16
  @value_for_ast = MapValuesToRuby.new
13
17
  @calculator = FormulaeCalculator.new
18
+ @replacements_made_in_the_last_pass = 0
14
19
  @cache = {}
15
20
  end
16
21
 
@@ -21,6 +26,7 @@ class MapFormulaeToValues
21
26
  # FIXME: Caching works in the odd edge cases of long formula
22
27
  # but I really need to find the root cause of the problem
23
28
  def map(ast)
29
+ @calculator.original_excel_filename = original_excel_filename
24
30
  @cache[ast] ||= do_map(ast)
25
31
  end
26
32
 
@@ -33,7 +39,7 @@ class MapFormulaeToValues
33
39
  [operator,*ast[1..-1].map {|a| map(a) }]
34
40
  end
35
41
  end
36
-
42
+
37
43
  def prefix(operator,argument)
38
44
  argument_value = value(map(argument))
39
45
  return [:prefix, operator, map(argument)] if argument_value == :not_a_value
@@ -52,7 +58,7 @@ class MapFormulaeToValues
52
58
  end
53
59
 
54
60
  alias :comparison :arithmetic
55
-
61
+
56
62
  def percentage(number)
57
63
  ast_for_value(value([:percentage, number]))
58
64
  end
@@ -82,6 +88,12 @@ class MapFormulaeToValues
82
88
  end
83
89
  end
84
90
  end
91
+
92
+ def map_count(range)
93
+ return [:function, "COUNT", range] unless [:array, :cell, :sheet_reference].include?(range.first)
94
+ range = array_as_values(range)
95
+ ast_for_value(range.size * range.first.size)
96
+ end
85
97
 
86
98
  def map_index(array,row_number,column_number = :not_specified)
87
99
  return map_index_with_only_two_arguments(array,row_number) if column_number == :not_specified
@@ -96,7 +108,7 @@ class MapFormulaeToValues
96
108
  return [:function, "INDEX", array_mapped, map(row_number), map(column_number)] unless array_as_values
97
109
 
98
110
  result = @calculator.send(MapFormulaeToRuby::FUNCTIONS["INDEX"],array_as_values,row_as_number,column_as_number)
99
- result = ast_for_value(result) unless result.is_a?(Array)
111
+ result = ast_for_value(result)
100
112
  result
101
113
  end
102
114
 
@@ -107,7 +119,7 @@ class MapFormulaeToValues
107
119
  array_as_values = array_as_values(array)
108
120
  return [:function, "INDEX", array_mapped, map(row_number)] unless array_as_values
109
121
  result = @calculator.send(MapFormulaeToRuby::FUNCTIONS["INDEX"],array_as_values,row_as_number)
110
- result = ast_for_value(result) unless result.is_a?(Array)
122
+ result = ast_for_value(result)
111
123
  result
112
124
  end
113
125
 
@@ -125,8 +137,6 @@ class MapFormulaeToValues
125
137
  nil
126
138
  end
127
139
  end
128
-
129
-
130
140
 
131
141
  def value(ast)
132
142
  return extract_values_from_array(ast) if ast.first == :array
@@ -150,6 +160,8 @@ class MapFormulaeToValues
150
160
  end
151
161
 
152
162
  def ast_for_value(value)
163
+ return value if value.is_a?(Array) && value.first.is_a?(Symbol)
164
+ @replacements_made_in_the_last_pass += 1
153
165
  case value
154
166
  when Numeric; [:number,value.inspect]
155
167
  when true; [:boolean_true]
@@ -8,7 +8,7 @@ class RemoveCells
8
8
  end
9
9
 
10
10
  def rewrite(input,output)
11
- input.lines do |line|
11
+ input.each_line do |line|
12
12
  ref = line[/^(.*?)\t/,1]
13
13
  if cells_to_keep.has_key?(ref)
14
14
  output.puts line
@@ -8,7 +8,7 @@ class ReplaceArraysWithSingleCells
8
8
 
9
9
  def replace(input,output)
10
10
 
11
- input.lines do |line|
11
+ input.each_line do |line|
12
12
  # Looks to match shared string lines
13
13
  if line =~ /\[:array/
14
14
  content = line.split("\t")
@@ -0,0 +1,58 @@
1
+ class ReplaceColumnWithColumnNumberAST
2
+
3
+ attr_accessor :replacements_made_in_the_last_pass
4
+
5
+ def initialize
6
+ @replacements_made_in_the_last_pass = 0
7
+ end
8
+
9
+ def map(ast)
10
+ return ast unless ast.is_a?(Array)
11
+ operator = ast[0]
12
+ if respond_to?(operator)
13
+ send(operator,*ast[1..-1])
14
+ else
15
+ [operator,*ast[1..-1].map {|a| map(a) }]
16
+ end
17
+ end
18
+
19
+ def function(name,*args)
20
+ if name == "COLUMN" && args.size == 1 && [:cell, :sheet_reference].include?(args[0][0])
21
+ if args[0][0] == :cell
22
+ reference = Reference.for(args[0][1])
23
+ elsif args[0][0] == :sheet_reference
24
+ reference = Reference.for(args[0][2][1])
25
+ end
26
+ reference.calculate_excel_variables
27
+ @replacements_made_in_the_last_pass += 1
28
+ [:number, reference.excel_column_number.to_s]
29
+ else
30
+ [:function,name,*args.map { |a| map(a) }]
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+
37
+ class ReplaceColumnWithColumnNumber
38
+
39
+ def self.replace(*args)
40
+ self.new.replace(*args)
41
+ end
42
+
43
+ attr_accessor :replacements_made_in_the_last_pass
44
+
45
+ def replace(input,output)
46
+ rewriter = ReplaceColumnWithColumnNumberAST.new
47
+ input.each_line do |line|
48
+ # Looks to match lines with references
49
+ if line =~ /"COLUMN"/
50
+ ref, ast = line.split("\t")
51
+ output.puts "#{ref}\t#{rewriter.map(eval(ast)).inspect}"
52
+ else
53
+ output.puts line
54
+ end
55
+ end
56
+ @replacements_made_in_the_last_pass = rewriter.replacements_made_in_the_last_pass
57
+ end
58
+ end
@@ -12,7 +12,7 @@ class ReplaceCommonElementsInFormulae
12
12
  ref, element = a.split("\t")
13
13
  @common_elements[element.strip] = [:cell, ref]
14
14
  end
15
- input.lines do |line|
15
+ input.each_line do |line|
16
16
  ref, formula = line.split("\t")
17
17
  output.puts "#{ref}\t#{replace_repeated_formulae(eval(formula)).inspect}"
18
18
  end
@@ -2,13 +2,18 @@ require_relative 'map_formulae_to_values'
2
2
 
3
3
  class ReplaceFormulaeWithCalculatedValues
4
4
 
5
+ attr_accessor :excel_file
6
+
5
7
  def self.replace(*args)
6
8
  self.new.replace(*args)
7
9
  end
10
+
11
+ attr_accessor :replacements_made_in_the_last_pass
8
12
 
9
13
  def replace(input,output)
10
14
  rewriter = MapFormulaeToValues.new
11
- input.lines do |line|
15
+ rewriter.original_excel_filename = excel_file
16
+ input.each_line do |line|
12
17
  begin
13
18
  ref, ast = line.split("\t")
14
19
  output.puts "#{ref}\t#{rewriter.map(eval(ast)).inspect}"
@@ -18,5 +23,6 @@ class ReplaceFormulaeWithCalculatedValues
18
23
  raise
19
24
  end
20
25
  end
26
+ @replacements_made_in_the_last_pass = rewriter.replacements_made_in_the_last_pass
21
27
  end
22
28
  end
@@ -1,7 +1,13 @@
1
1
  require_relative '../excel/formula_peg'
2
2
 
3
3
  class ReplaceIndirectsWithReferencesAst
4
-
4
+
5
+ attr_accessor :replacements_made_in_the_last_pass
6
+
7
+ def initialize
8
+ @replacements_made_in_the_last_pass = 0
9
+ end
10
+
5
11
  def map(ast)
6
12
  return ast unless ast.is_a?(Array)
7
13
  operator = ast[0]
@@ -13,8 +19,12 @@ class ReplaceIndirectsWithReferencesAst
13
19
  end
14
20
 
15
21
  def function(name,*args)
16
- if name == "INDIRECT" && args.size == 1 && args[0][0] == :string
22
+ if name == "INDIRECT" && args[0][0] == :string
23
+ @replacements_made_in_the_last_pass += 1
17
24
  Formula.parse(args[0][1]).to_ast[1]
25
+ elsif name == "INDIRECT" && args[0][0] == :error
26
+ @replacements_made_in_the_last_pass += 1
27
+ args[0]
18
28
  else
19
29
  puts "indirect #{[:function,name,*args.map { |a| map(a) }].inspect} not replaced" if name == "INDIRECT"
20
30
  [:function,name,*args.map { |a| map(a) }]
@@ -28,10 +38,12 @@ class ReplaceIndirectsWithReferences
28
38
  def self.replace(*args)
29
39
  self.new.replace(*args)
30
40
  end
41
+
42
+ attr_accessor :replacements_made_in_the_last_pass
31
43
 
32
44
  def replace(input,output)
33
45
  rewriter = ReplaceIndirectsWithReferencesAst.new
34
- input.lines do |line|
46
+ input.each_line do |line|
35
47
  # Looks to match lines with references
36
48
  if line =~ /"INDIRECT"/
37
49
  ref, ast = line.split("\t")
@@ -40,5 +52,6 @@ class ReplaceIndirectsWithReferences
40
52
  output.puts line
41
53
  end
42
54
  end
55
+ @replacements_made_in_the_last_pass = rewriter.replacements_made_in_the_last_pass
43
56
  end
44
57
  end
@@ -68,7 +68,7 @@ class ReplaceNamedReferences
68
68
  def replace(values,named_references,output)
69
69
  named_references = NamedReferences.new(named_references.readlines)
70
70
  rewriter = ReplaceNamedReferencesAst.new(named_references,sheet_name)
71
- values.lines do |line|
71
+ values.each_line do |line|
72
72
  # Looks to match shared string lines
73
73
  if line =~ /\[:named_reference/
74
74
  cols = line.split("\t")
@@ -0,0 +1,66 @@
1
+ class ReplaceOffsetsWithReferencesAst
2
+
3
+ attr_accessor :replacements_made_in_the_last_pass
4
+
5
+ def initialize
6
+ @replacements_made_in_the_last_pass = 0
7
+ end
8
+
9
+ def map(ast)
10
+ return ast unless ast.is_a?(Array)
11
+ operator = ast[0]
12
+ if respond_to?(operator)
13
+ send(operator,*ast[1..-1])
14
+ else
15
+ [operator,*ast[1..-1].map {|a| map(a) }]
16
+ end
17
+ end
18
+
19
+ def function(name,*args)
20
+ if name == "OFFSET" && args.size == 5 && args[0][0] == :cell && args[1][0] == :number && args[2][0] == :number && args[3][0] == :number && args[4][0] == :number
21
+ replace_offset(args[0][1], args[1][1], args[2][1], args[3][1], args[4][1])
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])
24
+ else
25
+ puts "offset in #{[:function,name,*args.map { |a| map(a) }].inspect} not replaced" if name == "INDIRECT"
26
+ [:function,name,*args.map { |a| map(a) }]
27
+ end
28
+ end
29
+
30
+ def replace_offset(reference, row_offset, column_offset, height = 1, width = 1)
31
+ @replacements_made_in_the_last_pass += 1
32
+ reference = Reference.for(reference.gsub!("$",""))
33
+ start_reference = reference.offset(row_offset.to_i, column_offset.to_i)
34
+ end_reference = reference.offset(row_offset.to_i + height.to_i - 1, column_offset.to_i + width.to_i - 1)
35
+ if start_reference == end_reference
36
+ [:cell, start_reference]
37
+ else
38
+ [:area, start_reference, end_reference]
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+
45
+ class ReplaceOffsetsWithReferences
46
+
47
+ def self.replace(*args)
48
+ self.new.replace(*args)
49
+ end
50
+
51
+ attr_accessor :replacements_made_in_the_last_pass
52
+
53
+ def replace(input,output)
54
+ rewriter = ReplaceOffsetsWithReferencesAst.new
55
+ input.each_line do |line|
56
+ # Looks to match lines with references
57
+ if line =~ /"OFFSET"/
58
+ ref, ast = line.split("\t")
59
+ output.puts "#{ref}\t#{rewriter.map(eval(ast)).inspect}"
60
+ else
61
+ output.puts line
62
+ end
63
+ end
64
+ @replacements_made_in_the_last_pass = rewriter.replacements_made_in_the_last_pass
65
+ end
66
+ end
@@ -39,7 +39,7 @@ class ReplaceRangesWithArrayLiterals
39
39
  def replace(input,output)
40
40
  rewriter = ReplaceRangesWithArrayLiteralsAst.new
41
41
 
42
- input.lines do |line|
42
+ input.each_line do |line|
43
43
  # Looks to match shared string lines
44
44
  if line =~ /\[:area/
45
45
  content = line.split("\t")
@@ -36,7 +36,7 @@ class ReplaceSharedStrings
36
36
  # Rewrites ast with shared strings to strings
37
37
  def replace(values,shared_strings,output)
38
38
  rewriter = ReplaceSharedStringAst.new(shared_strings.readlines)
39
- values.lines do |line|
39
+ values.each_line do |line|
40
40
  # Looks to match shared string lines
41
41
  if line =~ /\[:shared_string/
42
42
  ref, ast = line.split("\t")
@@ -49,7 +49,7 @@ class ReplaceTableReferences
49
49
 
50
50
  rewriter = ReplaceTableReferenceAst.new(tables,sheet_name)
51
51
 
52
- input.lines do |line|
52
+ input.each_line do |line|
53
53
  # Looks to match shared string lines
54
54
  begin
55
55
  if line =~ /\[(:table_reference|:local_table_reference)/
@@ -68,4 +68,4 @@ class ReplaceTableReferences
68
68
  end
69
69
  end
70
70
 
71
- end
71
+ end
@@ -33,7 +33,7 @@ class ReplaceValuesWithConstants
33
33
 
34
34
  def replace(input,output)
35
35
  @rewriter ||= MapValuesToConstants.new
36
- input.lines do |line|
36
+ input.each_line do |line|
37
37
  begin
38
38
  ref, ast = line.split("\t")
39
39
  output.puts "#{ref}\t#{rewriter.map(eval(ast)).inspect}"
@@ -40,7 +40,7 @@ class SimplifyArithmetic
40
40
 
41
41
  def replace(input,output)
42
42
  rewriter = SimplifyArithmeticAst.new
43
- input.lines do |line|
43
+ input.each_line do |line|
44
44
  # Looks to match lines with references
45
45
  if line =~ /:arithmetic/
46
46
  content = line.split("\t")
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.8
4
+ version: 0.1.10
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-06-05 00:00:00.000000000 Z
11
+ date: 2013-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubypeg
@@ -123,6 +123,7 @@ files:
123
123
  - src/excel/excel_functions/and.rb
124
124
  - src/excel/excel_functions/apply_to_range.rb
125
125
  - src/excel/excel_functions/average.rb
126
+ - src/excel/excel_functions/cell.rb
126
127
  - src/excel/excel_functions/choose.rb
127
128
  - src/excel/excel_functions/cosh.rb
128
129
  - src/excel/excel_functions/count.rb
@@ -140,6 +141,7 @@ files:
140
141
  - src/excel/excel_functions/less_than.rb
141
142
  - src/excel/excel_functions/less_than_or_equal.rb
142
143
  - src/excel/excel_functions/max.rb
144
+ - src/excel/excel_functions/mid.rb
143
145
  - src/excel/excel_functions/min.rb
144
146
  - src/excel/excel_functions/mod.rb
145
147
  - src/excel/excel_functions/more_than.rb
@@ -151,6 +153,7 @@ files:
151
153
  - src/excel/excel_functions/pi.rb
152
154
  - src/excel/excel_functions/pmt.rb
153
155
  - src/excel/excel_functions/power.rb
156
+ - src/excel/excel_functions/pv.rb
154
157
  - src/excel/excel_functions/round.rb
155
158
  - src/excel/excel_functions/rounddown.rb
156
159
  - src/excel/excel_functions/roundup.rb
@@ -161,6 +164,8 @@ files:
161
164
  - src/excel/excel_functions/sumif.rb
162
165
  - src/excel/excel_functions/sumifs.rb
163
166
  - src/excel/excel_functions/sumproduct.rb
167
+ - src/excel/excel_functions/text.rb
168
+ - src/excel/excel_functions/trim.rb
164
169
  - src/excel/excel_functions/vlookup.rb
165
170
  - src/excel/excel_functions.rb
166
171
  - src/excel/formula_peg.rb
@@ -206,10 +211,12 @@ files:
206
211
  - src/simplify/map_formulae_to_values.rb
207
212
  - src/simplify/remove_cells.rb
208
213
  - src/simplify/replace_arrays_with_single_cells.rb
214
+ - src/simplify/replace_column_with_column_number.rb
209
215
  - src/simplify/replace_common_elements_in_formulae.rb
210
216
  - src/simplify/replace_formulae_with_calculated_values.rb
211
217
  - src/simplify/replace_indirects_with_references.rb
212
218
  - src/simplify/replace_named_references.rb
219
+ - src/simplify/replace_offsets_with_references.rb
213
220
  - src/simplify/replace_ranges_with_array_literals.rb
214
221
  - src/simplify/replace_shared_strings.rb
215
222
  - src/simplify/replace_table_references.rb