excel_to_code 0.1.23 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/src/commands/excel_to_c.rb +39 -92
  3. data/src/commands/excel_to_ruby.rb +9 -35
  4. data/src/commands/excel_to_x.rb +515 -536
  5. data/src/compile/c/a.out +0 -0
  6. data/src/compile/c/compile_named_reference_setters.rb +4 -6
  7. data/src/compile/c/compile_to_c.rb +34 -21
  8. data/src/compile/c/compile_to_c_header.rb +7 -7
  9. data/src/compile/c/excel_to_c_runtime.c +8 -4
  10. data/src/compile/c/map_formulae_to_c.rb +85 -86
  11. data/src/compile/c/map_values_to_c.rb +7 -1
  12. data/src/compile/c/map_values_to_c_structs.rb +1 -1
  13. data/src/compile/ruby/compile_to_ruby.rb +14 -11
  14. data/src/compile/ruby/compile_to_ruby_unit_test.rb +17 -10
  15. data/src/compile/ruby/map_formulae_to_ruby.rb +56 -56
  16. data/src/compile/ruby/map_values_to_ruby.rb +14 -2
  17. data/src/excel/area.rb +6 -8
  18. data/src/excel/excel_functions/hlookup.rb +1 -1
  19. data/src/excel/excel_functions/vlookup.rb +1 -1
  20. data/src/excel/formula_peg.rb +1 -1
  21. data/src/excel/formula_peg.txt +1 -1
  22. data/src/excel/reference.rb +4 -3
  23. data/src/excel/table.rb +4 -4
  24. data/src/extract.rb +1 -0
  25. data/src/extract/check_for_unknown_functions.rb +2 -2
  26. data/src/extract/extract_array_formulae.rb +9 -9
  27. data/src/extract/extract_everything.rb +140 -0
  28. data/src/extract/extract_formulae.rb +30 -20
  29. data/src/extract/extract_named_references.rb +37 -22
  30. data/src/extract/extract_relationships.rb +16 -3
  31. data/src/extract/extract_shared_formulae.rb +8 -11
  32. data/src/extract/extract_shared_formulae_targets.rb +1 -6
  33. data/src/extract/extract_shared_strings.rb +21 -8
  34. data/src/extract/extract_simple_formulae.rb +11 -6
  35. data/src/extract/extract_table.rb +26 -13
  36. data/src/extract/extract_values.rb +35 -11
  37. data/src/extract/extract_worksheet_dimensions.rb +13 -3
  38. data/src/extract/extract_worksheet_names.rb +16 -3
  39. data/src/extract/extract_worksheet_table_relationships.rb +16 -4
  40. data/src/extract/simple_extract_from_xml.rb +9 -11
  41. data/src/rewrite.rb +3 -0
  42. data/src/rewrite/ast_copy_formula.rb +5 -1
  43. data/src/rewrite/ast_expand_array_formulae.rb +71 -59
  44. data/src/rewrite/caching_formula_parser.rb +110 -0
  45. data/src/rewrite/rewrite_array_formulae.rb +21 -14
  46. data/src/rewrite/rewrite_cell_references_to_include_sheet.rb +41 -13
  47. data/src/rewrite/rewrite_shared_formulae.rb +17 -18
  48. data/src/rewrite/rewrite_values_to_ast.rb +2 -0
  49. data/src/rewrite/rewrite_whole_row_column_references_to_areas.rb +28 -25
  50. data/src/simplify.rb +1 -0
  51. data/src/simplify/count_formula_references.rb +22 -23
  52. data/src/simplify/emergency_array_formula_replace_indirect_bodge.rb +44 -0
  53. data/src/simplify/identify_dependencies.rb +7 -8
  54. data/src/simplify/identify_repeated_formula_elements.rb +5 -6
  55. data/src/simplify/inline_formulae.rb +48 -48
  56. data/src/simplify/map_formulae_to_values.rb +197 -79
  57. data/src/simplify/remove_cells.rb +13 -6
  58. data/src/simplify/replace_arithmetic_on_ranges.rb +42 -28
  59. data/src/simplify/replace_arrays_with_single_cells.rb +11 -5
  60. data/src/simplify/replace_column_with_column_number.rb +31 -23
  61. data/src/simplify/replace_common_elements_in_formulae.rb +16 -17
  62. data/src/simplify/replace_indirects_with_references.rb +26 -21
  63. data/src/simplify/replace_named_references.rb +26 -31
  64. data/src/simplify/replace_offsets_with_references.rb +33 -34
  65. data/src/simplify/replace_ranges_with_array_literals.rb +48 -20
  66. data/src/simplify/replace_shared_strings.rb +15 -13
  67. data/src/simplify/replace_string_join_on_ranges.rb +7 -9
  68. data/src/simplify/replace_table_references.rb +16 -11
  69. data/src/simplify/replace_values_with_constants.rb +6 -4
  70. data/src/simplify/simplify_arithmetic.rb +33 -19
  71. data/src/simplify/sort_into_calculation_order.rb +13 -13
  72. data/src/simplify/wrap_formulae_that_return_arrays_and_are_not_in_arrays.rb +21 -13
  73. metadata +19 -2
data/src/compile/c/a.out CHANGED
Binary file
@@ -25,7 +25,7 @@ class MapNamedReferenceToCSetter
25
25
  end
26
26
 
27
27
  def cell(reference)
28
- reference.downcase.gsub('$','')
28
+ Reference.for(reference).unfix.downcase.to_s
29
29
  end
30
30
 
31
31
  def sheet_reference(sheet,reference)
@@ -56,7 +56,7 @@ class MapNamedReferenceToCSetter
56
56
  settable_refs = cells_that_can_be_set_at_runtime[sheet]
57
57
  return false unless settable_refs
58
58
  return true if settable_refs == :all
59
- settable_refs.include?(reference.upcase)
59
+ settable_refs.include?(reference.upcase.to_sym)
60
60
  end
61
61
 
62
62
  end
@@ -71,12 +71,10 @@ class CompileNamedReferenceSetters
71
71
 
72
72
  def rewrite(named_references, sheet_names, output)
73
73
  mapper = MapNamedReferenceToCSetter.new
74
- mapper.sheet_names = Hash[sheet_names.readlines.map { |line| line.strip.split("\t")}]
74
+ mapper.sheet_names = sheet_names
75
75
  mapper.cells_that_can_be_set_at_runtime = cells_that_can_be_set_at_runtime
76
76
 
77
- named_references.each_line do |line|
78
- name, reference = line.split("\t")
79
- ast = eval(reference)
77
+ named_references.each do |name, ast|
80
78
  output.puts "void set_#{name}(ExcelValue newValue) {"
81
79
  output.puts mapper.map(ast)
82
80
  output.puts "}"
@@ -4,28 +4,32 @@ class CompileToC
4
4
 
5
5
  attr_accessor :settable
6
6
  attr_accessor :gettable
7
- attr_accessor :worksheet
8
7
  attr_accessor :variable_set_counter
9
8
 
10
9
  def self.rewrite(*args)
11
10
  self.new.rewrite(*args)
12
11
  end
13
12
 
14
- def rewrite(input,sheet_names_file,output)
13
+ def rewrite(formulae, sheet_names, output)
15
14
  self.settable ||= lambda { |ref| false }
16
15
  self.gettable ||= lambda { |ref| true }
17
16
  @variable_set_counter ||= 0
17
+
18
18
  mapper = MapFormulaeToC.new
19
- mapper.worksheet = worksheet
20
- mapper.sheet_names = Hash[sheet_names_file.readlines.map { |line| line.strip.split("\t")}]
21
- c_name = mapper.sheet_names[worksheet] || worksheet
22
- input.each_line do |line|
19
+ mapper.sheet_names = sheet_names
20
+ formulae.each do |ref, ast|
23
21
  begin
24
- ref, formula = line.split("\t")
25
- ast = eval(formula)
22
+ worksheet = ref.first
23
+ cell = ref.last
24
+ mapper.worksheet = worksheet
25
+ worksheet_c_name = mapper.sheet_names[worksheet.to_s] || worksheet.to_s
26
26
  calculation = mapper.map(ast)
27
- name = c_name ? "#{c_name}_#{ref.downcase}" : ref.downcase
27
+ name = worksheet_c_name.length > 0 ? "#{worksheet_c_name}_#{cell.downcase}" : cell.downcase
28
+
29
+ # Declare function as static so it can be inlined where possible
28
30
  static_or_not = gettable.call(ref) ? "" : "static "
31
+
32
+ # Settable functions need a default value and then a function for getting and setting
29
33
  if settable.call(ref)
30
34
  output.puts "ExcelValue #{name}_default() {"
31
35
  mapper.initializers.each do |i|
@@ -34,25 +38,34 @@ class CompileToC
34
38
  output.puts " return #{calculation};"
35
39
  output.puts "}"
36
40
  output.puts "static ExcelValue #{name}_variable;"
37
- output.puts "ExcelValue #{name}() { if(variable_set[#{@variable_set_counter}] == 1) { return #{name}_variable; } else { return #{c_name}_#{ref.downcase}_default(); } }"
41
+ output.puts "ExcelValue #{name}() { if(variable_set[#{@variable_set_counter}] == 1) { return #{name}_variable; } else { return #{name}_default(); } }"
38
42
  output.puts "void set_#{name}(ExcelValue newValue) { variable_set[#{@variable_set_counter}] = 1; #{name}_variable = newValue; }"
43
+ output.puts
44
+ # Other functions just have a getter
39
45
  else
40
- output.puts "#{static_or_not}ExcelValue #{name}() {"
41
- output.puts " static ExcelValue result;"
42
- output.puts " if(variable_set[#{@variable_set_counter}] == 1) { return result;}"
43
- mapper.initializers.each do |i|
44
- output.puts " #{i}"
46
+ # In simple cases, don't bother memoizing the result
47
+ simple = (ast[0] == :constant) || (ast[0] == :cell && ast[1] =~ /common\d+/) || (ast[0] == :blank) || (ast[0] == :error)
48
+
49
+ if simple
50
+ output.puts "#{static_or_not}ExcelValue #{name}() { return #{calculation}; }"
51
+ else
52
+ output.puts "#{static_or_not}ExcelValue #{name}() {"
53
+ output.puts " static ExcelValue result;"
54
+ output.puts " if(variable_set[#{@variable_set_counter}] == 1) { return result;}"
55
+ mapper.initializers.each do |i|
56
+ output.puts " #{i}"
57
+ end
58
+ output.puts " result = #{calculation};"
59
+ output.puts " variable_set[#{@variable_set_counter}] = 1;"
60
+ output.puts " return result;"
61
+ output.puts "}"
62
+ output.puts
45
63
  end
46
- output.puts " result = #{calculation};"
47
- output.puts " variable_set[#{@variable_set_counter}] = 1;"
48
- output.puts " return result;"
49
- output.puts "}"
50
64
  end
51
- output.puts
52
65
  @variable_set_counter += 1
53
66
  mapper.reset
54
67
  rescue Exception => e
55
- puts "Exception at line #{line}"
68
+ puts "Exception at #{ref} #{ast}"
56
69
  raise
57
70
  end
58
71
  end
@@ -1,6 +1,5 @@
1
1
  class CompileToCHeader
2
2
 
3
- attr_accessor :worksheet
4
3
  attr_accessor :gettable
5
4
  attr_accessor :settable
6
5
 
@@ -8,17 +7,18 @@ class CompileToCHeader
8
7
  self.new.rewrite(*args)
9
8
  end
10
9
 
11
- def rewrite(input,sheet_names_file,output,defaults = nil)
12
- c_name = Hash[sheet_names_file.readlines.map { |line| line.strip.split("\t")}][worksheet]
10
+ def rewrite(formulae, c_name_for_worksheet_name, output)
13
11
  self.gettable ||= lambda { |ref| true }
14
12
  self.settable ||= lambda { |ref| false }
15
- input.each_line do |line|
13
+ formulae.each do |ref, ast|
16
14
  begin
17
- ref, formula = line.split("\t")
18
15
  static_or_not = (gettable.call(ref) || settable.call(ref)) ? "" : "static "
19
- output.puts "#{static_or_not}ExcelValue #{c_name}_#{ref.downcase}();"
16
+ worksheet = c_name_for_worksheet_name[ref.first.to_s] || ref.first.to_s
17
+ ref = ref.last.downcase
18
+ name = worksheet.length > 0 ? "#{worksheet}_#{ref}" : ref
19
+ output.puts "#{static_or_not}ExcelValue #{name}();"
20
20
  rescue Exception => e
21
- puts "Exception at line #{line}"
21
+ puts "Exception at #{ref} #{ast}"
22
22
  raise
23
23
  end
24
24
  end
@@ -755,7 +755,7 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
755
755
  }
756
756
 
757
757
  static ExcelValue excel_match_2(ExcelValue lookup_value, ExcelValue lookup_array ) {
758
- return excel_match(lookup_value,lookup_array,new_excel_number(0));
758
+ return excel_match(lookup_value, lookup_array, ZERO);
759
759
  }
760
760
 
761
761
  static ExcelValue find(ExcelValue find_text_v, ExcelValue within_text_v, ExcelValue start_number_v) {
@@ -843,12 +843,12 @@ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
843
843
  printf("Out of memory");
844
844
  exit(-1);
845
845
  }
846
- free_later(left_string);
847
846
  memcpy(left_string,string,number_of_characters);
848
847
  left_string[number_of_characters] = '\0';
849
848
  if(string_must_be_freed == 1) {
850
849
  free(string);
851
850
  }
851
+ free_later(left_string);
852
852
  return new_excel_string(left_string);
853
853
  }
854
854
 
@@ -1331,7 +1331,6 @@ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
1331
1331
  printf("Out of memory");
1332
1332
  exit(-1);
1333
1333
  }
1334
- free_later(string);
1335
1334
  char *current_string;
1336
1335
  int current_string_length;
1337
1336
  int must_free_current_string;
@@ -1381,6 +1380,7 @@ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
1381
1380
  }
1382
1381
  string = realloc(string,used_length+1);
1383
1382
  string[used_length] = '\0';
1383
+ free_later(string);
1384
1384
  return new_excel_string(string);
1385
1385
  }
1386
1386
 
@@ -1750,8 +1750,8 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
1750
1750
  if(strcmp(format_v.string,"0%") == 0) {
1751
1751
  // FIXME: Too little?
1752
1752
  s = malloc(100);
1753
- free_later(s);
1754
1753
  sprintf(s, "%d%%",(int) round(number_v.number*100));
1754
+ free_later(s);
1755
1755
  result = new_excel_string(s);
1756
1756
  } else {
1757
1757
  return format_v;
@@ -2283,6 +2283,10 @@ int test_functions() {
2283
2283
  assert(string_join(2, string_join_array_4).string[8] == '\0');
2284
2284
  // ... should convert TRUE and FALSE into strings
2285
2285
  assert(string_join(3,string_join_array_5).string[4] == 'T');
2286
+ // Should deal with very long string joins
2287
+ ExcelValue string_join_array_6[] = {new_excel_string("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"), new_excel_string("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")};
2288
+ assert(string_join(2, string_join_array_6).string[0] == '0');
2289
+ free_all_allocated_memory();
2286
2290
 
2287
2291
  // Test SUBTOTAL function
2288
2292
  ExcelValue subtotal_array_1[] = {new_excel_number(10),new_excel_number(100),BLANK};
@@ -17,67 +17,67 @@ class MapFormulaeToC < MapValuesToC
17
17
  end
18
18
 
19
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
- 'CONCATENATE' => 'string_join',
35
- 'COSH' => 'cosh',
36
- 'COUNT' => 'count',
37
- 'COUNTA' => 'counta',
38
- 'FIND2' => 'find_2',
39
- 'FIND3' => 'find',
40
- 'HLOOKUP3' => 'hlookup_3',
41
- 'HLOOKUP4' => 'hlookup',
42
- 'IF2' => 'excel_if_2',
43
- 'IF3' => 'excel_if',
44
- 'IFERROR' => 'iferror',
45
- 'INDEX2' => 'excel_index_2',
46
- 'INDEX3' => 'excel_index',
47
- 'INT' => 'excel_int',
48
- 'ISNUMBER' => 'excel_isnumber',
49
- 'LARGE' => 'large',
50
- 'LEFT1' => 'left_1',
51
- 'LEFT2' => 'left',
52
- 'LOG1' => 'excel_log',
53
- 'LOG2' => 'excel_log_2',
54
- 'MATCH2' => 'excel_match_2',
55
- 'MATCH3' => 'excel_match',
56
- 'MAX' => 'max',
57
- 'MIN' => 'min',
58
- 'MMULT' => 'mmult',
59
- 'MOD' => 'mod',
60
- 'PMT' => 'pmt',
61
- 'PV3' => 'pv_3',
62
- 'PV4' => 'pv_4',
63
- 'PV5' => 'pv_5',
64
- 'RANK2' => 'rank_2',
65
- 'RANK3' => 'rank',
66
- 'ROUND' => 'excel_round',
67
- 'ROUNDDOWN' => 'rounddown',
68
- 'ROUNDUP' => 'roundup',
69
- 'string_join' => 'string_join',
70
- 'SUBTOTAL' => 'subtotal',
71
- 'SUM' => 'sum',
72
- 'SUMIF2' => 'sumif_2',
73
- 'SUMIF3' => 'sumif',
74
- 'SUMIFS' => 'sumifs',
75
- 'TEXT2' => 'text',
76
- 'SUMPRODUCT' => 'sumproduct',
77
- 'VLOOKUP3' => 'vlookup_3',
78
- 'VLOOKUP4' => 'vlookup',
79
- '^' => 'power',
80
- 'POWER' => 'power'
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
+ :'CONCATENATE' => 'string_join',
35
+ :'COSH' => 'cosh',
36
+ :'COUNT' => 'count',
37
+ :'COUNTA' => 'counta',
38
+ :'FIND2' => 'find_2',
39
+ :'FIND3' => 'find',
40
+ :'HLOOKUP3' => 'hlookup_3',
41
+ :'HLOOKUP4' => 'hlookup',
42
+ :'IF2' => 'excel_if_2',
43
+ :'IF3' => 'excel_if',
44
+ :'IFERROR' => 'iferror',
45
+ :'INDEX2' => 'excel_index_2',
46
+ :'INDEX3' => 'excel_index',
47
+ :'INT' => 'excel_int',
48
+ :'ISNUMBER' => 'excel_isnumber',
49
+ :'LARGE' => 'large',
50
+ :'LEFT1' => 'left_1',
51
+ :'LEFT2' => 'left',
52
+ :'LOG1' => 'excel_log',
53
+ :'LOG2' => 'excel_log_2',
54
+ :'MATCH2' => 'excel_match_2',
55
+ :'MATCH3' => 'excel_match',
56
+ :'MAX' => 'max',
57
+ :'MIN' => 'min',
58
+ :'MMULT' => 'mmult',
59
+ :'MOD' => 'mod',
60
+ :'PMT' => 'pmt',
61
+ :'PV3' => 'pv_3',
62
+ :'PV4' => 'pv_4',
63
+ :'PV5' => 'pv_5',
64
+ :'RANK2' => 'rank_2',
65
+ :'RANK3' => 'rank',
66
+ :'ROUND' => 'excel_round',
67
+ :'ROUNDDOWN' => 'rounddown',
68
+ :'ROUNDUP' => 'roundup',
69
+ :'string_join' => 'string_join',
70
+ :'SUBTOTAL' => 'subtotal',
71
+ :'SUM' => 'sum',
72
+ :'SUMIF2' => 'sumif_2',
73
+ :'SUMIF3' => 'sumif',
74
+ :'SUMIFS' => 'sumifs',
75
+ :'TEXT2' => 'text',
76
+ :'SUMPRODUCT' => 'sumproduct',
77
+ :'VLOOKUP3' => 'vlookup_3',
78
+ :'VLOOKUP4' => 'vlookup',
79
+ :'^' => 'power',
80
+ :'POWER' => 'power'
81
81
  }
82
82
 
83
83
  def prefix(symbol,ast)
@@ -103,19 +103,19 @@ class MapFormulaeToC < MapValuesToC
103
103
 
104
104
  def function(function_name,*arguments)
105
105
  # Some functions are special cases
106
- if self.respond_to?("function_#{function_name.downcase}")
107
- send("function_#{function_name.downcase}",*arguments)
106
+ if self.respond_to?("function_#{function_name.to_s.downcase}")
107
+ send("function_#{function_name.to_s.downcase}",*arguments)
108
108
  # Some arguments can take any number of arguments, which we need to treat separately
109
- elsif FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS.include?(function_name)
109
+ elsif FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS.include?(function_name.to_s)
110
110
  any_number_of_argument_function(function_name,arguments)
111
111
 
112
112
  # Check for whether this function has variants based on the number of arguments
113
- elsif FUNCTIONS.has_key?("#{function_name}#{arguments.size}")
114
- "#{FUNCTIONS["#{function_name}#{arguments.size}"]}(#{arguments.map { |a| map(a) }.join(",")})"
113
+ elsif FUNCTIONS.has_key?("#{function_name.to_s}#{arguments.size}".to_sym)
114
+ "#{FUNCTIONS["#{function_name.to_s}#{arguments.size}".to_sym]}(#{arguments.map { |a| map(a) }.join(",")})"
115
115
 
116
116
  # Then check for whether it is just a standard type
117
- elsif FUNCTIONS.has_key?(function_name)
118
- "#{FUNCTIONS[function_name]}(#{arguments.map { |a| map(a) }.join(",")})"
117
+ elsif FUNCTIONS.has_key?(function_name.to_sym)
118
+ "#{FUNCTIONS[function_name.to_sym]}(#{arguments.map { |a| map(a) }.join(",")})"
119
119
 
120
120
  else
121
121
  raise NotSupportedException.new("Function #{function_name} with #{arguments.size} arguments not supported")
@@ -129,20 +129,20 @@ class MapFormulaeToC < MapValuesToC
129
129
  end
130
130
 
131
131
  def function_choose(index,*arguments)
132
- "#{FUNCTIONS["CHOOSE"]}(#{map(index)}, #{map_arguments_to_array(arguments)})"
132
+ "#{FUNCTIONS[:CHOOSE]}(#{map(index)}, #{map_arguments_to_array(arguments)})"
133
133
  end
134
134
 
135
135
  def function_subtotal(type,*arguments)
136
- "#{FUNCTIONS["SUBTOTAL"]}(#{map(type)}, #{map_arguments_to_array(arguments)})"
136
+ "#{FUNCTIONS[:SUBTOTAL]}(#{map(type)}, #{map_arguments_to_array(arguments)})"
137
137
  end
138
138
 
139
139
  def function_sumifs(sum_range,*criteria)
140
- "#{FUNCTIONS["SUMIFS"]}(#{map(sum_range)}, #{map_arguments_to_array(criteria)})"
140
+ "#{FUNCTIONS[:SUMIFS]}(#{map(sum_range)}, #{map_arguments_to_array(criteria)})"
141
141
  end
142
142
 
143
143
 
144
144
  def any_number_of_argument_function(function_name,arguments)
145
- "#{FUNCTIONS[function_name]}(#{map_arguments_to_array(arguments)})"
145
+ "#{FUNCTIONS[function_name.to_sym]}(#{map_arguments_to_array(arguments)})"
146
146
  end
147
147
 
148
148
  def map_arguments_to_array(arguments)
@@ -158,35 +158,34 @@ class MapFormulaeToC < MapValuesToC
158
158
  def cell(reference)
159
159
  # FIXME: What a cludge.
160
160
  if reference =~ /common\d+/
161
- "_#{reference}()"
161
+ "#{reference}()"
162
162
  else
163
- reference.downcase.gsub('$','')
163
+ reference.to_s.downcase.gsub('$','')
164
164
  end
165
165
  end
166
166
 
167
167
  def sheet_reference(sheet,reference)
168
- "#{sheet_names[sheet]}_#{map(reference).downcase}()"
168
+ "#{sheet_names[sheet]}_#{map(reference).to_s.downcase}()"
169
169
  end
170
170
 
171
171
  def array(*rows)
172
172
  # Make sure we get the right dimensions
173
173
  number_of_rows = rows.size
174
- number_of_columns = rows.max { |r| r.size }.size - 1
175
-
174
+ number_of_columns = rows[0].size - 1
175
+ size = number_of_rows * number_of_columns
176
+
176
177
  # First we have to create an excel array
177
178
  array_name = "array#{@counter}"
178
179
  @counter +=1
179
180
 
180
- cells = rows.map do |r|
181
- r.shift if r.first == :row
182
- r.map do |c|
183
- map(c)
181
+ initializers << "static ExcelValue #{array_name}[#{size}];"
182
+ i = 0
183
+ rows.each do |row|
184
+ row.each do |cell|
185
+ next if cell.is_a?(Symbol)
186
+ initializers << "#{array_name}[#{i}] = #{map(cell)};"
187
+ i += 1
184
188
  end
185
- end.flatten
186
-
187
- initializers << "static ExcelValue #{array_name}[#{cells.size}];"
188
- cells.each_with_index do |c,i|
189
- initializers << "#{array_name}[#{i}] = #{c};"
190
189
  end
191
190
 
192
191
  # Then we need to assign it to an excel value
@@ -66,7 +66,13 @@ class MapValuesToC
66
66
  "#DIV/0!" => "DIV0",
67
67
  "#REF!" => "REF",
68
68
  "#N/A" => "NA",
69
- "#NUM!" => "NUM"
69
+ "#NUM!" => "NUM",
70
+ :"#NAME?" => "NAME",
71
+ :"#VALUE!" => "VALUE",
72
+ :"#DIV/0!" => "DIV0",
73
+ :"#REF!" => "REF",
74
+ :"#N/A" => "NA",
75
+ :"#NUM!" => "NUM"
70
76
  }
71
77
 
72
78
  REVERSE_ERRORS = ERRORS.invert