excel_to_code 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/README +41 -0
  2. data/bin/excel_to_c +63 -0
  3. data/bin/excel_to_ruby +9 -0
  4. data/src/commands.rb +2 -0
  5. data/src/commands/excel_to_c.rb +858 -0
  6. data/src/commands/excel_to_ruby.rb +620 -0
  7. data/src/compile.rb +2 -0
  8. data/src/compile/c.rb +5 -0
  9. data/src/compile/c/compile_to_c.rb +62 -0
  10. data/src/compile/c/compile_to_c_header.rb +26 -0
  11. data/src/compile/c/compile_to_c_unit_test.rb +42 -0
  12. data/src/compile/c/excel_to_c_runtime.c +2029 -0
  13. data/src/compile/c/map_formulae_to_c.rb +184 -0
  14. data/src/compile/c/map_sheet_names_to_c_names.rb +19 -0
  15. data/src/compile/c/map_values_to_c.rb +85 -0
  16. data/src/compile/c/map_values_to_c_structs.rb +37 -0
  17. data/src/compile/ruby.rb +3 -0
  18. data/src/compile/ruby/compile_to_ruby.rb +33 -0
  19. data/src/compile/ruby/compile_to_ruby_unit_test.rb +28 -0
  20. data/src/compile/ruby/excel_to_ruby_runtime.rb +1 -0
  21. data/src/compile/ruby/map_formulae_to_ruby.rb +95 -0
  22. data/src/compile/ruby/map_sheet_names_to_ruby_names.rb +19 -0
  23. data/src/compile/ruby/map_values_to_ruby.rb +65 -0
  24. data/src/excel.rb +5 -0
  25. data/src/excel/area.rb +93 -0
  26. data/src/excel/excel_functions.rb +84 -0
  27. data/src/excel/excel_functions/abs.rb +14 -0
  28. data/src/excel/excel_functions/add.rb +18 -0
  29. data/src/excel/excel_functions/and.rb +30 -0
  30. data/src/excel/excel_functions/apply_to_range.rb +17 -0
  31. data/src/excel/excel_functions/average.rb +12 -0
  32. data/src/excel/excel_functions/choose.rb +18 -0
  33. data/src/excel/excel_functions/cosh.rb +9 -0
  34. data/src/excel/excel_functions/count.rb +9 -0
  35. data/src/excel/excel_functions/counta.rb +8 -0
  36. data/src/excel/excel_functions/divide.rb +23 -0
  37. data/src/excel/excel_functions/excel_equal.rb +20 -0
  38. data/src/excel/excel_functions/excel_if.rb +8 -0
  39. data/src/excel/excel_functions/excel_match.rb +51 -0
  40. data/src/excel/excel_functions/find.rb +39 -0
  41. data/src/excel/excel_functions/iferror.rb +10 -0
  42. data/src/excel/excel_functions/index.rb +48 -0
  43. data/src/excel/excel_functions/left.rb +12 -0
  44. data/src/excel/excel_functions/less_than.rb +26 -0
  45. data/src/excel/excel_functions/less_than_or_equal.rb +26 -0
  46. data/src/excel/excel_functions/max.rb +12 -0
  47. data/src/excel/excel_functions/min.rb +12 -0
  48. data/src/excel/excel_functions/mod.rb +15 -0
  49. data/src/excel/excel_functions/more_than.rb +26 -0
  50. data/src/excel/excel_functions/more_than_or_equal.rb +26 -0
  51. data/src/excel/excel_functions/multiply.rb +24 -0
  52. data/src/excel/excel_functions/negative.rb +12 -0
  53. data/src/excel/excel_functions/not_equal.rb +19 -0
  54. data/src/excel/excel_functions/number_argument.rb +30 -0
  55. data/src/excel/excel_functions/pi.rb +7 -0
  56. data/src/excel/excel_functions/pmt.rb +16 -0
  57. data/src/excel/excel_functions/power.rb +18 -0
  58. data/src/excel/excel_functions/round.rb +13 -0
  59. data/src/excel/excel_functions/rounddown.rb +14 -0
  60. data/src/excel/excel_functions/roundup.rb +17 -0
  61. data/src/excel/excel_functions/string_join.rb +19 -0
  62. data/src/excel/excel_functions/subtotal.rb +13 -0
  63. data/src/excel/excel_functions/subtract.rb +18 -0
  64. data/src/excel/excel_functions/sum.rb +8 -0
  65. data/src/excel/excel_functions/sumif.rb +7 -0
  66. data/src/excel/excel_functions/sumifs.rb +74 -0
  67. data/src/excel/excel_functions/sumproduct.rb +32 -0
  68. data/src/excel/excel_functions/vlookup.rb +49 -0
  69. data/src/excel/formula_peg.rb +238 -0
  70. data/src/excel/formula_peg.txt +45 -0
  71. data/src/excel/reference.rb +56 -0
  72. data/src/excel/table.rb +108 -0
  73. data/src/excel_to_code.rb +7 -0
  74. data/src/extract.rb +13 -0
  75. data/src/extract/check_for_unknown_functions.rb +20 -0
  76. data/src/extract/extract_array_formulae.rb +23 -0
  77. data/src/extract/extract_formulae.rb +36 -0
  78. data/src/extract/extract_named_references.rb +38 -0
  79. data/src/extract/extract_relationships.rb +10 -0
  80. data/src/extract/extract_shared_formulae.rb +23 -0
  81. data/src/extract/extract_shared_strings.rb +20 -0
  82. data/src/extract/extract_simple_formulae.rb +18 -0
  83. data/src/extract/extract_table.rb +24 -0
  84. data/src/extract/extract_values.rb +29 -0
  85. data/src/extract/extract_worksheet_dimensions.rb +11 -0
  86. data/src/extract/extract_worksheet_names.rb +10 -0
  87. data/src/extract/extract_worksheet_table_relationships.rb +10 -0
  88. data/src/extract/simple_extract_from_xml.rb +19 -0
  89. data/src/rewrite.rb +10 -0
  90. data/src/rewrite/ast_copy_formula.rb +42 -0
  91. data/src/rewrite/ast_expand_array_formulae.rb +180 -0
  92. data/src/rewrite/rewrite_array_formulae.rb +71 -0
  93. data/src/rewrite/rewrite_array_formulae_to_arrays.rb +18 -0
  94. data/src/rewrite/rewrite_cell_references_to_include_sheet.rb +56 -0
  95. data/src/rewrite/rewrite_formulae_to_ast.rb +24 -0
  96. data/src/rewrite/rewrite_merge_formulae_and_values.rb +18 -0
  97. data/src/rewrite/rewrite_relationship_id_to_filename.rb +22 -0
  98. data/src/rewrite/rewrite_shared_formulae.rb +38 -0
  99. data/src/rewrite/rewrite_values_to_ast.rb +28 -0
  100. data/src/rewrite/rewrite_whole_row_column_references_to_areas.rb +90 -0
  101. data/src/rewrite/rewrite_worksheet_names.rb +20 -0
  102. data/src/simplify.rb +16 -0
  103. data/src/simplify/count_formula_references.rb +58 -0
  104. data/src/simplify/identify_dependencies.rb +56 -0
  105. data/src/simplify/identify_repeated_formula_elements.rb +37 -0
  106. data/src/simplify/inline_formulae.rb +77 -0
  107. data/src/simplify/map_formulae_to_values.rb +157 -0
  108. data/src/simplify/remove_cells.rb +18 -0
  109. data/src/simplify/replace_arrays_with_single_cells.rb +27 -0
  110. data/src/simplify/replace_blanks.rb +58 -0
  111. data/src/simplify/replace_common_elements_in_formulae.rb +19 -0
  112. data/src/simplify/replace_formulae_with_calculated_values.rb +21 -0
  113. data/src/simplify/replace_indirects_with_references.rb +44 -0
  114. data/src/simplify/replace_named_references.rb +82 -0
  115. data/src/simplify/replace_ranges_with_array_literals.rb +54 -0
  116. data/src/simplify/replace_shared_strings.rb +49 -0
  117. data/src/simplify/replace_table_references.rb +71 -0
  118. data/src/simplify/replace_values_with_constants.rb +47 -0
  119. data/src/simplify/simplify_arithmetic.rb +54 -0
  120. data/src/util.rb +2 -0
  121. data/src/util/not_supported_exception.rb +2 -0
  122. data/src/util/try.rb +9 -0
  123. metadata +207 -0
@@ -0,0 +1,184 @@
1
+ require_relative 'map_values_to_c'
2
+
3
+ class MapFormulaeToC < MapValuesToC
4
+
5
+ attr_accessor :sheet_names
6
+ attr_accessor :worksheet
7
+ attr_reader :initializers
8
+ attr_reader :counter
9
+
10
+ def initialize
11
+ reset
12
+ end
13
+
14
+ def reset
15
+ @initializers = []
16
+ @counter = 0
17
+ end
18
+
19
+ FUNCTIONS = {
20
+ '*' => 'multiply',
21
+ '+' => 'add',
22
+ '-' => 'subtract',
23
+ '/' => 'divide',
24
+ '<' => 'less_than',
25
+ '<=' => 'less_than_or_equal',
26
+ '<>' => 'not_equal',
27
+ '=' => 'excel_equal',
28
+ '>' => 'more_than',
29
+ '>=' => 'more_than_or_equal',
30
+ 'ABS' => 'excel_abs',
31
+ 'AND' => 'excel_and',
32
+ 'AVERAGE' => 'average',
33
+ 'CHOOSE' => 'choose',
34
+ 'COSH' => 'cosh',
35
+ 'COUNT' => 'count',
36
+ 'COUNTA' => 'counta',
37
+ 'FIND2' => 'find_2',
38
+ 'FIND3' => 'find',
39
+ 'IF2' => 'excel_if_2',
40
+ 'IF3' => 'excel_if',
41
+ 'IFERROR' => 'iferror',
42
+ 'INDEX2' => 'excel_index_2',
43
+ 'INDEX3' => 'excel_index',
44
+ 'LEFT1' => 'left_1',
45
+ 'LEFT2' => 'left',
46
+ 'MATCH2' => 'excel_match_2',
47
+ 'MATCH3' => 'excel_match',
48
+ 'MAX' => 'max',
49
+ 'MIN' => 'min',
50
+ 'MOD' => 'mod',
51
+ 'PMT' => 'pmt',
52
+ 'ROUND' => 'excel_round',
53
+ 'ROUNDDOWN' => 'rounddown',
54
+ 'ROUNDUP' => 'roundup',
55
+ 'string_join' => 'string_join',
56
+ 'SUBTOTAL' => 'subtotal',
57
+ 'SUM' => 'sum',
58
+ 'SUMIF2' => 'sumif_2',
59
+ 'SUMIF3' => 'sumif',
60
+ 'SUMIFS' => 'sumifs',
61
+ 'SUMPRODUCT' => 'sumproduct',
62
+ 'VLOOKUP3' => 'vlookup_3',
63
+ 'VLOOKUP4' => 'vlookup',
64
+ '^' => 'power'
65
+ }
66
+
67
+ def prefix(symbol,ast)
68
+ return map(ast) if symbol == "+"
69
+ return "negative(#{map(ast)})"
70
+ end
71
+
72
+ def brackets(*contents)
73
+ "(#{contents.map { |a| map(a) }.join(',')})"
74
+ end
75
+
76
+ def arithmetic(left,operator,right)
77
+ "#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
78
+ end
79
+
80
+ def string_join(*strings)
81
+ any_number_of_argument_function('string_join',strings)
82
+ end
83
+
84
+ def comparison(left,operator,right)
85
+ "#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
86
+ end
87
+
88
+ def function(function_name,*arguments)
89
+ # Some functions are special cases
90
+ if self.respond_to?("function_#{function_name.downcase}")
91
+ send("function_#{function_name.downcase}",*arguments)
92
+ # Some arguments can take any number of arguments, which we need to treat separately
93
+ elsif FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS.include?(function_name)
94
+ any_number_of_argument_function(function_name,arguments)
95
+
96
+ # Check for whether this function has variants based on the number of arguments
97
+ elsif FUNCTIONS.has_key?("#{function_name}#{arguments.size}")
98
+ "#{FUNCTIONS["#{function_name}#{arguments.size}"]}(#{arguments.map { |a| map(a) }.join(",")})"
99
+
100
+ # Then check for whether it is just a standard type
101
+ elsif FUNCTIONS.has_key?(function_name)
102
+ "#{FUNCTIONS[function_name]}(#{arguments.map { |a| map(a) }.join(",")})"
103
+
104
+ else
105
+ raise NotSupportedException.new("Function #{function_name} with #{arguments.size} arguments not supported")
106
+ end
107
+ end
108
+
109
+ FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS = %w{SUM AND AVERAGE COUNT COUNTA MAX MIN SUMPRODUCT}
110
+
111
+ def function_pi()
112
+ "M_PI"
113
+ end
114
+
115
+ def function_choose(index,*arguments)
116
+ "#{FUNCTIONS["CHOOSE"]}(#{map(index)}, #{map_arguments_to_array(arguments)})"
117
+ end
118
+
119
+ def function_subtotal(type,*arguments)
120
+ "#{FUNCTIONS["SUBTOTAL"]}(#{map(type)}, #{map_arguments_to_array(arguments)})"
121
+ end
122
+
123
+ def function_sumifs(sum_range,*criteria)
124
+ "#{FUNCTIONS["SUMIFS"]}(#{map(sum_range)}, #{map_arguments_to_array(criteria)})"
125
+ end
126
+
127
+
128
+ def any_number_of_argument_function(function_name,arguments)
129
+ "#{FUNCTIONS[function_name]}(#{map_arguments_to_array(arguments)})"
130
+ end
131
+
132
+ def map_arguments_to_array(arguments)
133
+ # First we have to create an excel array
134
+ array_name = "array#{@counter}"
135
+ @counter +=1
136
+ arguments_size = arguments.size
137
+ arguments = arguments.map { |a| map(a) }.join(',')
138
+ initializers << "ExcelValue #{array_name}[] = {#{arguments}};"
139
+ "#{arguments_size}, #{array_name}"
140
+ end
141
+
142
+ def cell(reference)
143
+ # FIXME: What a cludge.
144
+ if reference =~ /common\d+/
145
+ "_#{reference}()"
146
+ else
147
+ reference.downcase.gsub('$','')
148
+ end
149
+ end
150
+
151
+ def sheet_reference(sheet,reference)
152
+ "#{sheet_names[sheet]}_#{map(reference).downcase}()"
153
+ end
154
+
155
+ def array(*rows)
156
+ # Make sure we get the right dimensions
157
+ number_of_rows = rows.size
158
+ number_of_columns = rows.max { |r| r.size }.size - 1
159
+
160
+ # First we have to create an excel array
161
+ array_name = "array#{@counter}"
162
+ @counter +=1
163
+
164
+ cells = rows.map do |r|
165
+ r.shift if r.first == :row
166
+ r.map do |c|
167
+ map(c)
168
+ end
169
+ end.flatten
170
+
171
+ initializers << "static ExcelValue #{array_name}[#{cells.size}];"
172
+ cells.each_with_index do |c,i|
173
+ initializers << "#{array_name}[#{i}] = #{c};"
174
+ end
175
+
176
+ # Then we need to assign it to an excel value
177
+ range_name = array_name+"_ev"
178
+ initializers << "ExcelValue #{range_name} = new_excel_range(#{array_name},#{number_of_rows},#{number_of_columns});"
179
+
180
+ range_name
181
+ end
182
+
183
+
184
+ end
@@ -0,0 +1,19 @@
1
+ class MapSheetNamesToCNames
2
+
3
+ def self.rewrite(*args)
4
+ self.new.rewrite(*args)
5
+ end
6
+
7
+ def rewrite(input,output)
8
+ c_names_assigned = {}
9
+ input.lines do |line|
10
+ excel_worksheet_name = line.split("\t").first
11
+ c_name = excel_worksheet_name.downcase.gsub(/[^a-z0-9]+/,'_')
12
+ c_name = "s"+c_name if c_name[0] !~ /[a-z]/
13
+ c_name = ruby_name + "2" if c_names_assigned.has_key?(c_name)
14
+ c_name.succ! while c_names_assigned.has_key?(c_name)
15
+ output.puts "#{excel_worksheet_name}\t#{c_name}"
16
+ c_names_assigned[c_name] = excel_worksheet_name
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,85 @@
1
+ require_relative '../../util/not_supported_exception'
2
+
3
+ class MapValuesToC
4
+
5
+ def map(ast)
6
+ if ast.is_a?(Array)
7
+ operator = ast[0]
8
+ if respond_to?(operator)
9
+ send(operator,*ast[1..-1])
10
+ else
11
+ raise NotSupportedException.new("#{operator} in #{ast.inspect} not supported")
12
+ end
13
+ else
14
+ raise NotSupportedException.new("#{ast} not supported")
15
+ end
16
+ end
17
+
18
+ def blank
19
+ "BLANK"
20
+ end
21
+
22
+ def constant(name)
23
+ name
24
+ end
25
+
26
+ alias :null :blank
27
+
28
+ def number(text)
29
+ n = case text
30
+ when /\./
31
+ text.to_f.to_s
32
+ when /e/i
33
+ text.to_f.to_s
34
+ else
35
+ text.to_i.to_s
36
+ end
37
+
38
+ case n
39
+ when 0; "ZERO"
40
+ when 1; "ONE"
41
+ when 2; "TWO"
42
+ when 3; "THREE"
43
+ when 4; "FOUR"
44
+ when 5; "FIVE"
45
+ when 6; "SIX"
46
+ when 7; "SEVEN"
47
+ when 8; "EIGHT"
48
+ when 9; "NINE"
49
+ when 10; "TEN"
50
+ else
51
+ "new_excel_number(#{n})"
52
+ end
53
+ end
54
+
55
+ def percentage(text)
56
+ "new_excel_number(#{(text.to_f / 100.0).to_s})"
57
+ end
58
+
59
+ def string(text)
60
+ "new_excel_string(#{text.inspect})"
61
+ end
62
+
63
+ ERRORS = {
64
+ "#NAME?" => "NAME",
65
+ "#VALUE!" => "VALUE",
66
+ "#DIV/0!" => "DIV0",
67
+ "#REF!" => "REF",
68
+ "#N/A" => "NA"
69
+ }
70
+
71
+ REVERSE_ERRORS = ERRORS.invert
72
+
73
+ def error(text)
74
+ ERRORS[text] || (raise NotSupportedException.new("#{text.inspect} error not recognised"))
75
+ end
76
+
77
+ def boolean_true
78
+ "TRUE"
79
+ end
80
+
81
+ def boolean_false
82
+ "FALSE"
83
+ end
84
+
85
+ end
@@ -0,0 +1,37 @@
1
+ require_relative '../../util/not_supported_exception'
2
+
3
+ class MapValuesToCStructs
4
+
5
+ def map(ast)
6
+ if ast.is_a?(Array)
7
+ operator = ast[0]
8
+ if respond_to?(operator)
9
+ send(operator,*ast[1..-1])
10
+ else
11
+ raise NotSupportedException.new("#{operator} in #{ast.inspect} not supported")
12
+ end
13
+ else
14
+ raise NotSupportedException.new("#{ast} not supported")
15
+ end
16
+ end
17
+
18
+ def number(text)
19
+ n = case text
20
+ when /\./
21
+ text.to_f.to_s
22
+ when /e/i
23
+ text.to_f.to_s
24
+ else
25
+ text.to_i.to_s
26
+ end
27
+ "{.type = ExcelNumber, .number = #{n}}"
28
+ end
29
+
30
+ def percentage(text)
31
+ "{.type = ExcelNumber, .number = #{(text.to_f / 100.0).to_s}}"
32
+ end
33
+
34
+ def string(text)
35
+ "{.type = ExcelString, .string = #{text.inspect}}"
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ require_relative 'ruby/compile_to_ruby'
2
+ require_relative 'ruby/compile_to_ruby_unit_test'
3
+ require_relative 'ruby/map_sheet_names_to_ruby_names'
@@ -0,0 +1,33 @@
1
+ require_relative 'map_formulae_to_ruby'
2
+
3
+ class CompileToRuby
4
+
5
+ attr_accessor :settable
6
+ attr_accessor :worksheet
7
+
8
+ def self.rewrite(*args)
9
+ self.new.rewrite(*args)
10
+ end
11
+
12
+ def rewrite(input,sheet_names_file,output,defaults = nil)
13
+ self.settable ||= lambda { |ref| false }
14
+ mapper = MapFormulaeToRuby.new
15
+ mapper.worksheet = worksheet
16
+ mapper.sheet_names = Hash[sheet_names_file.readlines.map { |line| line.strip.split("\t")}]
17
+ input.lines do |line|
18
+ begin
19
+ ref, formula = line.split("\t")
20
+ if settable.call(ref)
21
+ output.puts " attr_accessor :#{ref.downcase} # Default: #{mapper.map(eval(formula))}"
22
+ defaults.puts " @#{ref.downcase} = #{mapper.map(eval(formula))}" if defaults
23
+ else
24
+ output.puts " def #{ref.downcase}; @#{ref.downcase} ||= #{mapper.map(eval(formula))}; end"
25
+ end
26
+ rescue Exception => e
27
+ puts "Exception at line #{line}"
28
+ raise
29
+ end
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,28 @@
1
+ require_relative "map_values_to_ruby"
2
+
3
+ class CompileToRubyUnitTest
4
+
5
+ def self.rewrite(*args)
6
+ self.new.rewrite(*args)
7
+ end
8
+
9
+ def rewrite(input,output)
10
+ mapper = MapValuesToRuby.new
11
+ input.lines do |line|
12
+ ref, formula = line.split("\t")
13
+ ast = eval(formula)
14
+ value = mapper.map(ast)
15
+ full_reference = "worksheet.#{ref.downcase}"
16
+ if ast.first == :number
17
+ if value == "0" # Need to do a slightly different test, because needs to pass if nil returned, as well as zero
18
+ output.puts " def test_#{ref.downcase}; assert_in_epsilon(#{value},#{full_reference} || 0); end"
19
+ else
20
+ output.puts " def test_#{ref.downcase}; assert_in_epsilon(#{value},#{full_reference}); end"
21
+ end
22
+ else
23
+ output.puts " def test_#{ref.downcase}; assert_equal(#{value},#{full_reference}); end"
24
+ end
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1 @@
1
+ require_relative '../../excel/excel_functions'
@@ -0,0 +1,95 @@
1
+ require_relative 'map_values_to_ruby'
2
+
3
+ class MapFormulaeToRuby < MapValuesToRuby
4
+
5
+ attr_accessor :sheet_names
6
+ attr_accessor :worksheet
7
+
8
+ FUNCTIONS = {
9
+ '*' => 'multiply',
10
+ '+' => 'add',
11
+ '-' => 'subtract',
12
+ '/' => 'divide',
13
+ '<' => 'less_than?',
14
+ '<=' => 'less_than_or_equal?',
15
+ '<>' => 'not_equal?',
16
+ '=' => 'excel_equal?',
17
+ '>' => 'more_than?',
18
+ '>=' => 'more_than_or_equal?',
19
+ 'ABS' => 'abs',
20
+ 'AND' => 'excel_and',
21
+ 'AVERAGE' => 'average',
22
+ 'CHOOSE' => 'choose',
23
+ 'COSH' => 'cosh',
24
+ 'COUNT' => 'count',
25
+ 'COUNTA' => 'counta',
26
+ 'FIND' => 'find',
27
+ 'IF' => 'excel_if',
28
+ 'IFERROR' => 'iferror',
29
+ 'INDEX' => 'index',
30
+ 'LEFT' => 'left',
31
+ 'MATCH' => 'excel_match',
32
+ 'MAX' => 'max',
33
+ 'MIN' => 'min',
34
+ 'MOD' => 'mod',
35
+ 'PI' => 'pi',
36
+ 'PMT' => 'pmt',
37
+ 'ROUND' => 'round',
38
+ 'ROUNDDOWN' => 'rounddown',
39
+ 'ROUNDUP' => 'roundup',
40
+ 'SUBTOTAL' => 'subtotal',
41
+ 'SUM' => 'sum',
42
+ 'SUMIF' => 'sumif',
43
+ 'SUMIFS' => 'sumifs',
44
+ 'SUMPRODUCT' => 'sumproduct',
45
+ 'VLOOKUP' => 'vlookup',
46
+ '^' => 'power'
47
+ }
48
+
49
+ def prefix(symbol,ast)
50
+ return map(ast) if symbol == "+"
51
+ return "negative(#{map(ast)})"
52
+ end
53
+
54
+ def brackets(*contents)
55
+ "(#{contents.map { |a| map(a) }.join(',')})"
56
+ end
57
+
58
+ def arithmetic(left,operator,right)
59
+ "#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
60
+ end
61
+
62
+ def string_join(*strings)
63
+ "string_join(#{strings.map {|a| map(a)}.join(',')})"
64
+ end
65
+
66
+ def comparison(left,operator,right)
67
+ "#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
68
+ end
69
+
70
+ def function(function_name,*arguments)
71
+ if FUNCTIONS.has_key?(function_name)
72
+ "#{FUNCTIONS[function_name]}(#{arguments.map { |a| map(a) }.join(",")})"
73
+ else
74
+ raise NotSupportedException.new("Function #{function_name} not supported")
75
+ end
76
+ end
77
+
78
+ def cell(reference)
79
+ reference.downcase.gsub('$','')
80
+ end
81
+
82
+ def sheet_reference(sheet,reference)
83
+ return map(reference) if worksheet && worksheet == sheet
84
+ "#{sheet_names[sheet]}.#{map(reference)}"
85
+ end
86
+
87
+ def array(*rows)
88
+ "[#{rows.map {|r| map(r)}.join(",")}]"
89
+ end
90
+
91
+ def row(*cells)
92
+ "[#{cells.map {|r| map(r)}.join(",")}]"
93
+ end
94
+
95
+ end