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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dbfac77ee7c479c1e3608dac1dad7892a8156e92
4
- data.tar.gz: f474343c232b69a7b91a05a51fad658253af9991
3
+ metadata.gz: e4ebae76600b8d182956b7c1f6a0d98617cb7aeb
4
+ data.tar.gz: 07751fc9af519871db9f60f6011b8de21ee0e6f8
5
5
  SHA512:
6
- metadata.gz: 20fe12e945146c0d0740e00b534a8474848231cf3d938f71a85fafff43ef977b233ba12cafc53d165a440ce0a3ed950d316ff70a53239af0a314ba1dace6884a
7
- data.tar.gz: e6efe0d22d6f042633ea7885d83ba0319bcddda0ea00adb874784a8e05e7b90b115c6cd02c218b9d62960a99f3e0a9b6136054df623afddb048e123ebbb3e27d
6
+ metadata.gz: 46b666e419461ce012bf8e2f84e2c6b97996943c4d41590c3260e10bbf3de827b4ca6e96caa10f99d16afa80785fea8c6179dc36b0e7f3c58b1a3886f1853daf
7
+ data.tar.gz: e694dff8476a31eea15131fadb9fa44ddf8d77839ce3ab5e525d40a4ba4307d97ebbfa485a4b9bb4847a05663cbe2970db576d92ab52d21c327904f4f6df97d4
@@ -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.lines.each do |line|
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();
@@ -45,6 +45,7 @@ class MapFormulaeToC < MapValuesToC
45
45
  'INDEX2' => 'excel_index_2',
46
46
  'INDEX3' => 'excel_index',
47
47
  'INT' => 'excel_int',
48
+ 'ISNUMBER' => 'excel_isnumber',
48
49
  'LARGE' => 'large',
49
50
  'LEFT1' => 'left_1',
50
51
  'LEFT2' => 'left',
@@ -31,6 +31,7 @@ class MapFormulaeToRuby < MapValuesToRuby
31
31
  'IFERROR' => 'iferror',
32
32
  'INDEX' => 'index',
33
33
  'INT' => 'int',
34
+ 'ISNUMBER' => 'isnumber',
34
35
  'LARGE' => 'large',
35
36
  'LEFT' => 'left',
36
37
  'LOG' => 'log',
@@ -87,3 +87,5 @@ require_relative 'excel_functions/log'
87
87
  require_relative 'excel_functions/mmult'
88
88
 
89
89
  require_relative 'excel_functions/rank'
90
+
91
+ require_relative 'excel_functions/isnumber'
@@ -0,0 +1,8 @@
1
+ module ExcelFunctions
2
+
3
+ def isnumber(a)
4
+ return true if a.is_a?(Numeric)
5
+ false
6
+ end
7
+
8
+ end
@@ -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
@@ -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" && 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])
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 replace_offset(reference, row_offset, column_offset, height = 1, width = 1)
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.20
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-08-28 00:00:00.000000000 Z
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