herb 0.7.2-x86_64-linux-gnu → 0.7.4-x86_64-linux-gnu

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/Makefile +2 -0
  3. data/README.md +1 -1
  4. data/Rakefile +46 -1
  5. data/config.yml +714 -0
  6. data/ext/herb/extconf.rb +2 -1
  7. data/ext/herb/nodes.c +1 -1
  8. data/herb.gemspec +3 -0
  9. data/lib/herb/3.0/herb.so +0 -0
  10. data/lib/herb/3.1/herb.so +0 -0
  11. data/lib/herb/3.2/herb.so +0 -0
  12. data/lib/herb/3.3/herb.so +0 -0
  13. data/lib/herb/3.4/herb.so +0 -0
  14. data/lib/herb/engine.rb +8 -1
  15. data/lib/herb/version.rb +1 -1
  16. data/src/analyze.c +5 -9
  17. data/src/analyze_helpers.c +17 -6
  18. data/src/herb.c +2 -2
  19. data/src/include/parser.h +2 -2
  20. data/src/include/pretty_print.h +1 -1
  21. data/src/include/version.h +1 -1
  22. data/src/parser.c +3 -2
  23. data/src/pretty_print.c +1 -1
  24. data/templates/ext/herb/error_helpers.c.erb +85 -0
  25. data/templates/ext/herb/error_helpers.h.erb +12 -0
  26. data/templates/ext/herb/nodes.c.erb +90 -0
  27. data/templates/ext/herb/nodes.h.erb +9 -0
  28. data/templates/javascript/packages/core/src/errors.ts.erb +193 -0
  29. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +325 -0
  30. data/templates/javascript/packages/core/src/nodes.ts.erb +414 -0
  31. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -0
  32. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +113 -0
  33. data/templates/javascript/packages/node/extension/error_helpers.h.erb +17 -0
  34. data/templates/javascript/packages/node/extension/nodes.cpp.erb +111 -0
  35. data/templates/javascript/packages/node/extension/nodes.h.erb +17 -0
  36. data/templates/lib/herb/ast/nodes.rb.erb +117 -0
  37. data/templates/lib/herb/errors.rb.erb +106 -0
  38. data/templates/lib/herb/visitor.rb.erb +28 -0
  39. data/templates/sig/serialized_ast_errors.rbs.erb +10 -0
  40. data/templates/sig/serialized_ast_nodes.rbs.erb +10 -0
  41. data/templates/src/ast_nodes.c.erb +145 -0
  42. data/templates/src/ast_pretty_print.c.erb +97 -0
  43. data/templates/src/errors.c.erb +245 -0
  44. data/templates/src/include/ast_nodes.h.erb +46 -0
  45. data/templates/src/include/ast_pretty_print.h.erb +14 -0
  46. data/templates/src/include/errors.h.erb +58 -0
  47. data/templates/src/visitor.c.erb +47 -0
  48. data/templates/template.rb +406 -0
  49. data/templates/wasm/error_helpers.cpp.erb +93 -0
  50. data/templates/wasm/error_helpers.h.erb +15 -0
  51. data/templates/wasm/nodes.cpp.erb +79 -0
  52. data/templates/wasm/nodes.h.erb +15 -0
  53. data/vendor/prism/Rakefile +75 -0
  54. data/vendor/prism/config.yml +4713 -0
  55. data/vendor/prism/include/prism/ast.h +8190 -0
  56. data/vendor/prism/include/prism/defines.h +260 -0
  57. data/vendor/prism/include/prism/diagnostic.h +455 -0
  58. data/vendor/prism/include/prism/encoding.h +283 -0
  59. data/vendor/prism/include/prism/node.h +129 -0
  60. data/vendor/prism/include/prism/options.h +482 -0
  61. data/vendor/prism/include/prism/pack.h +163 -0
  62. data/vendor/prism/include/prism/parser.h +933 -0
  63. data/vendor/prism/include/prism/prettyprint.h +34 -0
  64. data/vendor/prism/include/prism/regexp.h +43 -0
  65. data/vendor/prism/include/prism/static_literals.h +121 -0
  66. data/vendor/prism/include/prism/util/pm_buffer.h +236 -0
  67. data/vendor/prism/include/prism/util/pm_char.h +204 -0
  68. data/vendor/prism/include/prism/util/pm_constant_pool.h +218 -0
  69. data/vendor/prism/include/prism/util/pm_integer.h +130 -0
  70. data/vendor/prism/include/prism/util/pm_list.h +103 -0
  71. data/vendor/prism/include/prism/util/pm_memchr.h +29 -0
  72. data/vendor/prism/include/prism/util/pm_newline_list.h +113 -0
  73. data/vendor/prism/include/prism/util/pm_string.h +200 -0
  74. data/vendor/prism/include/prism/util/pm_strncasecmp.h +32 -0
  75. data/vendor/prism/include/prism/util/pm_strpbrk.h +46 -0
  76. data/vendor/prism/include/prism/version.h +29 -0
  77. data/vendor/prism/include/prism.h +408 -0
  78. data/vendor/prism/src/diagnostic.c +848 -0
  79. data/vendor/prism/src/encoding.c +5235 -0
  80. data/vendor/prism/src/node.c +8676 -0
  81. data/vendor/prism/src/options.c +328 -0
  82. data/vendor/prism/src/pack.c +509 -0
  83. data/vendor/prism/src/prettyprint.c +8941 -0
  84. data/vendor/prism/src/prism.c +23302 -0
  85. data/vendor/prism/src/regexp.c +790 -0
  86. data/vendor/prism/src/serialize.c +2268 -0
  87. data/vendor/prism/src/static_literals.c +617 -0
  88. data/vendor/prism/src/token_type.c +703 -0
  89. data/vendor/prism/src/util/pm_buffer.c +357 -0
  90. data/vendor/prism/src/util/pm_char.c +318 -0
  91. data/vendor/prism/src/util/pm_constant_pool.c +342 -0
  92. data/vendor/prism/src/util/pm_integer.c +670 -0
  93. data/vendor/prism/src/util/pm_list.c +49 -0
  94. data/vendor/prism/src/util/pm_memchr.c +35 -0
  95. data/vendor/prism/src/util/pm_newline_list.c +125 -0
  96. data/vendor/prism/src/util/pm_string.c +383 -0
  97. data/vendor/prism/src/util/pm_strncasecmp.c +36 -0
  98. data/vendor/prism/src/util/pm_strpbrk.c +206 -0
  99. data/vendor/prism/templates/ext/prism/api_node.c.erb +282 -0
  100. data/vendor/prism/templates/include/prism/ast.h.erb +226 -0
  101. data/vendor/prism/templates/include/prism/diagnostic.h.erb +130 -0
  102. data/vendor/prism/templates/java/org/prism/AbstractNodeVisitor.java.erb +22 -0
  103. data/vendor/prism/templates/java/org/prism/Loader.java.erb +434 -0
  104. data/vendor/prism/templates/java/org/prism/Nodes.java.erb +403 -0
  105. data/vendor/prism/templates/javascript/src/deserialize.js.erb +448 -0
  106. data/vendor/prism/templates/javascript/src/nodes.js.erb +197 -0
  107. data/vendor/prism/templates/javascript/src/visitor.js.erb +78 -0
  108. data/vendor/prism/templates/lib/prism/compiler.rb.erb +43 -0
  109. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +103 -0
  110. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +189 -0
  111. data/vendor/prism/templates/lib/prism/dsl.rb.erb +133 -0
  112. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +131 -0
  113. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +19 -0
  114. data/vendor/prism/templates/lib/prism/node.rb.erb +515 -0
  115. data/vendor/prism/templates/lib/prism/reflection.rb.erb +136 -0
  116. data/vendor/prism/templates/lib/prism/serialize.rb.erb +602 -0
  117. data/vendor/prism/templates/lib/prism/visitor.rb.erb +55 -0
  118. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +68 -0
  119. data/vendor/prism/templates/rbi/prism/node.rbi.erb +164 -0
  120. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +18 -0
  121. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +45 -0
  122. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +31 -0
  123. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +7 -0
  124. data/vendor/prism/templates/sig/prism/node.rbs.erb +132 -0
  125. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +17 -0
  126. data/vendor/prism/templates/sig/prism.rbs.erb +89 -0
  127. data/vendor/prism/templates/src/diagnostic.c.erb +523 -0
  128. data/vendor/prism/templates/src/node.c.erb +333 -0
  129. data/vendor/prism/templates/src/prettyprint.c.erb +166 -0
  130. data/vendor/prism/templates/src/serialize.c.erb +406 -0
  131. data/vendor/prism/templates/src/token_type.c.erb +369 -0
  132. data/vendor/prism/templates/template.rb +689 -0
  133. metadata +112 -2
@@ -0,0 +1,406 @@
1
+ # frozen_string_literal: true
2
+ # typed: false
3
+
4
+ require "erb"
5
+ require "fileutils"
6
+ require "yaml"
7
+
8
+ module Herb
9
+ module Template
10
+ class Field
11
+ attr_reader :name, :options
12
+
13
+ def initialize(name:, **options)
14
+ @name = name
15
+ @options = options
16
+ end
17
+ end
18
+
19
+ class ArrayField < Field
20
+ def initialize(kind:, **options)
21
+ @kind = kind
22
+ super(**options)
23
+ end
24
+
25
+ def ruby_type
26
+ return "Array" unless specific_kind
27
+ return "Array[Herb::AST::#{specific_kind}]" if specific_kind.end_with?("Node")
28
+
29
+ "Array[#{specific_kind}]"
30
+ end
31
+
32
+ def c_type
33
+ "array_T*"
34
+ end
35
+
36
+ def c_item_type
37
+ if specific_kind
38
+ "AST_#{specific_kind.gsub(/(?<=[a-zA-Z])(?=[A-Z][a-z])/, "_").upcase}_T*"
39
+ else
40
+ "void*"
41
+ end
42
+ end
43
+
44
+ def specific_kind
45
+ @kind unless @kind.is_a?(Array)
46
+ end
47
+
48
+ def union_kind
49
+ @kind if @kind.is_a?(Array)
50
+ end
51
+ end
52
+
53
+ class NodeField < Field
54
+ def initialize(kind:, **options)
55
+ @kind = kind
56
+ super(**options)
57
+ end
58
+
59
+ def c_type
60
+ if specific_kind
61
+ "struct AST_#{specific_kind.gsub(/(?<=[a-zA-Z])(?=[A-Z][a-z])/, "_").upcase}_STRUCT*"
62
+ else
63
+ "AST_NODE_T*"
64
+ end
65
+ end
66
+
67
+ def ruby_type
68
+ "Herb::AST::#{specific_kind || "Node"}"
69
+ end
70
+
71
+ def specific_kind
72
+ @kind unless @kind.is_a?(Array)
73
+ end
74
+
75
+ def union_kind
76
+ @kind if @kind.is_a?(Array)
77
+ end
78
+ end
79
+
80
+ class TokenField < Field
81
+ def ruby_type
82
+ "Herb::Token"
83
+ end
84
+
85
+ def c_type
86
+ "token_T*"
87
+ end
88
+ end
89
+
90
+ class TokenTypeField < Field
91
+ def ruby_type
92
+ "String"
93
+ end
94
+
95
+ def c_type
96
+ "token_type_T"
97
+ end
98
+ end
99
+
100
+ class StringField < Field
101
+ def ruby_type
102
+ "String"
103
+ end
104
+
105
+ def c_type
106
+ "const char*"
107
+ end
108
+ end
109
+
110
+ class PositionField < Field
111
+ def ruby_type
112
+ "Herb::Position"
113
+ end
114
+
115
+ def c_type
116
+ "position_T*"
117
+ end
118
+ end
119
+
120
+ class IntegerField < Field
121
+ def ruby_type
122
+ "Integer"
123
+ end
124
+
125
+ def c_type
126
+ "const int"
127
+ end
128
+ end
129
+
130
+ class SizeTField < Field
131
+ def ruby_type
132
+ "Integer"
133
+ end
134
+
135
+ def c_type
136
+ "size_t"
137
+ end
138
+ end
139
+
140
+ class BooleanField < Field
141
+ def ruby_type
142
+ "bool"
143
+ end
144
+
145
+ def c_type
146
+ "bool"
147
+ end
148
+ end
149
+
150
+ class PrismNodeField < Field
151
+ def ruby_type
152
+ "Prism::Node"
153
+ end
154
+
155
+ def c_type
156
+ "pm_node_t*"
157
+ end
158
+ end
159
+
160
+ class VoidPointerField < Field
161
+ def ruby_type
162
+ "nil"
163
+ end
164
+
165
+ def c_type
166
+ "void*"
167
+ end
168
+ end
169
+
170
+ class AnalyzedRubyField < Field
171
+ def ruby_type
172
+ "nil"
173
+ end
174
+
175
+ def c_type
176
+ "analyzed_ruby_T*"
177
+ end
178
+ end
179
+
180
+ class ElementSourceField < Field
181
+ def ruby_type
182
+ "String"
183
+ end
184
+
185
+ def c_type
186
+ "element_source_t"
187
+ end
188
+ end
189
+
190
+ module ConfigType
191
+ private
192
+
193
+ def normalize_kind(kind, type, name, field_name)
194
+ if kind
195
+ kind = [kind] unless kind.is_a?(Array)
196
+
197
+ kind = kind.first if kind.size == 1
198
+ elsif type < NodeField
199
+ raise "Missing kind in config.yml for field #{name}##{field_name}"
200
+ end
201
+
202
+ kind
203
+ end
204
+
205
+ def field_type_for(name)
206
+ case name
207
+ when "array" then ArrayField
208
+ when "node" then NodeField
209
+ when "token" then TokenField
210
+ when "token_type" then TokenTypeField
211
+ when "string" then StringField
212
+ when "position" then PositionField
213
+ when "size_t" then SizeTField
214
+ when "boolean" then BooleanField
215
+ when "prism_node" then PrismNodeField
216
+ when "analyzed_ruby" then AnalyzedRubyField
217
+ when "element_source" then ElementSourceField
218
+ when "void*" then VoidPointerField
219
+ else raise("Unknown field type: #{name.inspect}")
220
+ end
221
+ end
222
+ end
223
+
224
+ class ErrorType
225
+ include ConfigType
226
+
227
+ attr_reader :name, :type, :struct_type, :struct_name, :human, :fields, :message_template, :message_arguments
228
+
229
+ def initialize(config)
230
+ @name = config.fetch("name")
231
+ @message_template = config.dig("message", "template")
232
+ @message_arguments = config.dig("message", "arguments")
233
+
234
+ camelized = @name.gsub(/(?<=[a-zA-Z])(?=[A-Z][a-z])/, "_")
235
+ @type = camelized.upcase
236
+ @struct_type = "#{camelized.upcase}_T"
237
+ @struct_name = "#{camelized.upcase}_STRUCT"
238
+ @human = camelized.downcase
239
+
240
+ @fields = config.fetch("fields", []).map do |field|
241
+ field_name = field.fetch("name")
242
+ type = field_type_for(field.fetch("type"))
243
+ kind = normalize_kind(field.fetch("kind", nil), type, @name, field_name)
244
+
245
+ type.new(name: field_name, kind: kind)
246
+ end
247
+ end
248
+ end
249
+
250
+ class NodeType
251
+ include ConfigType
252
+
253
+ attr_reader :name, :type, :struct_type, :struct_name, :human, :fields
254
+
255
+ def initialize(config)
256
+ @name = config.fetch("name")
257
+ camelized = @name.gsub(/(?<=[a-zA-Z])(?=[A-Z][a-z])/, "_")
258
+ @type = "AST_#{camelized.upcase}"
259
+ @struct_type = "AST_#{camelized.upcase}_T"
260
+ @struct_name = "AST_#{camelized.upcase}_STRUCT"
261
+ @human = camelized.downcase
262
+
263
+ @fields = config.fetch("fields", []).map do |field|
264
+ field_name = field.fetch("name")
265
+ type = field_type_for(field.fetch("type"))
266
+ kind = normalize_kind(field.fetch("kind", nil), type, @name, field_name)
267
+
268
+ type.new(name: field_name, kind: kind)
269
+ end
270
+ end
271
+ end
272
+
273
+ class PrintfMessageTemplate
274
+ MAX_STRING_SIZE = 128
275
+
276
+ # Estimated sizes for different format specifiers
277
+ ESTIMATED_SIZES = {
278
+ "%s" => MAX_STRING_SIZE, # Strings are truncated
279
+ "%d" => 11, # INT_MAX is 10 digits + sign
280
+ "%u" => 10, # UINT_MAX fits in 10 digits
281
+ "%zu" => 20, # Large enough for size_t
282
+ "%llu" => 20, # Large enough for long long unsigned
283
+ "%ld" => 20, # Large enough for long int
284
+ "%f" => 32, # Floating point with precision
285
+ "%lf" => 32, # Long double
286
+ }.freeze
287
+
288
+ def self.estimate_buffer_size(template)
289
+ base_length = template.length
290
+ total_size = base_length
291
+
292
+ format_specifiers = template.scan(/%[sdulfz]/)
293
+
294
+ format_specifiers.each_with_index do |specifier, _i|
295
+ estimated_size = ESTIMATED_SIZES[specifier] || 16 # Default extra buffer
296
+ total_size += estimated_size
297
+ end
298
+
299
+ total_size += 1 # Null terminator
300
+ total_size
301
+ end
302
+ end
303
+
304
+ def self.heading_for(file, template_file)
305
+ case File.extname(file)
306
+ when ".rb", ".rbs"
307
+ <<~HEADING
308
+ # frozen_string_literal: true
309
+ # typed: true
310
+
311
+ # NOTE: This file is generated by the templates/template.rb script and should not be
312
+ # modified manually. See #{template_file}
313
+
314
+ HEADING
315
+ else
316
+ <<~HEADING
317
+ // NOTE: This file is generated by the templates/template.rb script and should not
318
+ // be modified manually. See #{template_file}
319
+
320
+ HEADING
321
+ end
322
+ end
323
+
324
+ def self.check_gitignore(name)
325
+ file = Pathname.new(name)
326
+ file = file.absolute? ? file.relative_path_from(File.expand_path("../", __dir__)).to_s : file.to_s
327
+ return if gitignore_lines.include?(file)
328
+
329
+ puts "[WARNING]: make sure to add `#{file}` to the `.gitignore`"
330
+ puts
331
+ end
332
+
333
+ def self.render(template_file)
334
+ name = Pathname.new(template_file)
335
+ name = if name.absolute?
336
+ template_file.gsub(
337
+ "#{__dir__}/",
338
+ __dir__.delete_suffix("templates").to_s
339
+ )
340
+ else
341
+ name.to_s.delete_prefix("templates/")
342
+ end
343
+
344
+ name = name.delete_suffix(".erb")
345
+
346
+ destination = if Pathname.new(name).absolute?
347
+ Pathname.new(name)
348
+ else
349
+ Pathname.new(
350
+ File.expand_path("../#{name}", __dir__)
351
+ )
352
+ end
353
+
354
+ puts "Rendering #{template_file.delete_prefix("#{File.expand_path("../", __dir__)}/")} → #{destination}"
355
+
356
+ template_file = Pathname.new(template_file)
357
+ template_path = if template_file.absolute?
358
+ template_file
359
+ else
360
+ Pathname(
361
+ File.expand_path("../#{template_file}", __dir__)
362
+ )
363
+ end
364
+
365
+ rendered_template = read_template(template_path.to_s).result_with_hash({ nodes: nodes, errors: errors })
366
+ content = heading_for(name, template_file) + rendered_template
367
+
368
+ check_gitignore(name)
369
+
370
+ FileUtils.mkdir_p(File.dirname(destination))
371
+ File.write(destination, content)
372
+ rescue SyntaxError => e
373
+ puts
374
+ puts "Error while rendering #{template_file}:"
375
+ puts e
376
+ puts
377
+ end
378
+
379
+ def self.read_template(path)
380
+ content = File.read(path, encoding: Encoding::UTF_8)
381
+
382
+ ERB.new(content, trim_mode: "-").tap do |erb|
383
+ erb.filename = path
384
+ end
385
+ end
386
+
387
+ def self.gitignore_lines
388
+ @gitignore_lines ||= File.readlines(".gitignore").map(&:chomp)
389
+ rescue Errno::ENOENT
390
+ puts "[Herb Templates] Couldn't find .gitignore"
391
+ []
392
+ end
393
+
394
+ def self.nodes
395
+ (config.dig("nodes", "types") || []).map { |node| NodeType.new(node) }
396
+ end
397
+
398
+ def self.errors
399
+ (config.dig("errors", "types") || []).map { |node| ErrorType.new(node) }
400
+ end
401
+
402
+ def self.config
403
+ YAML.load_file("config.yml")
404
+ end
405
+ end
406
+ end
@@ -0,0 +1,93 @@
1
+ #include <emscripten/bind.h>
2
+ #include <emscripten/val.h>
3
+
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+
8
+ #include "extension_helpers.h"
9
+
10
+ extern "C" {
11
+ #include "../src/include/herb.h"
12
+ #include "../src/include/token.h"
13
+ #include "../src/include/array.h"
14
+ #include "../src/include/errors.h"
15
+ #include "../src/include/ast_node.h"
16
+ #include "../src/include/ast_nodes.h"
17
+ }
18
+
19
+ using namespace emscripten;
20
+
21
+ val CreateLocation(location_T* location);
22
+ val CreateToken(token_T* token);
23
+ val NodeFromCStruct(AST_NODE_T* node);
24
+ val NodesArrayFromCArray(array_T* array);
25
+ val ErrorFromCStruct(ERROR_T* error);
26
+ val ErrorsArrayFromCArray(array_T* array);
27
+
28
+ <%- errors.each do |error| -%>
29
+ val <%= error.name %>FromCStruct(<%= error.struct_type %>* <%= error.human %>) {
30
+ if (!<%= error.human %>) {
31
+ return val::null();
32
+ }
33
+
34
+ val Object = val::global("Object");
35
+ val result = Object.new_();
36
+
37
+ result.set("type", CreateString(error_type_to_string(&<%= error.human %>->base)));
38
+ result.set("message", CreateString(<%= error.human %>->base.message));
39
+ result.set("location", CreateLocation(<%= error.human %>->base.location));
40
+ <%- error.fields.each do |field| -%>
41
+ <%- case field -%>
42
+ <%- when Herb::Template::StringField -%>
43
+ result.set("<%= field.name %>", CreateString(<%= error.human %>-><%= field.name %>));
44
+ <%- when Herb::Template::NodeField -%>
45
+ result.set("<%= field.name %>", NodeFromCStruct((AST_NODE_T*)<%= error.human %>-><%= field.name %>));
46
+ <%- when Herb::Template::TokenField -%>
47
+ result.set("<%= field.name %>", CreateToken(<%= error.human %>-><%= field.name %>));
48
+ <%- when Herb::Template::TokenTypeField -%>
49
+ result.set("<%= field.name %>", CreateString(token_type_to_string(<%= error.human %>-><%= field.name %>)));
50
+ <%- when Herb::Template::BooleanField -%>
51
+ result.set("<%= field.name %>", <%= error.human %>-><%= field.name %>);
52
+ <%- when Herb::Template::ArrayField -%>
53
+ result.set("<%= field.name %>", NodesArrayFromCArray(<%= error.human %>-><%= field.name %>));
54
+ <%- else -%>
55
+ result.set("<%= field.name %>", val::null());
56
+ <%- end -%>
57
+ <%- end -%>
58
+
59
+ return result;
60
+ }
61
+
62
+ <%- end -%>
63
+
64
+ val ErrorsArrayFromCArray(array_T* array) {
65
+ val Array = val::global("Array");
66
+ val result = Array.new_();
67
+
68
+ if (array) {
69
+ for (size_t i = 0; i < array_size(array); i++) {
70
+ ERROR_T* error = (ERROR_T*)array_get(array, i);
71
+ if (error) {
72
+ result.call<void>("push", ErrorFromCStruct(error));
73
+ }
74
+ }
75
+ }
76
+
77
+ return result;
78
+ }
79
+
80
+ val ErrorFromCStruct(ERROR_T* error) {
81
+ if (!error) {
82
+ return val::null();
83
+ }
84
+
85
+ switch (error->type) {
86
+ <%- errors.each do |error| -%>
87
+ case <%= error.type %>:
88
+ return <%= error.name %>FromCStruct((<%= error.struct_type %>*)error);
89
+ <%- end -%>
90
+ default:
91
+ return val::null();
92
+ }
93
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef HERB_EXTENSION_ERRORS_H
2
+ #define HERB_EXTENSION_ERRORS_H
3
+
4
+ extern "C" {
5
+ #include "../src/include/herb.h"
6
+ }
7
+
8
+ emscripten::val ErrorFromCStruct(ERROR_T* error);
9
+ emscripten::val ErrorsArrayFromCArray(array_T* array);
10
+
11
+ <%- errors.each do |error| -%>
12
+ emscripten::val <%= error.name %>FromCStruct(<%= error.struct_type %>* <%= error.human %>);
13
+ <%- end -%>
14
+
15
+ #endif
@@ -0,0 +1,79 @@
1
+ #include <emscripten/bind.h>
2
+ #include <emscripten/val.h>
3
+
4
+ #include "error_helpers.h"
5
+ #include "extension_helpers.h"
6
+
7
+ #include "../src/include/herb.h"
8
+ #include "../src/include/token.h"
9
+ #include "../src/include/array.h"
10
+ #include "../src/include/ast_node.h"
11
+ #include "../src/include/ast_nodes.h"
12
+ #include "../src/include/location.h"
13
+
14
+ using namespace emscripten;
15
+
16
+ val NodeFromCStruct(AST_NODE_T* node);
17
+ val NodesArrayFromCArray(array_T* array);
18
+
19
+ <%- nodes.each do |node| -%>
20
+ val <%= node.name %>FromCStruct(<%= node.struct_type %>* <%= node.human %>) {
21
+ if (!<%= node.human %>) return val::null();
22
+
23
+ val result = val::object();
24
+ result.set("type", CreateString(ast_node_type_to_string(&<%= node.human %>->base)));
25
+ result.set("location", CreateLocation(<%= node.human %>->base.location));
26
+ result.set("errors", ErrorsArrayFromCArray(<%= node.human %>->base.errors));
27
+
28
+ <%- node.fields.each do |field| -%>
29
+ <%- case field -%>
30
+ <%- when Herb::Template::StringField -%>
31
+ result.set("<%= field.name %>", CreateString(<%= node.human %>-><%= field.name %>));
32
+ <%- when Herb::Template::NodeField -%>
33
+ result.set("<%= field.name %>", NodeFromCStruct((AST_NODE_T*) <%= node.human %>-><%= field.name %>));
34
+ <%- when Herb::Template::TokenField -%>
35
+ result.set("<%= field.name %>", CreateToken(<%= node.human %>-><%= field.name %>));
36
+ <%- when Herb::Template::BooleanField -%>
37
+ result.set("<%= field.name %>", <%= node.human %>-><%= field.name %> ? true : false);
38
+ <%- when Herb::Template::ArrayField -%>
39
+ result.set("<%= field.name %>", NodesArrayFromCArray(<%= node.human %>-><%= field.name %>));
40
+ <%- when Herb::Template::ElementSourceField -%>
41
+ result.set("<%= field.name %>", CreateString(element_source_to_string(<%= node.human %>-><%= field.name %>)));
42
+ <%- else -%>
43
+ result.set("<%= field.name %>", val::null());
44
+ <%- end -%>
45
+ <%- end -%>
46
+
47
+ return result;
48
+ }
49
+
50
+ <%- end -%>
51
+
52
+ val NodeFromCStruct(AST_NODE_T* node) {
53
+ if (!node) return val::null();
54
+
55
+ switch (node->type) {
56
+ <%- nodes.each do |node| -%>
57
+ case <%= node.type %>:
58
+ return <%= node.name %>FromCStruct((<%= node.struct_type %>*) node);
59
+ <%- end -%>
60
+ default:
61
+ return val::null();
62
+ }
63
+ }
64
+
65
+ val NodesArrayFromCArray(array_T* array) {
66
+ if (!array) return val::null();
67
+
68
+ val jsArray = val::array();
69
+
70
+ for (size_t i = 0; i < array_size(array); i++) {
71
+ AST_NODE_T* child_node = (AST_NODE_T*) array_get(array, i);
72
+
73
+ if (child_node) {
74
+ jsArray.set(i, NodeFromCStruct(child_node));
75
+ }
76
+ }
77
+
78
+ return jsArray;
79
+ }
@@ -0,0 +1,15 @@
1
+ #ifndef HERB_EXTENSION_NODES_H
2
+ #define HERB_EXTENSION_NODES_H
3
+
4
+ extern "C" {
5
+ #include "../src/include/herb.h"
6
+ }
7
+
8
+ emscripten::val NodeFromCStruct(AST_NODE_T* node);
9
+ emscripten::val NodesArrayFromCArray(array_T* array);
10
+
11
+ <%- nodes.each do |node| -%>
12
+ emscripten::val <%= node.human %>NodeFromCStruct(<%= node.struct_type %>* <%= node.human %>);
13
+ <%- end -%>
14
+
15
+ #endif
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/clean"
5
+
6
+ task default: %i[compile test]
7
+
8
+ require_relative "templates/template"
9
+
10
+ desc "Generate all ERB template based files"
11
+ task templates: Prism::Template::TEMPLATES
12
+
13
+ make = RUBY_PLATFORM.match?(/openbsd|freebsd/) ? "gmake" : "make"
14
+ task(make: :templates) { sh(make) }
15
+ task(make_no_debug: :templates) { sh("#{make} all-no-debug") }
16
+ task(make_minimal: :templates) { sh("#{make} minimal") }
17
+
18
+ task compile: :make
19
+ task compile_no_debug: %i[make_no_debug compile]
20
+ task compile_minimal: %i[make_minimal compile]
21
+
22
+ # decorate the gem build task with prerequisites
23
+ task build: [:check_manifest, :templates]
24
+
25
+ # the C extension
26
+ task "compile:prism" => ["templates"] # must be before the ExtensionTask is created
27
+
28
+ if RUBY_ENGINE == "ruby" and !ENV["PRISM_FFI_BACKEND"]
29
+ require "rake/extensiontask"
30
+
31
+ Rake::ExtensionTask.new(:compile) do |ext|
32
+ ext.name = "prism"
33
+ ext.ext_dir = "ext/prism"
34
+ ext.lib_dir = "lib/prism"
35
+ ext.gem_spec = Gem::Specification.load("prism.gemspec")
36
+ end
37
+ elsif RUBY_ENGINE == "jruby"
38
+ require "rake/javaextensiontask"
39
+
40
+ # This compiles java to make sure any templating changes produces valid code.
41
+ Rake::JavaExtensionTask.new(:compile) do |ext|
42
+ ext.name = "prism"
43
+ ext.ext_dir = "java"
44
+ ext.lib_dir = "tmp"
45
+ ext.source_version = "1.8"
46
+ ext.target_version = "1.8"
47
+ ext.gem_spec = Gem::Specification.load("prism.gemspec")
48
+ end
49
+ end
50
+
51
+ # So `rake clobber` will delete generated files
52
+ CLOBBER.concat(Prism::Template::TEMPLATES)
53
+ CLOBBER.concat(["build"])
54
+ CLOBBER << "lib/prism/prism.#{RbConfig::CONFIG["DLEXT"]}"
55
+
56
+ Prism::Template::TEMPLATES.each do |filepath|
57
+ desc "Generate #{filepath}"
58
+ file filepath => ["templates/#{filepath}.erb", "templates/template.rb", "config.yml"] do |t|
59
+ Prism::Template.render(t.name)
60
+ end
61
+ end
62
+
63
+ namespace :build do
64
+ task :dev_version_set do
65
+ filepath = File.expand_path("prism.gemspec", __dir__)
66
+ File.write(filepath, File.read(filepath).sub(/spec\.version = ".+?"/, %Q{spec.version = "9999.9.9"}))
67
+ end
68
+
69
+ task :dev_version_clear do
70
+ sh "git checkout -- prism.gemspec Gemfile.lock"
71
+ end
72
+
73
+ desc "Build a development version of the gem"
74
+ task dev: ["build:dev_version_set", "build", "build:dev_version_clear"]
75
+ end