excel_to_code 0.3.17 → 0.3.18.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +67 -34
  3. data/bin/excel_to_c +8 -78
  4. data/bin/excel_to_go +41 -0
  5. data/bin/excel_to_ruby +2 -69
  6. data/src/commands.rb +2 -0
  7. data/src/commands/common_command_line_options.rb +81 -0
  8. data/src/commands/excel_to_c.rb +3 -0
  9. data/src/commands/excel_to_go.rb +91 -0
  10. data/src/commands/excel_to_x.rb +77 -11
  11. data/src/compile.rb +1 -0
  12. data/src/compile/c/a.out +0 -0
  13. data/src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out +0 -0
  14. data/src/compile/c/compile_to_c.rb +2 -0
  15. data/src/compile/c/excel_to_c_runtime.c +691 -145
  16. data/src/compile/c/excel_to_c_runtime_test.c +226 -20
  17. data/src/compile/c/map_formulae_to_c.rb +62 -23
  18. data/src/compile/c/run_c_unit_tests +3 -0
  19. data/src/compile/cd.rb +6 -0
  20. data/src/compile/go.rb +3 -0
  21. data/src/compile/go/compile_to_go.rb +85 -0
  22. data/src/compile/go/compile_to_go_test.rb +73 -0
  23. data/src/compile/go/excel.go +171 -0
  24. data/src/compile/go/excel_test.go +54 -0
  25. data/src/compile/go/map_values_to_go.rb +67 -0
  26. data/src/compile/ruby/map_formulae_to_ruby.rb +30 -12
  27. data/src/excel/excel_functions.rb +26 -1
  28. data/src/excel/excel_functions/ceiling.rb +23 -0
  29. data/src/excel/excel_functions/countif.rb +15 -0
  30. data/src/excel/excel_functions/countifs.rb +10 -0
  31. data/src/excel/excel_functions/floor.rb +14 -0
  32. data/src/excel/excel_functions/hyperlink.rb +9 -0
  33. data/src/excel/excel_functions/na.rb +7 -0
  34. data/src/excel/excel_functions/not.rb +13 -0
  35. data/src/excel/excel_functions/or.rb +30 -0
  36. data/src/excel/excel_functions/product.rb +8 -0
  37. data/src/excel/excel_functions/rate.rb +16 -0
  38. data/src/excel/excel_functions/replace.rb +13 -0
  39. data/src/excel/excel_functions/scurve.rb +73 -0
  40. data/src/excel/excel_functions/sqrt.rb +11 -0
  41. data/src/excel/excel_functions/string_argument.rb +37 -0
  42. data/src/excel/excel_functions/sumifs.rb +19 -8
  43. data/src/excel/excel_functions/text.rb +3 -3
  44. data/src/excel/formula_peg.rb +1 -1
  45. data/src/excel/formula_peg.txt +2 -3
  46. data/src/excel/table.rb +15 -15
  47. data/src/excel_to_code.rb +1 -4
  48. data/src/extract/extract_data_from_worksheet.rb +8 -1
  49. data/src/rewrite/ast_expand_array_formulae.rb +4 -0
  50. data/src/rewrite/caching_formula_parser.rb +16 -11
  51. data/src/simplify.rb +1 -0
  52. data/src/simplify/inline_formulae.rb +16 -0
  53. data/src/simplify/replace_arithmetic_on_ranges.rb +14 -1
  54. data/src/simplify/replace_arrays_with_single_cells.rb +42 -15
  55. data/src/simplify/replace_cell_addresses_with_references.rb +70 -0
  56. data/src/simplify/replace_column_with_column_number.rb +8 -1
  57. data/src/simplify/replace_table_references.rb +40 -19
  58. data/src/simplify/simplify_arithmetic.rb +15 -10
  59. data/src/version.rb +4 -0
  60. metadata +115 -43
  61. data/TODO +0 -25
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+ clang excel_to_c_runtime_test.c
3
+ ./a.out
data/src/compile/cd.rb ADDED
@@ -0,0 +1,6 @@
1
+ require_relative 'c/compile_to_c'
2
+ require_relative 'c/compile_to_c_header'
3
+ require_relative 'c/map_sheet_names_to_c_names'
4
+ require_relative "c/compile_to_c_unit_test"
5
+ require_relative "c/map_values_to_c_structs"
6
+ require_relative "c/compile_named_reference_setters"
data/src/compile/go.rb ADDED
@@ -0,0 +1,3 @@
1
+ require_relative 'go/compile_to_go'
2
+ require_relative 'go/compile_to_go_test'
3
+ require_relative 'go/map_values_to_go'
@@ -0,0 +1,85 @@
1
+
2
+ class CompileToGo
3
+
4
+ attr_accessor :settable
5
+ attr_accessor :gettable
6
+ attr_accessor :sheet_names
7
+
8
+ def struct_type
9
+ "spreadsheet"
10
+ end
11
+
12
+ def self.rewrite(*args)
13
+ self.new.rewrite(*args)
14
+ end
15
+
16
+ def rewrite(formulae, sheet_names, output)
17
+ self.settable ||= lambda { |ref| false }
18
+ self.gettable ||= lambda { |ref| true }
19
+ self.sheet_names = sheet_names
20
+
21
+ m = MapValuesToGo.new
22
+
23
+ # The struct
24
+ output.puts "type #{struct_type} struct {"
25
+ formulae.each do |ref, _|
26
+ output.puts " #{variable_name(ref)} cachedValue"
27
+ end
28
+ output.puts "}"
29
+
30
+ # The initializer
31
+ output.puts <<~END
32
+
33
+ func New() #{struct_type} {
34
+ return #{struct_type}{}
35
+ }
36
+
37
+ END
38
+
39
+ formulae.each do |ref, ast|
40
+ v = variable_name(ref)
41
+ output.puts <<~END
42
+ func (s *#{struct_type}) #{getter_method_name(ref)}() (interface{}, error) {
43
+ if !s.#{v}.isCached() {
44
+ s.#{v}.set(#{m.map(ast)})
45
+ }
46
+ return s.#{v}.get()
47
+ }
48
+
49
+ END
50
+ if settable.call(ref)
51
+ output.puts <<~END
52
+
53
+ func (s *#{struct_type}) #{setter_method_name(ref)}(v interface{}) {
54
+ s.#{v}.set(v)
55
+ }
56
+
57
+ END
58
+ end
59
+ end
60
+ end
61
+
62
+ def getter_method_name(ref)
63
+ v = variable_name(ref)
64
+ if gettable.call(ref)
65
+ v[0] = v[0].upcase!
66
+ else
67
+ v[0] = v[0].downcase!
68
+ end
69
+ v
70
+ end
71
+
72
+ def setter_method_name(ref)
73
+ v = variable_name(ref)
74
+ v[0].upcase!
75
+ "Set#{v}"
76
+ end
77
+
78
+ def variable_name(ref)
79
+ worksheet = ref.first
80
+ cell = ref.last
81
+ worksheet_name = sheet_names[worksheet.to_s] || worksheet.to_s
82
+ return worksheet_name.length > 0 ? "#{worksheet_name.downcase}#{cell.upcase}" : cell.downcase
83
+ end
84
+
85
+ end
@@ -0,0 +1,73 @@
1
+
2
+ class CompileToGoTest
3
+
4
+ attr_accessor :settable
5
+ attr_accessor :gettable
6
+ attr_accessor :sheet_names
7
+
8
+ def struct_type
9
+ "spreadsheet"
10
+ end
11
+
12
+ def self.rewrite(*args)
13
+ self.new.rewrite(*args)
14
+ end
15
+
16
+ def rewrite(formulae, sheet_names, output)
17
+ self.settable ||= lambda { |ref| false }
18
+ self.gettable ||= lambda { |ref| true }
19
+ self.sheet_names = sheet_names
20
+
21
+ m = MapValuesToGo.new
22
+
23
+ formulae.each do |ref, ast|
24
+ next unless gettable.call(ref)
25
+ n = getter_method_name(ref)
26
+
27
+ if ast.first == :error
28
+ output.puts <<~END
29
+ func Test#{n}(t *testing.T) {
30
+ s := New()
31
+ e := #{m.map(ast)}
32
+ a, err := s.#{n}()
33
+ if err != e {
34
+ t.Errorf("#{n} = (%v, %v), want (nil, %v)", a, err, e)
35
+ }
36
+ }
37
+
38
+ END
39
+
40
+ else
41
+ output.puts <<~END
42
+ func Test#{n}(t *testing.T) {
43
+ s := New()
44
+ e := #{m.map(ast)}
45
+ a, err := s.#{n}()
46
+ if a != e || err != nil {
47
+ t.Errorf("#{n} = (%v, %v), want (%v, nil)", a, err, e)
48
+ }
49
+ }
50
+
51
+ END
52
+ end
53
+ end
54
+ end
55
+
56
+ def getter_method_name(ref)
57
+ v = variable_name(ref)
58
+ if gettable.call(ref)
59
+ v[0] = v[0].upcase!
60
+ else
61
+ v[0] = v[0].downcase!
62
+ end
63
+ v
64
+ end
65
+
66
+ def variable_name(ref)
67
+ worksheet = ref.first
68
+ cell = ref.last
69
+ worksheet_name = sheet_names[worksheet.to_s] || worksheet.to_s
70
+ return worksheet_name.length > 0 ? "#{worksheet_name.downcase}#{cell.upcase}" : cell.downcase
71
+ end
72
+
73
+ end
@@ -0,0 +1,171 @@
1
+ // excel replicates values and functions from Microsoft Excel
2
+ package excel
3
+
4
+ import (
5
+ "fmt"
6
+ "strconv"
7
+ )
8
+
9
+ // cachedValue wraps the different possible Excel Values
10
+ //
11
+ // Later, we may have one for each Excel type
12
+ // which is why we use wrappers.
13
+ type cachedValue struct {
14
+ // v is the cached value, in this case of any type
15
+ v interface{}
16
+ // c is whether it is cached
17
+ c bool
18
+ }
19
+
20
+ func (c *cachedValue) isCached() bool {
21
+ return c.c
22
+ }
23
+
24
+ func (c *cachedValue) set(v interface{}) {
25
+ c.v = v
26
+ c.c = true
27
+ }
28
+
29
+ // get returns the cached value. If the cached
30
+ // value is an Excel Error that is returned as
31
+ // the second argument. If the item isn't cached
32
+ // then will return a NotCachedError.
33
+ func (c *cachedValue) get() (interface{}, error) {
34
+ if !c.c {
35
+ return nil, notCachedError{}
36
+ }
37
+ if err, ok := c.v.(error); ok {
38
+ return nil, err
39
+ }
40
+ return c.v, nil
41
+ }
42
+
43
+ type notCachedError struct{}
44
+
45
+ func (e notCachedError) Error() string {
46
+ return "Get() called but nothing cached"
47
+ }
48
+
49
+ // Blank is an empty Excel cell.
50
+ type Blank struct{}
51
+
52
+ // The Excel #VALUE! error
53
+ type ValueError struct {
54
+ value interface{}
55
+ cast string
56
+ }
57
+
58
+ // The Excel #NAME? error
59
+ type NameError struct{}
60
+
61
+ // The Excel #DIV/0! error
62
+ type Div0Error struct{}
63
+
64
+ // The Excel #REF! error
65
+ type RefError struct{}
66
+
67
+ // The Excel #N/A error
68
+ type NAError struct{}
69
+
70
+ // The Excel #NUM! error
71
+ type NumError struct{}
72
+
73
+ func (e ValueError) Error() string {
74
+ return fmt.Sprintf("#VALUE!: could not convert %v to %v", e.value, e.cast)
75
+ }
76
+
77
+ func (e NameError) Error() string {
78
+ return "#NAME?"
79
+ }
80
+
81
+ func (e Div0Error) Error() string {
82
+ return "#DIV/0!"
83
+ }
84
+
85
+ func (e RefError) Error() string {
86
+ return "#REF!"
87
+ }
88
+
89
+ func (e NAError) Error() string {
90
+ return "#N/A"
91
+ }
92
+
93
+ func (e NumError) Error() string {
94
+ return "#DIV/0!"
95
+ }
96
+
97
+ func excel_if(c interface{}, t, f func() interface{}) interface{} {
98
+ b, err := boolean(c)
99
+ if err != nil {
100
+ return err
101
+ }
102
+ if b {
103
+ if t == nil {
104
+ return true
105
+ } else {
106
+ return t()
107
+ }
108
+ } else {
109
+ if f == nil {
110
+ return false
111
+ } else {
112
+ return f()
113
+ }
114
+ }
115
+ }
116
+
117
+ func add(a, b interface{}) interface{} {
118
+ n1, err := number(a)
119
+ if err != nil {
120
+ return err
121
+ }
122
+ n2, err := number(b)
123
+ if err != nil {
124
+ return err
125
+ }
126
+ return n1 + n2
127
+ }
128
+
129
+ func number(a interface{}) (float64, error) {
130
+ switch a := a.(type) {
131
+ case Blank:
132
+ return 0, nil
133
+ case float64:
134
+ return a, nil
135
+ case bool:
136
+ if a {
137
+ return 1, nil
138
+ } else {
139
+ return 0, nil
140
+ }
141
+ case error:
142
+ return 0, a
143
+ case string:
144
+ i, err := strconv.ParseFloat(a, 64)
145
+ if err != nil {
146
+ return 0, ValueError{a, "float64"}
147
+ }
148
+ return i, nil
149
+ default:
150
+ return 0, ValueError{a, "float64"}
151
+ }
152
+ }
153
+
154
+ func boolean(a interface{}) (bool, error) {
155
+ switch a := a.(type) {
156
+ case Blank:
157
+ return false, nil
158
+ case float64:
159
+ if a == 0 {
160
+ return false, nil
161
+ } else {
162
+ return true, nil
163
+ }
164
+ case bool:
165
+ return a, nil
166
+ case error:
167
+ return false, a
168
+ default:
169
+ return false, ValueError{a, "bool"}
170
+ }
171
+ }
@@ -0,0 +1,54 @@
1
+ package excel
2
+
3
+ import "testing"
4
+
5
+ type Spreadsheet struct {
6
+ inputA1 interface{}
7
+ inputA2 interface{}
8
+ outputA1 interface{}
9
+ }
10
+
11
+ func (s *Spreadsheet) InputA1() interface{} {
12
+ if s.inputA1 == nil {
13
+ s.inputA1 = Blank{}
14
+ }
15
+ return s.inputA1
16
+ }
17
+
18
+ func (s *Spreadsheet) SetInputA1(value interface{}) {
19
+ s.inputA1 = value
20
+ }
21
+
22
+ func (s *Spreadsheet) InputA2() interface{} {
23
+ if s.inputA2 == nil {
24
+ s.inputA2 = Blank{}
25
+ }
26
+ return s.inputA2
27
+ }
28
+
29
+ func (s *Spreadsheet) SetInputA2(value interface{}) {
30
+ s.inputA2 = value
31
+ }
32
+
33
+ func (s *Spreadsheet) OutputA1() interface{} {
34
+ if s.outputA1 == nil {
35
+ inputA1 := s.InputA1()
36
+ inputA2 := s.InputA2()
37
+ sum := add(inputA1, inputA2)
38
+ s.outputA1 = excel_if(sum, func() interface{} {
39
+ return Blank{}
40
+ }, s.InputA1)
41
+ }
42
+ return s.outputA1
43
+ }
44
+
45
+ func TestHelloWorld(t *testing.T) {
46
+ s := Spreadsheet{}
47
+ s.SetInputA1(1.0)
48
+ s.SetInputA2(1.0)
49
+ //inputA1 := s.InputA1()
50
+ outputA1 := s.OutputA1()
51
+ if outputA1 != 1 {
52
+ t.Errorf("%v = %v, want %v", "s.OutputA1()", outputA1, 1)
53
+ }
54
+ }
@@ -0,0 +1,67 @@
1
+ require_relative '../../util/not_supported_exception'
2
+
3
+ class MapValuesToGo
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 inlined_blank
23
+ "Blank{}"
24
+ end
25
+
26
+ def constant(name)
27
+ name
28
+ end
29
+
30
+ alias :null :blank
31
+
32
+ def number(text)
33
+ text.to_s
34
+ end
35
+
36
+ def percentage(text)
37
+ (text.to_f / 100.0).to_s
38
+ end
39
+
40
+ def string(text)
41
+ text.inspect
42
+ end
43
+
44
+ ERRORS = {
45
+ :"#NAME?" => "NameError{}",
46
+ :"#VALUE!" => "ValueError{}",
47
+ :"#DIV/0!" => "Div0Error{}",
48
+ :"#REF!" => "RefError{}",
49
+ :"#N/A" => "NAError{}",
50
+ :"#NUM!" => "NumError{}"
51
+ }
52
+
53
+ REVERSE_ERRORS = ERRORS.invert
54
+
55
+ def error(text)
56
+ ERRORS[text.to_sym] || (raise NotSupportedException.new("#{text.inspect} error not recognised"))
57
+ end
58
+
59
+ def boolean_true
60
+ "true"
61
+ end
62
+
63
+ def boolean_false
64
+ "false"
65
+ end
66
+
67
+ end