csv_plus_plus 0.1.1 → 0.1.3

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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +18 -63
  3. data/{CHANGELOG.md → docs/CHANGELOG.md} +17 -0
  4. data/lib/csv_plus_plus/benchmarked_compiler.rb +112 -0
  5. data/lib/csv_plus_plus/cell.rb +46 -24
  6. data/lib/csv_plus_plus/cli.rb +44 -17
  7. data/lib/csv_plus_plus/cli_flag.rb +1 -2
  8. data/lib/csv_plus_plus/color.rb +42 -11
  9. data/lib/csv_plus_plus/compiler.rb +178 -0
  10. data/lib/csv_plus_plus/entities/ast_builder.rb +50 -0
  11. data/lib/csv_plus_plus/entities/boolean.rb +40 -0
  12. data/lib/csv_plus_plus/entities/builtins.rb +58 -0
  13. data/lib/csv_plus_plus/entities/cell_reference.rb +231 -0
  14. data/lib/csv_plus_plus/entities/date.rb +63 -0
  15. data/lib/csv_plus_plus/entities/entity.rb +50 -0
  16. data/lib/csv_plus_plus/entities/entity_with_arguments.rb +57 -0
  17. data/lib/csv_plus_plus/entities/function.rb +45 -0
  18. data/lib/csv_plus_plus/entities/function_call.rb +50 -0
  19. data/lib/csv_plus_plus/entities/number.rb +48 -0
  20. data/lib/csv_plus_plus/entities/runtime_value.rb +43 -0
  21. data/lib/csv_plus_plus/entities/string.rb +42 -0
  22. data/lib/csv_plus_plus/entities/variable.rb +37 -0
  23. data/lib/csv_plus_plus/entities.rb +40 -0
  24. data/lib/csv_plus_plus/error/error.rb +20 -0
  25. data/lib/csv_plus_plus/error/formula_syntax_error.rb +37 -0
  26. data/lib/csv_plus_plus/error/modifier_syntax_error.rb +75 -0
  27. data/lib/csv_plus_plus/error/modifier_validation_error.rb +69 -0
  28. data/lib/csv_plus_plus/error/syntax_error.rb +71 -0
  29. data/lib/csv_plus_plus/error/writer_error.rb +17 -0
  30. data/lib/csv_plus_plus/error.rb +10 -2
  31. data/lib/csv_plus_plus/google_api_client.rb +11 -2
  32. data/lib/csv_plus_plus/google_options.rb +23 -18
  33. data/lib/csv_plus_plus/lexer/lexer.rb +17 -6
  34. data/lib/csv_plus_plus/lexer/tokenizer.rb +6 -1
  35. data/lib/csv_plus_plus/lexer.rb +24 -0
  36. data/lib/csv_plus_plus/modifier/conditional_formatting.rb +18 -0
  37. data/lib/csv_plus_plus/modifier/data_validation.rb +138 -0
  38. data/lib/csv_plus_plus/modifier/expand.rb +61 -0
  39. data/lib/csv_plus_plus/modifier/google_sheet_modifier.rb +133 -0
  40. data/lib/csv_plus_plus/modifier/modifier.rb +222 -0
  41. data/lib/csv_plus_plus/modifier/modifier_validator.rb +243 -0
  42. data/lib/csv_plus_plus/modifier/rubyxl_modifier.rb +84 -0
  43. data/lib/csv_plus_plus/modifier.rb +82 -150
  44. data/lib/csv_plus_plus/options.rb +64 -19
  45. data/lib/csv_plus_plus/{language → parser}/cell_value.tab.rb +25 -25
  46. data/lib/csv_plus_plus/{language → parser}/code_section.tab.rb +86 -95
  47. data/lib/csv_plus_plus/parser/modifier.tab.rb +478 -0
  48. data/lib/csv_plus_plus/row.rb +53 -15
  49. data/lib/csv_plus_plus/runtime/can_define_references.rb +87 -0
  50. data/lib/csv_plus_plus/runtime/can_resolve_references.rb +209 -0
  51. data/lib/csv_plus_plus/runtime/graph.rb +68 -0
  52. data/lib/csv_plus_plus/runtime/position_tracker.rb +231 -0
  53. data/lib/csv_plus_plus/runtime/references.rb +110 -0
  54. data/lib/csv_plus_plus/runtime/runtime.rb +126 -0
  55. data/lib/csv_plus_plus/runtime.rb +42 -0
  56. data/lib/csv_plus_plus/source_code.rb +66 -0
  57. data/lib/csv_plus_plus/template.rb +63 -36
  58. data/lib/csv_plus_plus/version.rb +2 -1
  59. data/lib/csv_plus_plus/writer/base_writer.rb +30 -5
  60. data/lib/csv_plus_plus/writer/csv.rb +11 -9
  61. data/lib/csv_plus_plus/writer/excel.rb +9 -2
  62. data/lib/csv_plus_plus/writer/file_backer_upper.rb +7 -4
  63. data/lib/csv_plus_plus/writer/google_sheet_builder.rb +88 -45
  64. data/lib/csv_plus_plus/writer/google_sheets.rb +79 -29
  65. data/lib/csv_plus_plus/writer/open_document.rb +6 -1
  66. data/lib/csv_plus_plus/writer/rubyxl_builder.rb +103 -33
  67. data/lib/csv_plus_plus/writer.rb +39 -9
  68. data/lib/csv_plus_plus.rb +41 -15
  69. metadata +44 -30
  70. data/lib/csv_plus_plus/code_section.rb +0 -101
  71. data/lib/csv_plus_plus/expand.rb +0 -18
  72. data/lib/csv_plus_plus/graph.rb +0 -62
  73. data/lib/csv_plus_plus/language/ast_builder.rb +0 -68
  74. data/lib/csv_plus_plus/language/benchmarked_compiler.rb +0 -65
  75. data/lib/csv_plus_plus/language/builtins.rb +0 -46
  76. data/lib/csv_plus_plus/language/compiler.rb +0 -152
  77. data/lib/csv_plus_plus/language/entities/boolean.rb +0 -33
  78. data/lib/csv_plus_plus/language/entities/cell_reference.rb +0 -33
  79. data/lib/csv_plus_plus/language/entities/entity.rb +0 -86
  80. data/lib/csv_plus_plus/language/entities/function.rb +0 -35
  81. data/lib/csv_plus_plus/language/entities/function_call.rb +0 -37
  82. data/lib/csv_plus_plus/language/entities/number.rb +0 -36
  83. data/lib/csv_plus_plus/language/entities/runtime_value.rb +0 -28
  84. data/lib/csv_plus_plus/language/entities/string.rb +0 -31
  85. data/lib/csv_plus_plus/language/entities/variable.rb +0 -25
  86. data/lib/csv_plus_plus/language/entities.rb +0 -28
  87. data/lib/csv_plus_plus/language/references.rb +0 -70
  88. data/lib/csv_plus_plus/language/runtime.rb +0 -205
  89. data/lib/csv_plus_plus/language/scope.rb +0 -192
  90. data/lib/csv_plus_plus/language/syntax_error.rb +0 -66
  91. data/lib/csv_plus_plus/modifier.tab.rb +0 -907
  92. data/lib/csv_plus_plus/writer/google_sheet_modifier.rb +0 -56
  93. data/lib/csv_plus_plus/writer/rubyxl_modifier.rb +0 -59
@@ -1,3 +1,4 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require_relative './writer/base_writer'
@@ -7,18 +8,47 @@ require_relative './writer/google_sheets'
7
8
  require_relative './writer/open_document'
8
9
 
9
10
  module CSVPlusPlus
10
- # Various strategies for writing to various formats (excel, google sheets, CSV, OpenDocument)
11
+ # Various strategies for writing to various formats (excel, google sheets, CSV & OpenDocument (not yet implemented))
11
12
  module Writer
12
- # Return an instance of a writer depending on the given +options+
13
- def self.writer(options)
14
- return ::CSVPlusPlus::Writer::GoogleSheets.new(options) if options.google
13
+ extend ::T::Sig
15
14
 
16
- case options.output_filename
17
- when /\.csv$/ then ::CSVPlusPlus::Writer::CSV.new(options)
18
- when /\.ods$/ then ::CSVPlusPlus::Writer::OpenDocument.new(options)
19
- when /\.xl(sx|sm|tx|tm)$/ then ::CSVPlusPlus::Writer::Excel.new(options)
20
- else raise(::CSVPlusPlus::Error, "Unsupported file extension: #{options.output_filename}")
15
+ sig do
16
+ params(
17
+ options: ::CSVPlusPlus::Options,
18
+ runtime: ::CSVPlusPlus::Runtime::Runtime
19
+ ).returns(
20
+ ::T.any(
21
+ ::CSVPlusPlus::Writer::CSV,
22
+ ::CSVPlusPlus::Writer::Excel,
23
+ ::CSVPlusPlus::Writer::GoogleSheets,
24
+ ::CSVPlusPlus::Writer::OpenDocument
25
+ )
26
+ )
27
+ end
28
+ # Return an instance of a writer depending on the given +options+
29
+ #
30
+ # @param options [Options] The supplied options.
31
+ # @param runtime [Runtime] The current runtime.
32
+ #
33
+ # @return [Writer::CSV | Writer::Excel | Writer::GoogleSheets | Writer::OpenDocument]
34
+ # rubocop:disable Metrics/MethodLength
35
+ def self.writer(options, runtime)
36
+ output_format = options.output_format
37
+ case output_format
38
+ when ::CSVPlusPlus::Options::OutputFormat::CSV then ::CSVPlusPlus::Writer::CSV.new(options, runtime)
39
+ when ::CSVPlusPlus::Options::OutputFormat::Excel then ::CSVPlusPlus::Writer::Excel.new(options, runtime)
40
+ when ::CSVPlusPlus::Options::OutputFormat::GoogleSheets then ::CSVPlusPlus::Writer::GoogleSheets.new(
41
+ options,
42
+ runtime
43
+ )
44
+ when ::CSVPlusPlus::Options::OutputFormat::OpenDocument then ::CSVPlusPlus::Writer::OpenDocument.new(
45
+ options,
46
+ runtime
47
+ )
48
+ else
49
+ ::T.absurd(output_format)
21
50
  end
22
51
  end
52
+ # rubocop:enable Metrics/MethodLength
23
53
  end
24
54
  end
data/lib/csv_plus_plus.rb CHANGED
@@ -1,30 +1,54 @@
1
+ # typed: strict
1
2
  # frozen_string_literal: true
2
3
 
4
+ require 'sorbet-runtime'
5
+
6
+ require 'benchmark'
7
+ require 'csv'
8
+ require 'fileutils'
3
9
  require 'google/apis/drive_v3'
4
10
  require 'google/apis/sheets_v4'
5
11
  require 'googleauth'
12
+ require 'optparse'
13
+ require 'pathname'
6
14
  require 'rubyXL'
7
15
  require 'rubyXL/convenience_methods'
8
16
  require 'set'
17
+ require 'tempfile'
18
+
19
+ require_relative 'csv_plus_plus/source_code'
20
+
21
+ require_relative 'csv_plus_plus/runtime'
22
+
23
+ require_relative 'csv_plus_plus/cli_flag'
24
+ require_relative 'csv_plus_plus/entities'
25
+ require_relative 'csv_plus_plus/error'
9
26
 
10
27
  require_relative 'csv_plus_plus/cell'
11
28
  require_relative 'csv_plus_plus/cli'
12
- require_relative 'csv_plus_plus/code_section'
13
29
  require_relative 'csv_plus_plus/color'
14
- require_relative 'csv_plus_plus/error'
15
- require_relative 'csv_plus_plus/language/builtins'
16
- require_relative 'csv_plus_plus/language/compiler'
17
- require_relative 'csv_plus_plus/language/runtime'
18
- require_relative 'csv_plus_plus/language/syntax_error'
19
30
  require_relative 'csv_plus_plus/modifier'
20
- require_relative 'csv_plus_plus/modifier.tab'
31
+
32
+ require_relative 'csv_plus_plus/parser/cell_value.tab'
33
+ require_relative 'csv_plus_plus/parser/code_section.tab'
34
+ require_relative 'csv_plus_plus/parser/modifier.tab'
35
+
36
+ require_relative 'csv_plus_plus/compiler'
37
+
38
+ require_relative 'csv_plus_plus/google_options'
39
+ require_relative 'csv_plus_plus/lexer'
21
40
  require_relative 'csv_plus_plus/options'
22
41
  require_relative 'csv_plus_plus/row'
23
42
  require_relative 'csv_plus_plus/template'
24
43
  require_relative 'csv_plus_plus/writer'
25
44
 
45
+ require_relative 'csv_plus_plus/benchmarked_compiler'
46
+
26
47
  # A programming language for writing rich CSV files
27
48
  module CSVPlusPlus
49
+ extend ::T::Sig
50
+
51
+ sig { params(input: ::String, filename: ::T.nilable(::String), options: ::CSVPlusPlus::Options).void }
28
52
  # Parse the input into a +Template+ and write it to the desired format
29
53
  #
30
54
  # @param input [String] The csvpp input to compile
@@ -33,25 +57,27 @@ module CSVPlusPlus
33
57
  def self.apply_template_to_sheet!(input, filename, options)
34
58
  warn(options.verbose_summary) if options.verbose
35
59
 
36
- runtime = ::CSVPlusPlus::Language::Runtime.new(input:, filename:)
60
+ runtime = ::CSVPlusPlus::Runtime.new(source_code: ::CSVPlusPlus::SourceCode.new(input:, filename:))
37
61
 
38
- ::CSVPlusPlus::Language::Compiler.with_compiler(options:, runtime:) do |compiler|
62
+ ::CSVPlusPlus::Compiler.with_compiler(options:, runtime:) do |compiler|
39
63
  template = compiler.compile_template
40
-
41
64
  warn(template.verbose_summary) if options.verbose
42
65
 
43
- write_template(template, compiler, options)
66
+ write_template(template:, compiler:, options:)
44
67
  end
45
68
  end
46
69
 
70
+ sig do
71
+ params(compiler: ::CSVPlusPlus::Compiler, options: ::CSVPlusPlus::Options, template: ::CSVPlusPlus::Template).void
72
+ end
47
73
  # Write the results (and possibly make a backup) of a compiled +template+
48
74
  #
49
- # @param template [Template] The compiled template
50
75
  # @param compiler [Compiler] The compiler currently in use
51
76
  # @param options [Options] The options we're running with
52
- def self.write_template(template, compiler, options)
53
- output = ::CSVPlusPlus::Writer.writer(options)
54
- compiler.outputting! do
77
+ # @param template [Template] The compiled template
78
+ def self.write_template(compiler:, options:, template:)
79
+ compiler.outputting! do |runtime|
80
+ output = ::CSVPlusPlus::Writer.writer(options, runtime)
55
81
  output.write_backup if options.backup
56
82
  output.write(template)
57
83
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csv_plus_plus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrick Carroll
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-03-11 00:00:00.000000000 Z
11
+ date: 2023-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-apis-drive_v3
@@ -118,48 +118,64 @@ executables:
118
118
  extensions: []
119
119
  extra_rdoc_files: []
120
120
  files:
121
- - CHANGELOG.md
122
121
  - README.md
123
122
  - bin/csv++
124
123
  - bin/csvpp
124
+ - docs/CHANGELOG.md
125
125
  - lib/csv_plus_plus.rb
126
+ - lib/csv_plus_plus/benchmarked_compiler.rb
126
127
  - lib/csv_plus_plus/cell.rb
127
128
  - lib/csv_plus_plus/cli.rb
128
129
  - lib/csv_plus_plus/cli_flag.rb
129
- - lib/csv_plus_plus/code_section.rb
130
130
  - lib/csv_plus_plus/color.rb
131
+ - lib/csv_plus_plus/compiler.rb
132
+ - lib/csv_plus_plus/entities.rb
133
+ - lib/csv_plus_plus/entities/ast_builder.rb
134
+ - lib/csv_plus_plus/entities/boolean.rb
135
+ - lib/csv_plus_plus/entities/builtins.rb
136
+ - lib/csv_plus_plus/entities/cell_reference.rb
137
+ - lib/csv_plus_plus/entities/date.rb
138
+ - lib/csv_plus_plus/entities/entity.rb
139
+ - lib/csv_plus_plus/entities/entity_with_arguments.rb
140
+ - lib/csv_plus_plus/entities/function.rb
141
+ - lib/csv_plus_plus/entities/function_call.rb
142
+ - lib/csv_plus_plus/entities/number.rb
143
+ - lib/csv_plus_plus/entities/runtime_value.rb
144
+ - lib/csv_plus_plus/entities/string.rb
145
+ - lib/csv_plus_plus/entities/variable.rb
131
146
  - lib/csv_plus_plus/error.rb
132
- - lib/csv_plus_plus/expand.rb
147
+ - lib/csv_plus_plus/error/error.rb
148
+ - lib/csv_plus_plus/error/formula_syntax_error.rb
149
+ - lib/csv_plus_plus/error/modifier_syntax_error.rb
150
+ - lib/csv_plus_plus/error/modifier_validation_error.rb
151
+ - lib/csv_plus_plus/error/syntax_error.rb
152
+ - lib/csv_plus_plus/error/writer_error.rb
133
153
  - lib/csv_plus_plus/google_api_client.rb
134
154
  - lib/csv_plus_plus/google_options.rb
135
- - lib/csv_plus_plus/graph.rb
136
- - lib/csv_plus_plus/language/ast_builder.rb
137
- - lib/csv_plus_plus/language/benchmarked_compiler.rb
138
- - lib/csv_plus_plus/language/builtins.rb
139
- - lib/csv_plus_plus/language/cell_value.tab.rb
140
- - lib/csv_plus_plus/language/code_section.tab.rb
141
- - lib/csv_plus_plus/language/compiler.rb
142
- - lib/csv_plus_plus/language/entities.rb
143
- - lib/csv_plus_plus/language/entities/boolean.rb
144
- - lib/csv_plus_plus/language/entities/cell_reference.rb
145
- - lib/csv_plus_plus/language/entities/entity.rb
146
- - lib/csv_plus_plus/language/entities/function.rb
147
- - lib/csv_plus_plus/language/entities/function_call.rb
148
- - lib/csv_plus_plus/language/entities/number.rb
149
- - lib/csv_plus_plus/language/entities/runtime_value.rb
150
- - lib/csv_plus_plus/language/entities/string.rb
151
- - lib/csv_plus_plus/language/entities/variable.rb
152
- - lib/csv_plus_plus/language/references.rb
153
- - lib/csv_plus_plus/language/runtime.rb
154
- - lib/csv_plus_plus/language/scope.rb
155
- - lib/csv_plus_plus/language/syntax_error.rb
156
155
  - lib/csv_plus_plus/lexer.rb
157
156
  - lib/csv_plus_plus/lexer/lexer.rb
158
157
  - lib/csv_plus_plus/lexer/tokenizer.rb
159
158
  - lib/csv_plus_plus/modifier.rb
160
- - lib/csv_plus_plus/modifier.tab.rb
159
+ - lib/csv_plus_plus/modifier/conditional_formatting.rb
160
+ - lib/csv_plus_plus/modifier/data_validation.rb
161
+ - lib/csv_plus_plus/modifier/expand.rb
162
+ - lib/csv_plus_plus/modifier/google_sheet_modifier.rb
163
+ - lib/csv_plus_plus/modifier/modifier.rb
164
+ - lib/csv_plus_plus/modifier/modifier_validator.rb
165
+ - lib/csv_plus_plus/modifier/rubyxl_modifier.rb
161
166
  - lib/csv_plus_plus/options.rb
167
+ - lib/csv_plus_plus/parser/cell_value.tab.rb
168
+ - lib/csv_plus_plus/parser/code_section.tab.rb
169
+ - lib/csv_plus_plus/parser/modifier.tab.rb
162
170
  - lib/csv_plus_plus/row.rb
171
+ - lib/csv_plus_plus/runtime.rb
172
+ - lib/csv_plus_plus/runtime/can_define_references.rb
173
+ - lib/csv_plus_plus/runtime/can_resolve_references.rb
174
+ - lib/csv_plus_plus/runtime/graph.rb
175
+ - lib/csv_plus_plus/runtime/position_tracker.rb
176
+ - lib/csv_plus_plus/runtime/references.rb
177
+ - lib/csv_plus_plus/runtime/runtime.rb
178
+ - lib/csv_plus_plus/source_code.rb
163
179
  - lib/csv_plus_plus/template.rb
164
180
  - lib/csv_plus_plus/version.rb
165
181
  - lib/csv_plus_plus/writer.rb
@@ -168,11 +184,9 @@ files:
168
184
  - lib/csv_plus_plus/writer/excel.rb
169
185
  - lib/csv_plus_plus/writer/file_backer_upper.rb
170
186
  - lib/csv_plus_plus/writer/google_sheet_builder.rb
171
- - lib/csv_plus_plus/writer/google_sheet_modifier.rb
172
187
  - lib/csv_plus_plus/writer/google_sheets.rb
173
188
  - lib/csv_plus_plus/writer/open_document.rb
174
189
  - lib/csv_plus_plus/writer/rubyxl_builder.rb
175
- - lib/csv_plus_plus/writer/rubyxl_modifier.rb
176
190
  homepage: https://github.com/patrickomatic/csv-plus-plus
177
191
  licenses:
178
192
  - MIT
@@ -182,7 +196,7 @@ metadata:
182
196
  github_repo: git://github.com/patrickomatic/csv-plus-plus
183
197
  homepage_uri: https://github.com/patrickomatic/csv-plus-plus
184
198
  source_code_uri: https://github.com/patrickomatic/csv-plus-plus
185
- changelog_uri: https://github.com/patrickomatic/csv-plus-plus/blob/main/CHANGELOG.md
199
+ changelog_uri: https://github.com/patrickomatic/csv-plus-plus/blob/main/docs/CHANGELOG.md
186
200
  rubygems_mfa_required: 'true'
187
201
  post_install_message:
188
202
  rdoc_options: []
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './language/code_section.tab'
4
- require_relative './language/entities'
5
-
6
- module CSVPlusPlus
7
- # A representation of the code section part of a template (the variable and function definitions)
8
- #
9
- # @attr variables [Hash<Symbol, Variable>] All defined variables
10
- # @attr_reader functions [Hash<Symbol, Function>] All defined functions
11
- class CodeSection
12
- attr_reader :functions
13
- attr_accessor :variables
14
-
15
- # @param variables [Hash<Symbol, Variable>] Initial variables
16
- # @param functions [Hash<Symbol, Variable>] Initial functions
17
- def initialize(variables: {}, functions: {})
18
- @variables = variables
19
- @functions = functions
20
- end
21
-
22
- # Define a (or re-define an existing) variable
23
- #
24
- # @param id [String, Symbol] The identifier for the variable
25
- # @param entity [Entity] The value (entity) the variable holds
26
- def def_variable(id, entity)
27
- @variables[id.to_sym] = entity
28
- end
29
-
30
- # Define (or re-define existing) variables
31
- #
32
- # @param variables [Hash<Symbol, Variable>] Variables to define
33
- def def_variables(variables)
34
- variables.each { |id, entity| def_variable(id, entity) }
35
- end
36
-
37
- # Define a (or re-define an existing) function
38
- #
39
- # @param id [String, Symbol] The identifier for the function
40
- # @param entity [Entities::Function] The defined function
41
- def def_function(id, entity)
42
- @functions[id.to_sym] = entity
43
- end
44
-
45
- # Is the variable defined?
46
- #
47
- # @param var_id [Symbol, String] The identifier of the variable
48
- #
49
- # @return [boolean]
50
- def defined_variable?(var_id)
51
- @variables.key?(var_id.to_sym)
52
- end
53
-
54
- # Is the function defined?
55
- #
56
- # @param fn_id [Symbol, String] The identifier of the function
57
- #
58
- # @return [boolean]
59
- def defined_function?(fn_id)
60
- @functions.key?(fn_id.to_sym)
61
- end
62
-
63
- # @return [String]
64
- def to_s
65
- "CodeSection(functions: #{@functions}, variables: #{@variables})"
66
- end
67
-
68
- # Provide a summary of the functions and variables compiled (to show in verbose mode)
69
- #
70
- # @return [String]
71
- def verbose_summary
72
- <<~SUMMARY
73
- # Code Section Summary
74
-
75
- ## Resolved Variables
76
-
77
- #{variable_summary}
78
-
79
- ## Functions
80
-
81
- #{function_summary}
82
- SUMMARY
83
- end
84
-
85
- private
86
-
87
- def variable_summary
88
- return '(no variables defined)' if @variables.empty?
89
-
90
- @variables.map { |k, v| "#{k} := #{v}" }
91
- .join("\n")
92
- end
93
-
94
- def function_summary
95
- return '(no functions defined)' if @functions.empty?
96
-
97
- @functions.map { |k, f| "#{k}: #{f}" }
98
- .join("\n")
99
- end
100
- end
101
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module CSVPlusPlus
4
- Expand =
5
- ::Struct.new(:repetitions) do
6
- # Does this infinitely expand?
7
- def infinite?
8
- repetitions.nil?
9
- end
10
-
11
- # to_s
12
- def to_s
13
- "Expand #{repetitions || 'infinity'}"
14
- end
15
- end
16
-
17
- public_constant :Expand
18
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'tsort'
4
-
5
- module CSVPlusPlus
6
- # Graph ordering and searching functions
7
- module Graph
8
- # Get a list of all variables references in a given +ast+
9
- # TODO: this is only used in one place - refactor it
10
- def self.variable_references(ast, runtime, include_runtime_variables: false)
11
- depth_first_search(ast) do |node|
12
- next unless node.variable?
13
-
14
- node.id if !runtime.runtime_variable?(node.id) || include_runtime_variables
15
- end
16
- end
17
-
18
- # Create a dependency graph of +variables+
19
- def self.dependency_graph(variables, runtime)
20
- ::CSVPlusPlus::Graph::DependencyGraph[
21
- variables.map { |var_id, ast| [var_id, variable_references(ast, runtime)] }
22
- ]
23
- end
24
-
25
- # Perform a topological sort on a +DependencyGraph+. A toplogical sort is noteworthy
26
- # because it will give us the order in which we need to resolve our variable dependencies.
27
- #
28
- # Given this dependency graph:
29
- #
30
- # { a: [b c], b: [c], c: [d], d: [] }
31
- #
32
- # it will return:
33
- #
34
- # [d, c, b, a]
35
- #
36
- def self.topological_sort(dependencies)
37
- dependencies.tsort
38
- end
39
-
40
- # Do a DFS on an AST starting at +node+
41
- def self.depth_first_search(node, accum = [], &)
42
- ret = yield(node)
43
- accum << ret unless ret.nil?
44
-
45
- return accum unless node.function_call?
46
-
47
- node.arguments.each { |n| depth_first_search(n, accum, &) }
48
- accum
49
- end
50
-
51
- # A dependency graph represented as a +Hash+ which will be used by our +topological_sort+ function
52
- class DependencyGraph < Hash
53
- include ::TSort
54
- alias tsort_each_node each_key
55
-
56
- # sort each child
57
- def tsort_each_child(node, &)
58
- fetch(node).each(&)
59
- end
60
- end
61
- end
62
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './entities'
4
-
5
- module CSVPlusPlus
6
- module Language
7
- # Some helpful functions that can be mixed into a class to help building ASTs
8
- module ASTBuilder
9
- # Let the current class have functions which can build a given entity by calling it's type. For example
10
- # +number(1)+, +variable(:foo)+
11
- #
12
- # @param method_name [Symbol] The +method_name+ to respond to
13
- # @param arguments [] The arguments to create the entity with
14
- #
15
- # @return [Entity, #super]
16
- def method_missing(method_name, *args, **kwargs, &)
17
- entity_class = ::CSVPlusPlus::Language::TYPES[method_name.to_sym]
18
- return super unless entity_class
19
-
20
- entity_class.new(*args, **kwargs, &)
21
- end
22
-
23
- # Let the current class have functions which can build a given entity by calling it's type. For example
24
- # +number(1)+, +variable(:foo)+
25
- #
26
- # @param method_name [Symbol] The +method_name+ to respond to
27
- # @param arguments [] The arguments to create the entity with
28
- #
29
- # @return [Boolean, #super]
30
- def respond_to_missing?(method_name, *_arguments)
31
- ::CSVPlusPlus::Language::TYPES.include?(method_name.to_sym) || super
32
- end
33
-
34
- # Turns index-based/X,Y coordinates into a A1 format
35
- #
36
- # @param row_index [Integer]
37
- # @param cell_index [Integer]
38
- #
39
- # @return [String]
40
- def ref(row_index: nil, cell_index: nil)
41
- return unless row_index || cell_index
42
-
43
- rowref = row_index ? (row_index + 1).to_s : ''
44
- cellref = cell_index ? cell_ref(cell_index) : ''
45
- cell_reference([cellref, rowref].join)
46
- end
47
-
48
- private
49
-
50
- ALPHA = ('A'..'Z').to_a.freeze
51
- private_constant :ALPHA
52
-
53
- def cell_ref(cell_index)
54
- c = cell_index.dup
55
- ref = ''
56
-
57
- while c >= 0
58
- # rubocop:disable Lint/ConstantResolution
59
- ref += ALPHA[c % 26]
60
- # rubocop:enable Lint/ConstantResolution
61
- c = (c / 26).floor - 1
62
- end
63
-
64
- ref.reverse
65
- end
66
- end
67
- end
68
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'benchmark'
4
-
5
- module CSVPlusPlus
6
- module Language
7
- # Extend a +Compiler+ class and add benchmark timings
8
- # @attr_reader timings [Array<Benchmark::Tms>] +Benchmark+ timings that have been accumulated by each step of
9
- # compilation
10
- # @attr_reader benchmark [Benchmark] A +Benchmark+ instance
11
- module BenchmarkedCompiler
12
- attr_reader :benchmark, :timings
13
-
14
- # Wrap a +Compiler+ with our instance methods that add benchmarks
15
- def self.with_benchmarks(compiler, &block)
16
- ::Benchmark.benchmark(::Benchmark::CAPTION, 25, ::Benchmark::FORMAT, '> Total') do |x|
17
- # compiler = new(options:, runtime:, benchmark: x)
18
- compiler.extend(self)
19
- compiler.benchmark = x
20
-
21
- block.call(compiler)
22
-
23
- [compiler.timings.reduce(:+)]
24
- end
25
- end
26
-
27
- # @param benchmark [Benchmark] A +Benchmark+ instance
28
- def benchmark=(benchmark)
29
- @benchmark = benchmark
30
- @timings = []
31
- end
32
-
33
- # Time the Compiler#outputting! stage
34
- def outputting!
35
- time_stage('Writing the spreadsheet') { super }
36
- end
37
-
38
- protected
39
-
40
- def parse_code_section!
41
- time_stage('Parsing code section') { super }
42
- end
43
-
44
- def parse_csv_section!
45
- time_stage('Parsing CSV section') { super }
46
- end
47
-
48
- def expanding
49
- time_stage('Expanding rows') { super }
50
- end
51
-
52
- def resolve_all_cells!(template)
53
- time_stage('Resolving each cell') { super(template) }
54
- end
55
-
56
- private
57
-
58
- def time_stage(stage, &block)
59
- ret = nil
60
- @timings << @benchmark.report(stage) { ret = block.call }
61
- ret
62
- end
63
- end
64
- end
65
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './ast_builder'
4
-
5
- module CSVPlusPlus
6
- module Language
7
- # Provides ASTs for builtin functions and variables
8
- module Builtins
9
- extend ::CSVPlusPlus::Language::ASTBuilder
10
-
11
- VARIABLES = {
12
- # The number (integer) of the current cell. Starts at 1
13
- cellnum: runtime_value(->(runtime) { number(runtime.cell_index + 1) }),
14
-
15
- # A reference to the current cell
16
- cellref: runtime_value(->(runtime) { ref(row_index: runtime.row_index, cell_index: runtime.cell_index) }),
17
-
18
- # A reference to the row above
19
- rowabove: runtime_value(->(runtime) { ref(row_index: [0, (runtime.row_index - 1)].max) }),
20
-
21
- # A reference to the row below
22
- rowbelow: runtime_value(->(runtime) { ref(row_index: runtime.row_index + 1) }),
23
-
24
- # The number (integer) of the current row. Starts at 1
25
- rownum: runtime_value(->(runtime) { number(runtime.rownum) }),
26
-
27
- # A reference to the current row
28
- rowref: runtime_value(->(runtime) { ref(row_index: runtime.row_index) })
29
- }.freeze
30
- public_constant :VARIABLES
31
-
32
- FUNCTIONS = {
33
- # TODO: A reference to a cell in a given row?
34
- # A reference to a cell above the current row
35
- cellabove: runtime_value(->(runtime, args) { cell_reference([args[0], [1, (runtime.rownum - 1)].max].join) }),
36
-
37
- # A reference to a cell in the current row
38
- celladjacent: runtime_value(->(runtime, args) { cell_reference([args[0], runtime.rownum].join) }),
39
-
40
- # A reference to a cell below the current row
41
- cellbelow: runtime_value(->(runtime, args) { cell_reference([args[0], runtime.rownum + 1].join) })
42
- }.freeze
43
- public_constant :FUNCTIONS
44
- end
45
- end
46
- end