herb 0.7.1-arm64-darwin → 0.7.3-arm64-darwin

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 (137) 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/error_helpers.c +27 -27
  7. data/ext/herb/extconf.rb +2 -1
  8. data/ext/herb/extension.c +6 -6
  9. data/ext/herb/extension_helpers.c +3 -3
  10. data/ext/herb/nodes.c +35 -35
  11. data/herb.gemspec +3 -0
  12. data/lib/herb/3.0/herb.bundle +0 -0
  13. data/lib/herb/3.1/herb.bundle +0 -0
  14. data/lib/herb/3.2/herb.bundle +0 -0
  15. data/lib/herb/3.3/herb.bundle +0 -0
  16. data/lib/herb/3.4/herb.bundle +0 -0
  17. data/lib/herb/engine/debug_visitor.rb +41 -21
  18. data/lib/herb/engine.rb +20 -6
  19. data/lib/herb/version.rb +1 -1
  20. data/sig/herb/engine/debug_visitor.rbs +3 -3
  21. data/sig/herb/engine.rbs +5 -0
  22. data/src/analyze.c +5 -9
  23. data/src/analyze_helpers.c +17 -6
  24. data/src/include/pretty_print.h +1 -1
  25. data/src/include/version.h +1 -1
  26. data/src/parser.c +6 -9
  27. data/src/pretty_print.c +1 -1
  28. data/templates/ext/herb/error_helpers.c.erb +85 -0
  29. data/templates/ext/herb/error_helpers.h.erb +12 -0
  30. data/templates/ext/herb/nodes.c.erb +90 -0
  31. data/templates/ext/herb/nodes.h.erb +9 -0
  32. data/templates/javascript/packages/core/src/errors.ts.erb +193 -0
  33. data/templates/javascript/packages/core/src/node-type-guards.ts.erb +325 -0
  34. data/templates/javascript/packages/core/src/nodes.ts.erb +414 -0
  35. data/templates/javascript/packages/core/src/visitor.ts.erb +29 -0
  36. data/templates/javascript/packages/node/extension/error_helpers.cpp.erb +113 -0
  37. data/templates/javascript/packages/node/extension/error_helpers.h.erb +17 -0
  38. data/templates/javascript/packages/node/extension/nodes.cpp.erb +111 -0
  39. data/templates/javascript/packages/node/extension/nodes.h.erb +17 -0
  40. data/templates/lib/herb/ast/nodes.rb.erb +117 -0
  41. data/templates/lib/herb/errors.rb.erb +106 -0
  42. data/templates/lib/herb/visitor.rb.erb +28 -0
  43. data/templates/sig/serialized_ast_errors.rbs.erb +10 -0
  44. data/templates/sig/serialized_ast_nodes.rbs.erb +10 -0
  45. data/templates/src/ast_nodes.c.erb +145 -0
  46. data/templates/src/ast_pretty_print.c.erb +97 -0
  47. data/templates/src/errors.c.erb +245 -0
  48. data/templates/src/include/ast_nodes.h.erb +46 -0
  49. data/templates/src/include/ast_pretty_print.h.erb +14 -0
  50. data/templates/src/include/errors.h.erb +58 -0
  51. data/templates/src/visitor.c.erb +47 -0
  52. data/templates/template.rb +406 -0
  53. data/templates/wasm/error_helpers.cpp.erb +93 -0
  54. data/templates/wasm/error_helpers.h.erb +15 -0
  55. data/templates/wasm/nodes.cpp.erb +79 -0
  56. data/templates/wasm/nodes.h.erb +15 -0
  57. data/vendor/prism/Rakefile +75 -0
  58. data/vendor/prism/config.yml +4713 -0
  59. data/vendor/prism/include/prism/ast.h +8190 -0
  60. data/vendor/prism/include/prism/defines.h +260 -0
  61. data/vendor/prism/include/prism/diagnostic.h +455 -0
  62. data/vendor/prism/include/prism/encoding.h +283 -0
  63. data/vendor/prism/include/prism/node.h +129 -0
  64. data/vendor/prism/include/prism/options.h +482 -0
  65. data/vendor/prism/include/prism/pack.h +163 -0
  66. data/vendor/prism/include/prism/parser.h +933 -0
  67. data/vendor/prism/include/prism/prettyprint.h +34 -0
  68. data/vendor/prism/include/prism/regexp.h +43 -0
  69. data/vendor/prism/include/prism/static_literals.h +121 -0
  70. data/vendor/prism/include/prism/util/pm_buffer.h +236 -0
  71. data/vendor/prism/include/prism/util/pm_char.h +204 -0
  72. data/vendor/prism/include/prism/util/pm_constant_pool.h +218 -0
  73. data/vendor/prism/include/prism/util/pm_integer.h +130 -0
  74. data/vendor/prism/include/prism/util/pm_list.h +103 -0
  75. data/vendor/prism/include/prism/util/pm_memchr.h +29 -0
  76. data/vendor/prism/include/prism/util/pm_newline_list.h +113 -0
  77. data/vendor/prism/include/prism/util/pm_string.h +200 -0
  78. data/vendor/prism/include/prism/util/pm_strncasecmp.h +32 -0
  79. data/vendor/prism/include/prism/util/pm_strpbrk.h +46 -0
  80. data/vendor/prism/include/prism/version.h +29 -0
  81. data/vendor/prism/include/prism.h +408 -0
  82. data/vendor/prism/src/diagnostic.c +848 -0
  83. data/vendor/prism/src/encoding.c +5235 -0
  84. data/vendor/prism/src/node.c +8676 -0
  85. data/vendor/prism/src/options.c +328 -0
  86. data/vendor/prism/src/pack.c +509 -0
  87. data/vendor/prism/src/prettyprint.c +8941 -0
  88. data/vendor/prism/src/prism.c +23302 -0
  89. data/vendor/prism/src/regexp.c +790 -0
  90. data/vendor/prism/src/serialize.c +2268 -0
  91. data/vendor/prism/src/static_literals.c +617 -0
  92. data/vendor/prism/src/token_type.c +703 -0
  93. data/vendor/prism/src/util/pm_buffer.c +357 -0
  94. data/vendor/prism/src/util/pm_char.c +318 -0
  95. data/vendor/prism/src/util/pm_constant_pool.c +342 -0
  96. data/vendor/prism/src/util/pm_integer.c +670 -0
  97. data/vendor/prism/src/util/pm_list.c +49 -0
  98. data/vendor/prism/src/util/pm_memchr.c +35 -0
  99. data/vendor/prism/src/util/pm_newline_list.c +125 -0
  100. data/vendor/prism/src/util/pm_string.c +383 -0
  101. data/vendor/prism/src/util/pm_strncasecmp.c +36 -0
  102. data/vendor/prism/src/util/pm_strpbrk.c +206 -0
  103. data/vendor/prism/templates/ext/prism/api_node.c.erb +282 -0
  104. data/vendor/prism/templates/include/prism/ast.h.erb +226 -0
  105. data/vendor/prism/templates/include/prism/diagnostic.h.erb +130 -0
  106. data/vendor/prism/templates/java/org/prism/AbstractNodeVisitor.java.erb +22 -0
  107. data/vendor/prism/templates/java/org/prism/Loader.java.erb +434 -0
  108. data/vendor/prism/templates/java/org/prism/Nodes.java.erb +403 -0
  109. data/vendor/prism/templates/javascript/src/deserialize.js.erb +448 -0
  110. data/vendor/prism/templates/javascript/src/nodes.js.erb +197 -0
  111. data/vendor/prism/templates/javascript/src/visitor.js.erb +78 -0
  112. data/vendor/prism/templates/lib/prism/compiler.rb.erb +43 -0
  113. data/vendor/prism/templates/lib/prism/dispatcher.rb.erb +103 -0
  114. data/vendor/prism/templates/lib/prism/dot_visitor.rb.erb +189 -0
  115. data/vendor/prism/templates/lib/prism/dsl.rb.erb +133 -0
  116. data/vendor/prism/templates/lib/prism/inspect_visitor.rb.erb +131 -0
  117. data/vendor/prism/templates/lib/prism/mutation_compiler.rb.erb +19 -0
  118. data/vendor/prism/templates/lib/prism/node.rb.erb +515 -0
  119. data/vendor/prism/templates/lib/prism/reflection.rb.erb +136 -0
  120. data/vendor/prism/templates/lib/prism/serialize.rb.erb +602 -0
  121. data/vendor/prism/templates/lib/prism/visitor.rb.erb +55 -0
  122. data/vendor/prism/templates/rbi/prism/dsl.rbi.erb +68 -0
  123. data/vendor/prism/templates/rbi/prism/node.rbi.erb +164 -0
  124. data/vendor/prism/templates/rbi/prism/visitor.rbi.erb +18 -0
  125. data/vendor/prism/templates/sig/prism/_private/dot_visitor.rbs.erb +45 -0
  126. data/vendor/prism/templates/sig/prism/dsl.rbs.erb +31 -0
  127. data/vendor/prism/templates/sig/prism/mutation_compiler.rbs.erb +7 -0
  128. data/vendor/prism/templates/sig/prism/node.rbs.erb +132 -0
  129. data/vendor/prism/templates/sig/prism/visitor.rbs.erb +17 -0
  130. data/vendor/prism/templates/sig/prism.rbs.erb +89 -0
  131. data/vendor/prism/templates/src/diagnostic.c.erb +523 -0
  132. data/vendor/prism/templates/src/node.c.erb +333 -0
  133. data/vendor/prism/templates/src/prettyprint.c.erb +166 -0
  134. data/vendor/prism/templates/src/serialize.c.erb +406 -0
  135. data/vendor/prism/templates/src/token_type.c.erb +369 -0
  136. data/vendor/prism/templates/template.rb +689 -0
  137. metadata +112 -2
data/lib/herb/engine.rb CHANGED
@@ -17,7 +17,7 @@ require_relative "engine/validators/accessibility_validator"
17
17
  module Herb
18
18
  class Engine
19
19
  attr_reader :src, :filename, :project_path, :relative_file_path, :bufvar, :debug, :content_for_head,
20
- :validation_error_template
20
+ :validation_error_template, :visitors
21
21
 
22
22
  ESCAPE_TABLE = {
23
23
  "&" => "&",
@@ -51,6 +51,16 @@ module Herb
51
51
  @content_for_head = properties[:content_for_head]
52
52
  @validation_error_template = nil
53
53
  @validation_mode = properties.fetch(:validation_mode, :raise)
54
+ @visitors = properties.fetch(:visitors, default_visitors)
55
+
56
+ if @debug && @visitors.empty?
57
+ debug_visitor = DebugVisitor.new(
58
+ file_path: @filename,
59
+ project_path: @project_path
60
+ )
61
+
62
+ @visitors << debug_visitor
63
+ end
54
64
 
55
65
  unless [:raise, :overlay, :none].include?(@validation_mode)
56
66
  raise ArgumentError,
@@ -109,12 +119,12 @@ module Herb
109
119
 
110
120
  add_validation_overlay(validation_errors, input) if @validation_mode == :overlay && validation_errors&.any?
111
121
 
112
- if @debug
113
- debug_visitor = DebugVisitor.new(self)
114
- ast.accept(debug_visitor)
122
+ @visitors.each do |visitor|
123
+ ast.accept(visitor)
115
124
  end
116
125
 
117
126
  compiler = Compiler.new(self, properties)
127
+
118
128
  ast.accept(compiler)
119
129
 
120
130
  compiler.generate_output
@@ -359,8 +369,12 @@ module Herb
359
369
  )
360
370
 
361
371
  error_html = overlay_generator.generate_html
362
- escaped_html = error_html.gsub("'", "\\'")
363
- @validation_error_template = "<template data-herb-parser-error>#{escaped_html}</template>"
372
+ @validation_error_template = "<template data-herb-parser-error>#{error_html}</template>"
373
+ end
374
+
375
+ #: () -> Array[Herb::Visitor]
376
+ def default_visitors
377
+ []
364
378
  end
365
379
  end
366
380
  end
data/lib/herb/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # typed: true
3
3
 
4
4
  module Herb
5
- VERSION = "0.7.1"
5
+ VERSION = "0.7.3"
6
6
  end
@@ -3,9 +3,7 @@
3
3
  module Herb
4
4
  class Engine
5
5
  class DebugVisitor < Herb::Visitor
6
- def initialize: (untyped engine) -> untyped
7
-
8
- def debug_enabled?: () -> untyped
6
+ def initialize: (?file_path: untyped, ?project_path: untyped) -> untyped
9
7
 
10
8
  def visit_document_node: (untyped node) -> untyped
11
9
 
@@ -23,6 +21,8 @@ module Herb
23
21
 
24
22
  private
25
23
 
24
+ def calculate_relative_path: () -> untyped
25
+
26
26
  def wrap_all_erb_nodes: (untyped node) -> untyped
27
27
 
28
28
  # Creates a dummy location for AST nodes that don't need real location info
data/sig/herb/engine.rbs CHANGED
@@ -18,6 +18,8 @@ module Herb
18
18
 
19
19
  attr_reader validation_error_template: untyped
20
20
 
21
+ attr_reader visitors: untyped
22
+
21
23
  ESCAPE_TABLE: untyped
22
24
 
23
25
  class CompilationError < StandardError
@@ -68,5 +70,8 @@ module Herb
68
70
  def escape_attr: (untyped text) -> untyped
69
71
 
70
72
  def add_parser_error_overlay: (untyped parser_errors, untyped input) -> untyped
73
+
74
+ # : () -> Array[Herb::Visitor]
75
+ def default_visitors: () -> Array[Herb::Visitor]
71
76
  end
72
77
  end
data/src/analyze.c CHANGED
@@ -54,7 +54,7 @@ static bool analyze_erb_content(const AST_NODE_T* node, void* data) {
54
54
  if (strcmp(opening, "<%%") != 0 && strcmp(opening, "<%%=") != 0 && strcmp(opening, "<%#") != 0) {
55
55
  analyzed_ruby_T* analyzed = herb_analyze_ruby(erb_content_node->content->value);
56
56
 
57
- if (false) { pretty_print_analyed_ruby(analyzed, erb_content_node->content->value); }
57
+ if (false) { pretty_print_analyzed_ruby(analyzed, erb_content_node->content->value); }
58
58
 
59
59
  erb_content_node->parsed = true;
60
60
  erb_content_node->valid = analyzed->valid;
@@ -1107,7 +1107,8 @@ void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source
1107
1107
  char* extracted_ruby = herb_extract_ruby_with_semicolons(source);
1108
1108
 
1109
1109
  pm_parser_t parser;
1110
- pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), NULL);
1110
+ pm_options_t options = { 0, .partial_script = true };
1111
+ pm_parser_init(&parser, (const uint8_t*) extracted_ruby, strlen(extracted_ruby), &options);
1111
1112
 
1112
1113
  pm_node_t* root = pm_parse(&parser);
1113
1114
 
@@ -1115,16 +1116,11 @@ void herb_analyze_parse_errors(AST_DOCUMENT_NODE_T* document, const char* source
1115
1116
  error = (const pm_diagnostic_t*) error->node.next) {
1116
1117
 
1117
1118
  RUBY_PARSE_ERROR_T* parse_error = ruby_parse_error_from_prism_error(error, (AST_NODE_T*) document, source, &parser);
1118
-
1119
- // TODO: ideally this shouldn't be hard-coded
1120
- if (strcmp(parse_error->diagnostic_id, "invalid_yield") == 0) {
1121
- error_free((ERROR_T*) parse_error);
1122
- } else {
1123
- array_append(document->base.errors, parse_error);
1124
- }
1119
+ array_append(document->base.errors, parse_error);
1125
1120
  }
1126
1121
 
1127
1122
  pm_node_destroy(&parser, root);
1128
1123
  pm_parser_free(&parser);
1124
+ pm_options_free(&options);
1129
1125
  free(extracted_ruby);
1130
1126
  }
@@ -91,9 +91,12 @@ bool search_if_nodes(const pm_node_t* node, void* data) {
91
91
  if (node->type == PM_IF_NODE) {
92
92
  const pm_if_node_t* if_node = (const pm_if_node_t*) node;
93
93
 
94
- // Handle ternary
95
- if (if_node->if_keyword_loc.start != NULL && if_node->if_keyword_loc.end != NULL) {
94
+ bool has_if_keyword = if_node->if_keyword_loc.start != NULL && if_node->if_keyword_loc.end != NULL;
95
+ bool has_end_keyword = if_node->end_keyword_loc.start != NULL && if_node->end_keyword_loc.end != NULL;
96
+
97
+ if (has_if_keyword && has_end_keyword) {
96
98
  analyzed->has_if_node = true;
99
+
97
100
  return true;
98
101
  }
99
102
  }
@@ -198,12 +201,20 @@ bool search_unless_nodes(const pm_node_t* node, void* data) {
198
201
  analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
199
202
 
200
203
  if (node->type == PM_UNLESS_NODE) {
201
- analyzed->has_unless_node = true;
202
- return true;
203
- } else {
204
- pm_visit_child_nodes(node, search_unless_nodes, analyzed);
204
+ const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
205
+
206
+ bool has_if_keyword = unless_node->keyword_loc.start != NULL && unless_node->keyword_loc.end != NULL;
207
+ bool has_end_keyword = unless_node->end_keyword_loc.start != NULL && unless_node->end_keyword_loc.end != NULL;
208
+
209
+ if (has_if_keyword && has_end_keyword) {
210
+ analyzed->has_unless_node = true;
211
+
212
+ return true;
213
+ }
205
214
  }
206
215
 
216
+ pm_visit_child_nodes(node, search_unless_nodes, analyzed);
217
+
207
218
  return false;
208
219
  }
209
220
 
@@ -88,6 +88,6 @@ void pretty_print_array(
88
88
 
89
89
  void pretty_print_errors(AST_NODE_T* node, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer);
90
90
 
91
- void pretty_print_analyed_ruby(analyzed_ruby_T* analyzed, const char* source);
91
+ void pretty_print_analyzed_ruby(analyzed_ruby_T* analyzed, const char* source);
92
92
 
93
93
  #endif
@@ -1,6 +1,6 @@
1
1
  #ifndef HERB_VERSION_H
2
2
  #define HERB_VERSION_H
3
3
 
4
- #define HERB_VERSION "0.7.1"
4
+ #define HERB_VERSION "0.7.3"
5
5
 
6
6
  #endif
data/src/parser.c CHANGED
@@ -555,14 +555,12 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser
555
555
  return value;
556
556
  }
557
557
 
558
- token_T* token = parser_advance(parser);
559
-
560
558
  append_unexpected_error(
561
559
  "Unexpected Token",
562
560
  "TOKEN_IDENTIFIER, TOKEN_QUOTE, TOKEN_ERB_START",
563
- token_type_to_string(token->type),
564
- token->location->start,
565
- token->location->end,
561
+ token_type_to_string(parser->current_token->type),
562
+ parser->current_token->location->start,
563
+ parser->current_token->location->end,
566
564
  errors
567
565
  );
568
566
 
@@ -571,13 +569,11 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser
571
569
  children,
572
570
  NULL,
573
571
  false,
574
- token->location->start,
575
- token->location->end,
572
+ parser->current_token->location->start,
573
+ parser->current_token->location->end,
576
574
  errors
577
575
  );
578
576
 
579
- token_free(token);
580
-
581
577
  return value;
582
578
  }
583
579
 
@@ -1135,6 +1131,7 @@ static void parser_parse_in_data_state(parser_T* parser, array_T* children, arra
1135
1131
  parser,
1136
1132
  TOKEN_AMPERSAND,
1137
1133
  TOKEN_AT,
1134
+ TOKEN_BACKTICK,
1138
1135
  TOKEN_CHARACTER,
1139
1136
  TOKEN_COLON,
1140
1137
  TOKEN_DASH,
data/src/pretty_print.c CHANGED
@@ -254,7 +254,7 @@ void pretty_print_string_property(
254
254
  }
255
255
  }
256
256
 
257
- void pretty_print_analyed_ruby(analyzed_ruby_T* analyzed, const char* source) {
257
+ void pretty_print_analyzed_ruby(analyzed_ruby_T* analyzed, const char* source) {
258
258
  printf(
259
259
  "------------------------\nanalyzed (%p)\n------------------------\n%s\n------------------------\n if: %i\n "
260
260
  " elsif: %i\n else: %i\n end: %i\n block: %i\n block_closing: %i\n case: %i\n when: %i\n for: "
@@ -0,0 +1,85 @@
1
+ #include <ruby.h>
2
+
3
+ #include "extension.h"
4
+ #include "extension_helpers.h"
5
+ #include "error_helpers.h"
6
+
7
+ #include "../../src/include/errors.h"
8
+ #include "../../src/include/herb.h"
9
+ #include "../../src/include/token.h"
10
+
11
+ VALUE rb_error_from_c_struct(ERROR_T* error);
12
+
13
+ <%- errors.each do |error| -%>
14
+ static VALUE rb_<%= error.human %>_from_c_struct(<%= error.struct_type %>* <%= error.human %>) {
15
+ if (<%= error.human %> == NULL) { return Qnil; }
16
+
17
+ ERROR_T* error = &<%= error.human %>->base;
18
+
19
+ VALUE Herb = rb_define_module("Herb");
20
+ VALUE Errors = rb_define_module_under(Herb, "Errors");
21
+ VALUE Error = rb_define_class_under(Errors, "Error", rb_cObject);
22
+ VALUE <%= error.name %> = rb_define_class_under(Errors, "<%= error.name %>", Error);
23
+
24
+ VALUE type = rb_utf8_str_new_cstr(error_type_to_string(error));
25
+ VALUE location = rb_location_from_c_struct(error->location);
26
+ VALUE message = rb_utf8_str_new_cstr(error->message);
27
+
28
+ <%- error.fields.each do |field| -%>
29
+ <%- case field -%>
30
+ <%- when Herb::Template::PositionField -%>
31
+ VALUE <%= error.human %>_<%= field.name %> = rb_position_from_c_struct(<%= error.human %>-><%= field.name %>);
32
+ <%- when Herb::Template::TokenField -%>
33
+ VALUE <%= error.human %>_<%= field.name %> = rb_token_from_c_struct(<%= error.human %>-><%= field.name %>);
34
+ <%- when Herb::Template::TokenTypeField -%>
35
+ VALUE <%= error.human %>_<%= field.name %> = rb_utf8_str_new_cstr(token_type_to_string(<%= error.human %>-><%= field.name %>));
36
+ <%- when Herb::Template::StringField -%>
37
+ VALUE <%= error.human %>_<%= field.name %> = rb_utf8_str_new_cstr(<%= error.human %>-><%= field.name %>);
38
+ <%- else -%>
39
+ /* <%= field.inspect %> */
40
+ VALUE <%= error.human %>_<%= field.name %> = Qnil;
41
+ <%- end -%>
42
+ <%- end -%>
43
+
44
+ VALUE args[<%= 3 + error.fields.count %>] = {
45
+ type,
46
+ location,
47
+ message<% if error.fields.any? %>,<% end %>
48
+ <%- error.fields.each do |field| -%>
49
+ <%= error.human %>_<%= field.name %><% if error.fields.last != field %>,<% end %>
50
+ <%- end -%>
51
+ };
52
+
53
+ return rb_class_new_instance(<%= 3 + error.fields.count %>, args, <%= error.name %>);
54
+ };
55
+
56
+ <%- end -%>
57
+
58
+ VALUE rb_error_from_c_struct(ERROR_T* error) {
59
+ if (!error) { return Qnil; }
60
+
61
+ switch (error->type) {
62
+ <%- errors.each do |error| -%>
63
+ case <%= error.type %>: return rb_<%= error.human %>_from_c_struct((<%= error.struct_type %>*) error); break;
64
+ <%- end -%>
65
+ }
66
+
67
+ return Qnil;
68
+ }
69
+
70
+ VALUE rb_errors_array_from_c_array(array_T* array) {
71
+ VALUE rb_array = rb_ary_new();
72
+
73
+ if (array) {
74
+ for (size_t i = 0; i < array_size(array); i++) {
75
+ ERROR_T* child_node = (ERROR_T*) array_get(array, i);
76
+
77
+ if (child_node) {
78
+ VALUE rb_child = rb_error_from_c_struct(child_node);
79
+ rb_ary_push(rb_array, rb_child);
80
+ }
81
+ }
82
+ }
83
+
84
+ return rb_array;
85
+ }
@@ -0,0 +1,12 @@
1
+ #ifndef HERB_EXTENSION_ERROR_HELPERS_H
2
+ #define HERB_EXTENSION_ERROR_HELPERS_H
3
+
4
+ #include "../../src/include/errors.h"
5
+ #include "../../src/include/herb.h"
6
+
7
+ #include <ruby.h>
8
+
9
+ VALUE rb_error_from_c_struct(ERROR_T* error);
10
+ VALUE rb_errors_array_from_c_array(array_T* array);
11
+
12
+ #endif
@@ -0,0 +1,90 @@
1
+ #include <ruby.h>
2
+
3
+ #include "error_helpers.h"
4
+ #include "extension_helpers.h"
5
+ #include "extension.h"
6
+ #include "nodes.h"
7
+
8
+ #include "../../src/include/herb.h"
9
+ #include "../../src/include/token.h"
10
+
11
+ VALUE rb_node_from_c_struct(AST_NODE_T* node);
12
+ static VALUE rb_nodes_array_from_c_array(array_T* array);
13
+
14
+ <%- nodes.each do |node| -%>
15
+ static VALUE rb_<%= node.human %>_from_c_struct(<%= node.struct_type %>* <%= node.human %>) {
16
+ if (<%= node.human %> == NULL) { return Qnil; }
17
+
18
+ AST_NODE_T* node = &<%= node.human %>->base;
19
+
20
+ VALUE Herb = rb_define_module("Herb");
21
+ VALUE AST = rb_define_module_under(Herb, "AST");
22
+ VALUE Node = rb_define_class_under(AST, "Node", rb_cObject);
23
+ VALUE <%= node.name %> = rb_define_class_under(AST, "<%= node.name %>", Node);
24
+
25
+ VALUE type = rb_utf8_str_new_cstr(ast_node_type_to_string(node));
26
+ VALUE location = rb_location_from_c_struct(node->location);
27
+ VALUE errors = rb_errors_array_from_c_array(node->errors);
28
+
29
+ <%- node.fields.each do |field| -%>
30
+ <%- case field -%>
31
+ <%- when Herb::Template::StringField -%>
32
+ VALUE <%= node.human %>_<%= field.name %> = rb_utf8_str_new_cstr(<%= node.human %>-><%= field.name %>);
33
+ <%- when Herb::Template::NodeField -%>
34
+ VALUE <%= node.human %>_<%= field.name %> = rb_node_from_c_struct((AST_NODE_T*) <%= node.human %>-><%= field.name %>);
35
+ <%- when Herb::Template::TokenField -%>
36
+ VALUE <%= node.human %>_<%= field.name %> = rb_token_from_c_struct(<%= node.human %>-><%= field.name %>);
37
+ <%- when Herb::Template::BooleanField -%>
38
+ VALUE <%= node.human %>_<%= field.name %> = (<%= node.human %>-><%= field.name %>) ? Qtrue : Qfalse;
39
+ <%- when Herb::Template::ArrayField -%>
40
+ VALUE <%= node.human %>_<%= field.name %> = rb_nodes_array_from_c_array(<%= node.human %>-><%= field.name %>);
41
+ <%- when Herb::Template::ElementSourceField -%>
42
+ VALUE <%= node.human %>_<%= field.name %> = rb_utf8_str_new_cstr(element_source_to_string(<%= node.human %>-><%= field.name %>));
43
+ <%- else -%>
44
+ /* <%= field.inspect %> */
45
+ VALUE <%= node.human %>_<%= field.name %> = Qnil;
46
+ <%- end -%>
47
+ <%- end -%>
48
+
49
+ VALUE args[<%= 3 + node.fields.count %>] = {
50
+ type,
51
+ location,
52
+ errors<% if node.fields.any? %>,<% end %>
53
+ <%- node.fields.each do |field| -%>
54
+ <%= node.human %>_<%= field.name %><% if node.fields.last != field %>,<% end %>
55
+ <%- end -%>
56
+ };
57
+
58
+ return rb_class_new_instance(<%= 3 + node.fields.count %>, args, <%= node.name %>);
59
+ };
60
+
61
+ <%- end -%>
62
+
63
+ VALUE rb_node_from_c_struct(AST_NODE_T* node) {
64
+ if (!node) { return Qnil; }
65
+
66
+ switch (node->type) {
67
+ <%- nodes.each do |node| -%>
68
+ case <%= node.type %>: return rb_<%= node.human %>_from_c_struct((<%= node.struct_type %>*) node); break;
69
+ <%- end -%>
70
+ }
71
+
72
+ return Qnil;
73
+ }
74
+
75
+ static VALUE rb_nodes_array_from_c_array(array_T* array) {
76
+ VALUE rb_array = rb_ary_new();
77
+
78
+ if (array) {
79
+ for (size_t i = 0; i < array_size(array); i++) {
80
+ AST_NODE_T* child_node = (AST_NODE_T*) array_get(array, i);
81
+
82
+ if (child_node) {
83
+ VALUE rb_child = rb_node_from_c_struct(child_node);
84
+ rb_ary_push(rb_array, rb_child);
85
+ }
86
+ }
87
+ }
88
+
89
+ return rb_array;
90
+ }
@@ -0,0 +1,9 @@
1
+ #ifndef HERB_EXTENSION_NODES_H
2
+ #define HERB_EXTENSION_NODES_H
3
+
4
+ #include "../../src/include/herb.h"
5
+ #include <ruby.h>
6
+
7
+ VALUE rb_node_from_c_struct(AST_NODE_T* node);
8
+
9
+ #endif
@@ -0,0 +1,193 @@
1
+ import { Location, SerializedLocation } from "./location.js"
2
+ import { Token, SerializedToken } from "./token.js"
3
+ import { Diagnostic, MonacoDiagnostic } from "./diagnostic.js"
4
+
5
+ export type HerbErrorType =
6
+ <%- errors.each_with_index.map do |error, index| -%>
7
+ | "<%= error.type %>"
8
+ <%- end -%>
9
+
10
+ export type SerializedErrorType = string
11
+
12
+ export interface SerializedHerbError {
13
+ type: string
14
+ message: string
15
+ location: SerializedLocation
16
+ }
17
+
18
+ export abstract class HerbError implements Diagnostic {
19
+ readonly type: string
20
+ readonly message: string
21
+ readonly location: Location
22
+ readonly severity: "error" | "warning" | "info" | "hint" = "error"
23
+ readonly source: string = "parser"
24
+
25
+ get code(): string {
26
+ return this.type
27
+ }
28
+
29
+ static from(error: SerializedHerbError): HerbError {
30
+ return fromSerializedError(error)
31
+ }
32
+
33
+ constructor(type: string, message: string, location: Location) {
34
+ this.type = type
35
+ this.message = message
36
+ this.location = location
37
+ }
38
+
39
+ toJSON(): SerializedHerbError {
40
+ return {
41
+ type: this.type,
42
+ message: this.message,
43
+ location: this.location.toJSON(),
44
+ }
45
+ }
46
+
47
+ inspect(): string {
48
+ return this.treeInspect(0)
49
+ }
50
+
51
+ abstract treeInspect(indent?: number): string
52
+ }
53
+
54
+ <%- errors.each do |error| -%>
55
+ export interface Serialized<%= error.name %> {
56
+ type: "<%= error.type %>";
57
+ message: string;
58
+ location: SerializedLocation;
59
+ <%- error.fields.each do |field| -%>
60
+ <%- case field -%>
61
+ <%- when Herb::Template::StringField -%>
62
+ <%= field.name %>: string;
63
+ <%- when Herb::Template::TokenField -%>
64
+ <%= field.name %>: SerializedToken | null;
65
+ <%- when Herb::Template::TokenTypeField -%>
66
+ <%= field.name %>: string | null;
67
+ <%- else -%>
68
+ <%= field.name %>: any; // <%= field.inspect %>
69
+ <%- end -%>
70
+ <%- end -%>
71
+ }
72
+
73
+ export interface <%= error.name %>Props {
74
+ type: string;
75
+ message: string;
76
+ location: Location;
77
+ <%- error.fields.each do |field| -%>
78
+ <%- case field -%>
79
+ <%- when Herb::Template::StringField -%>
80
+ <%= field.name %>: string;
81
+ <%- when Herb::Template::TokenField -%>
82
+ <%= field.name %>: Token | null;
83
+ <%- when Herb::Template::TokenTypeField -%>
84
+ <%= field.name %>: string | null;
85
+ <%- else -%>
86
+ <%= field.name %>: any; // <%= field.inspect %>
87
+ <%- end -%>
88
+ <%- end -%>
89
+ }
90
+
91
+ export class <%= error.name %> extends HerbError {
92
+ <%- error.fields.each do |field| -%>
93
+ <%- case field -%>
94
+ <%- when Herb::Template::StringField -%>
95
+ readonly <%= field.name %>: string;
96
+ <%- when Herb::Template::TokenField -%>
97
+ readonly <%= field.name %>: Token | null;
98
+ <%- when Herb::Template::TokenTypeField -%>
99
+ readonly <%= field.name %>: string | null;
100
+ <%- else -%>
101
+ readonly <%= field.name %>: any;
102
+ <%- end -%>
103
+ <%- end -%>
104
+
105
+ static from(data: Serialized<%= error.name %>): <%= error.name %> {
106
+ return new <%= error.name %>({
107
+ type: data.type,
108
+ message: data.message,
109
+ location: Location.from(data.location),
110
+ <%- error.fields.each do |field| -%>
111
+ <%- case field -%>
112
+ <%- when Herb::Template::StringField, Herb::Template::TokenTypeField, Herb::Template::SizeTField -%>
113
+ <%= field.name %>: data.<%= field.name %>,
114
+ <%- when Herb::Template::TokenField -%>
115
+ <%= field.name %>: data.<%= field.name %> ? Token.from(data.<%= field.name %>) : null,
116
+ <%- else -%>
117
+ <% raise "Unexpetected type: #{field.class}" %>
118
+ <%- end -%>
119
+ <%- end -%>
120
+ })
121
+ }
122
+
123
+ constructor(props: <%= error.name %>Props) {
124
+ super(props.type, props.message, props.location);
125
+
126
+ <%- error.fields.each do |field| -%>
127
+ this.<%= field.name %> = props.<%= field.name %>;
128
+ <%- end -%>
129
+ }
130
+
131
+ toJSON(): Serialized<%= error.name %> {
132
+ return {
133
+ ...super.toJSON(),
134
+ type: "<%= error.type %>",
135
+ <%- error.fields.each do |field| -%>
136
+ <%- case field -%>
137
+ <%- when Herb::Template::StringField, Herb::Template::TokenTypeField, Herb::Template::SizeTField -%>
138
+ <%= field.name %>: this.<%= field.name %>,
139
+ <%- when Herb::Template::TokenField -%>
140
+ <%= field.name %>: this.<%= field.name %> ? this.<%= field.name %>.toJSON() : null,
141
+ <%- else -%>
142
+ <% raise "Unexpetected type: #{field.class}" %>
143
+ <%- end -%>
144
+ <%- end -%>
145
+ };
146
+ }
147
+
148
+ toMonacoDiagnostic(): MonacoDiagnostic {
149
+ return {
150
+ line: this.location.start.line,
151
+ column: this.location.start.column,
152
+ endLine: this.location.end.line,
153
+ endColumn: this.location.end.column,
154
+ message: this.message,
155
+ severity: 'error'
156
+ }
157
+ }
158
+
159
+ treeInspect(): string {
160
+ let output = "";
161
+
162
+ output += `@ <%= error.name %> ${this.location.treeInspectWithLabel()}\n`;
163
+ <%- symbol = error.fields.any? ? "├──" : "└──" -%>
164
+ output += `<%= symbol %> message: "${this.message}"\n`;
165
+ <%- error.fields.each do |field| -%>
166
+ <%- symbol = error.fields.last == field ? "└──" : "├──" -%>
167
+ <%- name = "#{symbol} #{field.name}: " -%>
168
+ <%- case field -%>
169
+ <%- when Herb::Template::StringField, Herb::Template::TokenTypeField, Herb::Template::SizeTField -%>
170
+ output += `<%= name %>${JSON.stringify(this.<%= field.name %>)}\n`;
171
+ <%- when Herb::Template::TokenField -%>
172
+ output += `<%= name %>${this.<%= field.name %> ? this.<%= field.name %>.treeInspect() : "∅"}\n`;
173
+ <%- else -%>
174
+ <% raise "Unexpetected type: #{field.class}" %>
175
+ <%- end -%>
176
+ <%- end -%>
177
+
178
+ return output;
179
+ }
180
+ }
181
+
182
+ <%- end -%>
183
+
184
+ export function fromSerializedError(error: SerializedHerbError): HerbError {
185
+ switch (error.type) {
186
+ <%- errors.each do |error| -%>
187
+ case "<%= error.type %>": return <%= error.name %>.from(error as Serialized<%= error.name %>);
188
+ <%- end -%>
189
+
190
+ default:
191
+ throw new Error(`Unknown node type: ${error.type}`);
192
+ }
193
+ }