herb 0.11.0-arm-linux-gnu → 0.11.1-arm-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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/config.yml +3 -0
  3. data/ext/herb/nodes.c +34 -17
  4. data/lib/herb/3.2/herb.so +0 -0
  5. data/lib/herb/3.3/herb.so +0 -0
  6. data/lib/herb/3.4/herb.so +0 -0
  7. data/lib/herb/4.0/herb.so +0 -0
  8. data/lib/herb/ast/nodes.rb +32 -6
  9. data/lib/herb/bootstrap.rb +6 -2
  10. data/lib/herb/dev/runner.rb +6 -1
  11. data/lib/herb/engine/compiler.rb +47 -11
  12. data/lib/herb/engine/slots/dynamics_compiler.rb +10 -0
  13. data/lib/herb/engine/slots/markers.rb +24 -0
  14. data/lib/herb/engine/slots/state_compiler.rb +1 -2
  15. data/lib/herb/engine/slots/visitor.rb +39 -28
  16. data/lib/herb/engine.rb +0 -2
  17. data/lib/herb/version.rb +1 -1
  18. data/sig/herb/ast/nodes.rbs +10 -4
  19. data/sig/herb/bootstrap.rbs +2 -0
  20. data/sig/herb/dev/runner.rbs +3 -0
  21. data/sig/herb/engine/compiler.rbs +14 -3
  22. data/sig/herb/engine/slots/dynamics_compiler.rbs +3 -0
  23. data/sig/herb/engine/slots/markers.rbs +14 -0
  24. data/sig/herb/engine/slots/visitor.rbs +17 -13
  25. data/sig/serialized_ast_nodes.rbs +1 -0
  26. data/src/analyze/action_view/tag_helper_node_builders.c +6 -3
  27. data/src/analyze/action_view/tag_helpers.c +76 -20
  28. data/src/analyze/analyze.c +5 -25
  29. data/src/analyze/analyze_helpers.c +94 -232
  30. data/src/analyze/analyzed_ruby.c +2 -0
  31. data/src/analyze/builders.c +1 -0
  32. data/src/analyze/control_type.c +17 -7
  33. data/src/analyze/prism_annotate.c +32 -9
  34. data/src/ast/ast_nodes.c +3 -1
  35. data/src/ast/ast_pretty_print.c +5 -1
  36. data/src/extract.c +204 -143
  37. data/src/include/analyze/analyze.h +0 -22
  38. data/src/include/analyze/analyzed_ruby.h +25 -0
  39. data/src/include/analyze/helpers.h +2 -22
  40. data/src/include/ast/ast_nodes.h +2 -1
  41. data/src/include/lexer/lexer.h +1 -0
  42. data/src/include/prism/herb_prism_node.h +6 -1
  43. data/src/include/version.h +1 -1
  44. data/src/lexer.c +32 -0
  45. data/src/prism/prism_helpers.c +91 -0
  46. data/templates/ext/herb/nodes.c.erb +1 -1
  47. data/templates/java/nodes.c.erb +1 -1
  48. data/templates/javascript/packages/core/src/nodes.ts.erb +21 -1
  49. data/templates/javascript/packages/node/extension/nodes.cpp.erb +1 -1
  50. data/templates/rust/src/ast/nodes.rs.erb +1 -4
  51. data/templates/wasm/nodes.cpp.erb +5 -15
  52. metadata +1 -1
data/src/extract.c CHANGED
@@ -1,9 +1,12 @@
1
1
  #include "include/herb.h"
2
+ #include "include/lexer/lexer.h"
3
+ #include "include/lexer/token.h"
2
4
  #include "include/lib/hb_allocator.h"
3
5
  #include "include/lib/hb_array.h"
4
6
  #include "include/lib/hb_buffer.h"
5
7
  #include "include/lib/hb_string.h"
6
8
  #include "include/lib/string.h"
9
+ #include "include/util/util.h"
7
10
 
8
11
  #include <assert.h>
9
12
  #include <stdlib.h>
@@ -16,192 +19,250 @@ const herb_extract_ruby_options_T HERB_EXTRACT_RUBY_DEFAULT_OPTIONS = { .semicol
16
19
  .erb_openers = NULL,
17
20
  .erb_opener_count = 0 };
18
21
 
19
- void herb_extract_ruby_to_buffer_with_options(
20
- const char* source,
21
- hb_buffer_T* output,
22
- const herb_extract_ruby_options_T* options,
23
- hb_allocator_T* allocator
24
- ) {
25
- herb_extract_ruby_options_T extract_options = options ? *options : HERB_EXTRACT_RUBY_DEFAULT_OPTIONS;
22
+ typedef struct {
23
+ herb_extract_ruby_options_T options;
24
+ hb_buffer_T* output;
25
+ bool skip_erb_content;
26
+ bool is_comment_tag;
27
+ bool is_erb_comment_tag;
28
+ bool need_newline;
29
+ } extract_ruby_state_T;
26
30
 
27
- parser_options_T lex_options = HERB_DEFAULT_PARSER_OPTIONS;
28
- lex_options.erb_openers = extract_options.erb_openers;
29
- lex_options.erb_opener_count = extract_options.erb_opener_count;
31
+ static void extract_ruby_data(extract_ruby_state_T* state, const char* data, uint32_t from, uint32_t to) {
32
+ uint32_t run_start = from;
30
33
 
31
- hb_array_T* tokens = herb_lex_with_options(source, &lex_options, allocator);
32
- bool skip_erb_content = false;
33
- bool is_comment_tag = false;
34
- bool is_erb_comment_tag = false;
35
- bool need_newline = false;
34
+ for (uint32_t position = from; position < to; position++) {
35
+ if (!is_newline(data[position])) { continue; }
36
36
 
37
- for (size_t i = 0; i < hb_array_size(tokens); i++) {
38
- const token_T* token = hb_array_get(tokens, i);
37
+ if (state->options.preserve_positions) { hb_buffer_append_whitespace(state->output, position - run_start); }
39
38
 
40
- switch (token->type) {
41
- case TOKEN_NEWLINE: {
42
- hb_buffer_append_string(output, token->value);
43
- need_newline = false;
44
- break;
45
- }
39
+ hb_buffer_append_char(state->output, data[position]);
40
+ state->need_newline = false;
41
+ run_start = position + 1;
42
+ }
46
43
 
47
- case TOKEN_ERB_START: {
48
- is_erb_comment_tag = hb_string_equals(token->value, hb_string("<%#"));
44
+ if (state->options.preserve_positions) { hb_buffer_append_whitespace(state->output, to - run_start); }
45
+ }
49
46
 
50
- if (is_erb_comment_tag) {
51
- if (extract_options.comments) {
52
- skip_erb_content = false;
53
- is_comment_tag = false;
47
+ static void extract_ruby_token(extract_ruby_state_T* state, const token_T* token, const token_T* next) {
48
+ switch (token->type) {
49
+ case TOKEN_NEWLINE: {
50
+ hb_buffer_append_string(state->output, token->value);
51
+ state->need_newline = false;
52
+ break;
53
+ }
54
54
 
55
- if (extract_options.preserve_positions) {
56
- bool is_multiline = false;
55
+ case TOKEN_ERB_START: {
56
+ state->is_erb_comment_tag = hb_string_equals(token->value, hb_string("<%#"));
57
57
 
58
- if (i + 1 < hb_array_size(tokens)) {
59
- const token_T* next = hb_array_get(tokens, i + 1);
58
+ if (state->is_erb_comment_tag) {
59
+ if (state->options.comments) {
60
+ state->skip_erb_content = false;
61
+ state->is_comment_tag = false;
60
62
 
61
- if (next->type == TOKEN_ERB_CONTENT && !hb_string_is_null(next->value)
62
- && memchr(next->value.data, '\n', next->value.length) != NULL) {
63
- is_multiline = true;
64
- }
65
- }
63
+ if (state->options.preserve_positions) {
64
+ bool is_multiline = false;
66
65
 
67
- if (is_multiline) {
68
- hb_buffer_append_char(output, '#');
69
- hb_buffer_append_whitespace(output, 2);
70
- } else {
71
- hb_buffer_append_whitespace(output, 2);
72
- hb_buffer_append_char(output, '#');
73
- }
66
+ if (next && next->type == TOKEN_ERB_CONTENT && !hb_string_is_null(next->value)
67
+ && memchr(next->value.data, '\n', next->value.length) != NULL) {
68
+ is_multiline = true;
69
+ }
70
+
71
+ if (is_multiline) {
72
+ hb_buffer_append_char(state->output, '#');
73
+ hb_buffer_append_whitespace(state->output, 2);
74
74
  } else {
75
- if (need_newline) { hb_buffer_append_char(output, '\n'); }
76
- hb_buffer_append_char(output, '#');
77
- need_newline = true;
75
+ hb_buffer_append_whitespace(state->output, 2);
76
+ hb_buffer_append_char(state->output, '#');
78
77
  }
79
78
  } else {
80
- skip_erb_content = true;
81
- is_comment_tag = true;
82
- if (extract_options.preserve_positions) { hb_buffer_append_whitespace(output, range_length(token->range)); }
79
+ if (state->need_newline) { hb_buffer_append_char(state->output, '\n'); }
80
+ hb_buffer_append_char(state->output, '#');
81
+ state->need_newline = true;
83
82
  }
84
- } else if (hb_string_equals(token->value, hb_string("<%%")) || hb_string_equals(token->value, hb_string("<%%="))
85
- || (erb_opening_is_custom(token->value) && !extract_options.custom_tags)) {
86
- skip_erb_content = true;
87
- is_comment_tag = false;
88
- if (extract_options.preserve_positions) { hb_buffer_append_whitespace(output, range_length(token->range)); }
89
83
  } else {
90
- skip_erb_content = false;
91
- is_comment_tag = false;
92
-
93
- if (extract_options.preserve_positions) {
94
- hb_buffer_append_whitespace(output, range_length(token->range));
95
- } else if (need_newline) {
96
- hb_buffer_append_char(output, '\n');
97
- need_newline = false;
84
+ state->skip_erb_content = true;
85
+ state->is_comment_tag = true;
86
+ if (state->options.preserve_positions) {
87
+ hb_buffer_append_whitespace(state->output, range_length(token->range));
98
88
  }
99
89
  }
100
-
101
- break;
90
+ } else if (hb_string_equals(token->value, hb_string("<%%")) || hb_string_equals(token->value, hb_string("<%%="))
91
+ || (erb_opening_is_custom(token->value) && !state->options.custom_tags)) {
92
+ state->skip_erb_content = true;
93
+ state->is_comment_tag = false;
94
+ if (state->options.preserve_positions) {
95
+ hb_buffer_append_whitespace(state->output, range_length(token->range));
96
+ }
97
+ } else {
98
+ state->skip_erb_content = false;
99
+ state->is_comment_tag = false;
100
+
101
+ if (state->options.preserve_positions) {
102
+ hb_buffer_append_whitespace(state->output, range_length(token->range));
103
+ } else if (state->need_newline) {
104
+ hb_buffer_append_char(state->output, '\n');
105
+ state->need_newline = false;
106
+ }
102
107
  }
103
108
 
104
- case TOKEN_ERB_CONTENT: {
105
- if (skip_erb_content == false) {
106
- bool is_inline_comment = false;
109
+ break;
110
+ }
107
111
 
108
- if (!extract_options.comments && !is_comment_tag && !hb_string_is_empty(token->value)) {
109
- hb_string_T trimmed = hb_string_trim_start(token->value);
112
+ case TOKEN_ERB_CONTENT: {
113
+ if (state->skip_erb_content == false) {
114
+ bool is_inline_comment = false;
110
115
 
111
- if (!hb_string_is_empty(trimmed) && trimmed.data[0] == '#'
112
- && token->location.start.line == token->location.end.line) {
113
- is_comment_tag = true;
114
- is_inline_comment = true;
115
- }
116
- }
116
+ if (!state->options.comments && !state->is_comment_tag && !hb_string_is_empty(token->value)) {
117
+ hb_string_T trimmed = hb_string_trim_start(token->value);
117
118
 
118
- if (is_inline_comment) {
119
- if (extract_options.preserve_positions) { hb_buffer_append_whitespace(output, range_length(token->range)); }
120
- } else if (is_erb_comment_tag && !hb_string_is_null(token->value)) {
121
- const char* content = token->value.data;
122
- size_t content_remaining = token->value.length;
119
+ if (!hb_string_is_empty(trimmed) && trimmed.data[0] == '#'
120
+ && token->location.start.line == token->location.end.line) {
121
+ state->is_comment_tag = true;
122
+ is_inline_comment = true;
123
+ }
124
+ }
123
125
 
124
- while (content_remaining > 0) {
125
- if (*content == '\n') {
126
- hb_buffer_append_char(output, '\n');
127
- content++;
128
- content_remaining--;
126
+ if (is_inline_comment) {
127
+ if (state->options.preserve_positions) {
128
+ hb_buffer_append_whitespace(state->output, range_length(token->range));
129
+ }
130
+ } else if (state->is_erb_comment_tag && !hb_string_is_null(token->value)) {
131
+ const char* content = token->value.data;
132
+ size_t content_remaining = token->value.length;
129
133
 
130
- if (content_remaining > 0 && extract_options.preserve_positions && *content == ' ') {
131
- content++;
132
- content_remaining--;
133
- }
134
+ while (content_remaining > 0) {
135
+ if (*content == '\n') {
136
+ hb_buffer_append_char(state->output, '\n');
137
+ content++;
138
+ content_remaining--;
134
139
 
135
- hb_buffer_append_char(output, '#');
136
- } else {
137
- hb_buffer_append_char(output, *content);
140
+ if (content_remaining > 0 && state->options.preserve_positions && *content == ' ') {
138
141
  content++;
139
142
  content_remaining--;
140
143
  }
141
- }
142
-
143
- if (!extract_options.preserve_positions) { need_newline = true; }
144
- } else {
145
- hb_buffer_append_string(output, token->value);
146
-
147
- if (!extract_options.preserve_positions) { need_newline = true; }
148
- }
149
- } else {
150
- if (is_erb_comment_tag && extract_options.preserve_positions && !hb_string_is_null(token->value)) {
151
- const char* content = token->value.data;
152
- size_t content_remaining = token->value.length;
153
-
154
- while (content_remaining > 0) {
155
- if (*content == '\n') {
156
- hb_buffer_append_char(output, '\n');
157
- } else {
158
- hb_buffer_append_char(output, ' ');
159
- }
160
144
 
145
+ hb_buffer_append_char(state->output, '#');
146
+ } else {
147
+ hb_buffer_append_char(state->output, *content);
161
148
  content++;
162
149
  content_remaining--;
163
150
  }
164
- } else if (extract_options.preserve_positions) {
165
- hb_buffer_append_whitespace(output, range_length(token->range));
166
151
  }
167
- }
168
152
 
169
- break;
170
- }
153
+ if (!state->options.preserve_positions) { state->need_newline = true; }
154
+ } else {
155
+ hb_buffer_append_string(state->output, token->value);
171
156
 
172
- case TOKEN_ERB_END: {
173
- bool was_comment = is_comment_tag;
174
- bool was_erb_comment = is_erb_comment_tag;
175
- skip_erb_content = false;
176
- is_comment_tag = false;
177
- is_erb_comment_tag = false;
178
-
179
- if (extract_options.preserve_positions) {
180
- if (was_comment) {
181
- hb_buffer_append_whitespace(output, range_length(token->range));
182
- } else if (was_erb_comment && extract_options.comments) {
183
- hb_buffer_append_whitespace(output, range_length(token->range));
184
- } else if (extract_options.semicolons) {
185
- size_t length = range_length(token->range);
186
-
187
- if (length >= 2) { hb_buffer_append_char(output, ' '); }
188
- if (length >= 1) { hb_buffer_append_char(output, ';'); }
189
- if (length >= 2) { hb_buffer_append_whitespace(output, length - 2); }
190
- } else {
191
- hb_buffer_append_whitespace(output, range_length(token->range));
192
- }
157
+ if (!state->options.preserve_positions) { state->need_newline = true; }
193
158
  }
159
+ } else {
160
+ if (state->is_erb_comment_tag && state->options.preserve_positions && !hb_string_is_null(token->value)) {
161
+ const char* content = token->value.data;
162
+ size_t content_remaining = token->value.length;
163
+
164
+ while (content_remaining > 0) {
165
+ if (*content == '\n') {
166
+ hb_buffer_append_char(state->output, '\n');
167
+ } else {
168
+ hb_buffer_append_char(state->output, ' ');
169
+ }
194
170
 
195
- break;
171
+ content++;
172
+ content_remaining--;
173
+ }
174
+ } else if (state->options.preserve_positions) {
175
+ hb_buffer_append_whitespace(state->output, range_length(token->range));
176
+ }
196
177
  }
197
178
 
198
- default: {
199
- if (extract_options.preserve_positions) { hb_buffer_append_whitespace(output, range_length(token->range)); }
179
+ break;
180
+ }
181
+
182
+ case TOKEN_ERB_END: {
183
+ bool was_comment = state->is_comment_tag;
184
+ bool was_erb_comment = state->is_erb_comment_tag;
185
+ state->skip_erb_content = false;
186
+ state->is_comment_tag = false;
187
+ state->is_erb_comment_tag = false;
188
+
189
+ if (state->options.preserve_positions) {
190
+ if (was_comment) {
191
+ hb_buffer_append_whitespace(state->output, range_length(token->range));
192
+ } else if (was_erb_comment && state->options.comments) {
193
+ hb_buffer_append_whitespace(state->output, range_length(token->range));
194
+ } else if (state->options.semicolons) {
195
+ size_t length = range_length(token->range);
196
+
197
+ if (length >= 2) { hb_buffer_append_char(state->output, ' '); }
198
+ if (length >= 1) { hb_buffer_append_char(state->output, ';'); }
199
+ if (length >= 2) { hb_buffer_append_whitespace(state->output, length - 2); }
200
+ } else {
201
+ hb_buffer_append_whitespace(state->output, range_length(token->range));
202
+ }
200
203
  }
204
+
205
+ break;
206
+ }
207
+
208
+ default: {
209
+ if (state->options.preserve_positions) { hb_buffer_append_whitespace(state->output, range_length(token->range)); }
201
210
  }
202
211
  }
212
+ }
203
213
 
204
- herb_free_tokens(&tokens, allocator);
214
+ void herb_extract_ruby_to_buffer_with_options(
215
+ const char* source,
216
+ hb_buffer_T* output,
217
+ const herb_extract_ruby_options_T* options,
218
+ hb_allocator_T* allocator
219
+ ) {
220
+ extract_ruby_state_T state = {
221
+ .options = options ? *options : HERB_EXTRACT_RUBY_DEFAULT_OPTIONS,
222
+ .output = output,
223
+ .skip_erb_content = false,
224
+ .is_comment_tag = false,
225
+ .is_erb_comment_tag = false,
226
+ .need_newline = false,
227
+ };
228
+
229
+ parser_options_T lex_options = HERB_DEFAULT_PARSER_OPTIONS;
230
+ lex_options.erb_openers = state.options.erb_openers;
231
+ lex_options.erb_opener_count = state.options.erb_opener_count;
232
+
233
+ lexer_T lexer = { 0 };
234
+ lexer_init(&lexer, source ? source : "", allocator);
235
+ lexer_apply_erb_openers(&lexer, &lex_options);
236
+
237
+ const char* data = lexer.source.data;
238
+ uint32_t length = (uint32_t) lexer.source.length;
239
+ token_T* pending = NULL;
240
+
241
+ while (true) {
242
+ if (!pending && lexer.state == STATE_DATA) {
243
+ uint32_t position = lexer.current_position;
244
+
245
+ while (position < length && !(data[position] == '<' && data[position + 1] == '%')) {
246
+ position++;
247
+ }
248
+
249
+ extract_ruby_data(&state, data, lexer.current_position, position);
250
+ lexer_skip_data_to(&lexer, position);
251
+ }
252
+
253
+ token_T* token = pending ? pending : lexer_next_token(&lexer);
254
+ pending = NULL;
255
+
256
+ if (token->type == TOKEN_EOF) {
257
+ token_free(token, allocator);
258
+ break;
259
+ }
260
+
261
+ if (token->type == TOKEN_ERB_START) { pending = lexer_next_token(&lexer); }
262
+
263
+ extract_ruby_token(&state, token, pending);
264
+ token_free(token, allocator);
265
+ }
205
266
  }
206
267
 
207
268
  void herb_extract_ruby_to_buffer(const char* source, hb_buffer_T* output, hb_allocator_T* allocator) {
@@ -26,28 +26,6 @@ typedef struct ANALYZE_RUBY_CONTEXT_STRUCT {
26
26
  const parser_options_T* options;
27
27
  } analyze_ruby_context_T;
28
28
 
29
- typedef enum {
30
- CONTROL_TYPE_IF,
31
- CONTROL_TYPE_ELSIF,
32
- CONTROL_TYPE_ELSE,
33
- CONTROL_TYPE_END,
34
- CONTROL_TYPE_CASE,
35
- CONTROL_TYPE_CASE_MATCH,
36
- CONTROL_TYPE_WHEN,
37
- CONTROL_TYPE_IN,
38
- CONTROL_TYPE_BEGIN,
39
- CONTROL_TYPE_RESCUE,
40
- CONTROL_TYPE_ENSURE,
41
- CONTROL_TYPE_UNLESS,
42
- CONTROL_TYPE_WHILE,
43
- CONTROL_TYPE_UNTIL,
44
- CONTROL_TYPE_FOR,
45
- CONTROL_TYPE_BLOCK,
46
- CONTROL_TYPE_BLOCK_CLOSE,
47
- CONTROL_TYPE_YIELD,
48
- CONTROL_TYPE_UNKNOWN
49
- } control_type_t;
50
-
51
29
  typedef struct {
52
30
  int loop_depth;
53
31
  int rescue_depth;
@@ -5,6 +5,29 @@
5
5
  #include "../lib/hb_string.h"
6
6
 
7
7
  #include <prism.h>
8
+ #include <stdbool.h>
9
+
10
+ typedef enum {
11
+ CONTROL_TYPE_IF,
12
+ CONTROL_TYPE_ELSIF,
13
+ CONTROL_TYPE_ELSE,
14
+ CONTROL_TYPE_END,
15
+ CONTROL_TYPE_CASE,
16
+ CONTROL_TYPE_CASE_MATCH,
17
+ CONTROL_TYPE_WHEN,
18
+ CONTROL_TYPE_IN,
19
+ CONTROL_TYPE_BEGIN,
20
+ CONTROL_TYPE_RESCUE,
21
+ CONTROL_TYPE_ENSURE,
22
+ CONTROL_TYPE_UNLESS,
23
+ CONTROL_TYPE_WHILE,
24
+ CONTROL_TYPE_UNTIL,
25
+ CONTROL_TYPE_FOR,
26
+ CONTROL_TYPE_BLOCK,
27
+ CONTROL_TYPE_BLOCK_CLOSE,
28
+ CONTROL_TYPE_YIELD,
29
+ CONTROL_TYPE_UNKNOWN
30
+ } control_type_t;
8
31
 
9
32
  typedef struct ANALYZED_RUBY_STRUCT {
10
33
  pm_parser_t parser;
@@ -31,6 +54,8 @@ typedef struct ANALYZED_RUBY_STRUCT {
31
54
  int yield_node_count;
32
55
  int then_keyword_count;
33
56
  int unclosed_control_flow_count;
57
+ control_type_t control_type;
58
+ bool control_type_detected;
34
59
  } analyzed_ruby_T;
35
60
 
36
61
  analyzed_ruby_T* init_analyzed_ruby(hb_string_T source);
@@ -42,29 +42,9 @@ bool is_brace_block(pm_location_t opening_location);
42
42
  bool is_closing_brace(pm_location_t location);
43
43
  bool has_valid_block_closing(pm_location_t opening_loc, pm_location_t closing_loc);
44
44
 
45
- bool search_begin_nodes(const pm_node_t* node, void* data);
46
- bool search_block_nodes(const pm_node_t* node, void* data);
47
- bool search_case_match_nodes(const pm_node_t* node, void* data);
48
- bool search_case_nodes(const pm_node_t* node, void* data);
49
- bool search_for_nodes(const pm_node_t* node, void* data);
50
- bool search_if_nodes(const pm_node_t* node, void* data);
51
- bool search_in_nodes(const pm_node_t* node, void* data);
52
- bool search_then_keywords(const pm_node_t* node, void* data);
45
+ bool search_control_flow_nodes(const pm_node_t* node, void* data);
53
46
  bool search_unclosed_control_flows(const pm_node_t* node, void* data);
54
- bool search_unless_nodes(const pm_node_t* node, void* data);
55
- bool search_until_nodes(const pm_node_t* node, void* data);
56
- bool search_when_nodes(const pm_node_t* node, void* data);
57
- bool search_while_nodes(const pm_node_t* node, void* data);
58
- bool search_yield_nodes(const pm_node_t* node, void* data);
59
-
60
- bool search_unexpected_block_closing_nodes(analyzed_ruby_T* analyzed);
61
- bool search_unexpected_else_nodes(analyzed_ruby_T* analyzed);
62
- bool search_unexpected_elsif_nodes(analyzed_ruby_T* analyzed);
63
- bool search_unexpected_end_nodes(analyzed_ruby_T* analyzed);
64
- bool search_unexpected_ensure_nodes(analyzed_ruby_T* analyzed);
65
- bool search_unexpected_in_nodes(analyzed_ruby_T* analyzed);
66
- bool search_unexpected_rescue_nodes(analyzed_ruby_T* analyzed);
67
- bool search_unexpected_when_nodes(analyzed_ruby_T* analyzed);
47
+ void search_unexpected_keyword_errors(analyzed_ruby_T* analyzed);
68
48
 
69
49
  void check_erb_node_for_missing_end(const AST_NODE_T* node, hb_allocator_T* allocator, const parser_options_T* options);
70
50
 
@@ -478,6 +478,7 @@ typedef struct AST_ERB_YIELD_NODE_STRUCT {
478
478
  token_T* tag_opening;
479
479
  token_T* content;
480
480
  token_T* tag_closing;
481
+ herb_prism_node_T prism_node;
481
482
  } AST_ERB_YIELD_NODE_T;
482
483
 
483
484
  typedef struct AST_ERB_IN_NODE_STRUCT {
@@ -565,7 +566,7 @@ AST_RUBY_RENDER_KEYWORDS_NODE_T* ast_ruby_render_keywords_node_init(token_T* par
565
566
  AST_ERB_RENDER_NODE_T* ast_erb_render_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, analyzed_ruby_T* analyzed_ruby, herb_prism_node_T prism_node, struct AST_RUBY_RENDER_KEYWORDS_NODE_STRUCT* keywords, hb_array_T* body, hb_array_T* block_arguments, struct AST_ERB_RESCUE_NODE_STRUCT* rescue_clause, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_ENSURE_NODE_STRUCT* ensure_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator);
566
567
  AST_RUBY_PARAMETER_NODE_T* ast_ruby_parameter_node_init(token_T* name, struct AST_RUBY_LITERAL_NODE_STRUCT* default_value, hb_string_T kind, bool required, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator);
567
568
  AST_ERB_STRICT_LOCALS_NODE_T* ast_erb_strict_locals_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, analyzed_ruby_T* analyzed_ruby, herb_prism_node_T prism_node, hb_array_T* locals, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator);
568
- AST_ERB_YIELD_NODE_T* ast_erb_yield_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator);
569
+ AST_ERB_YIELD_NODE_T* ast_erb_yield_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, herb_prism_node_T prism_node, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator);
569
570
  AST_ERB_IN_NODE_T* ast_erb_in_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, location_T* then_keyword, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator);
570
571
  AST_HERB_DIRECTIVE_NODE_T* ast_herb_directive_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, token_T* key, token_T* arguments, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator);
571
572
  AST_HERB_STATE_DECLARATION_NODE_T* ast_herb_state_declaration_node_init(token_T* name, struct AST_RUBY_LITERAL_NODE_STRUCT* default_value, hb_string_T kind, position_T start_position, position_T end_position, hb_array_T* errors, hb_allocator_T* allocator);
@@ -7,5 +7,6 @@
7
7
  void lexer_init(lexer_T* lexer, const char* source, hb_allocator_T* allocator);
8
8
  token_T* lexer_next_token(lexer_T* lexer);
9
9
  token_T* lexer_error(lexer_T* lexer, const char* message);
10
+ void lexer_skip_data_to(lexer_T* lexer, uint32_t position);
10
11
 
11
12
  #endif
@@ -2,12 +2,17 @@
2
2
  #define HERB_PRISM_NODE_H
3
3
 
4
4
  #include <prism.h>
5
+ #include <stdint.h>
5
6
 
6
7
  typedef struct {
7
8
  pm_node_t* node;
8
9
  pm_parser_t* parser;
10
+ uint32_t source_start;
11
+ uint32_t source_end;
9
12
  } herb_prism_node_T;
10
13
 
11
- #define HERB_PRISM_NODE_EMPTY ((herb_prism_node_T) { .node = NULL, .parser = NULL })
14
+ #define HERB_PRISM_NODE_EMPTY ((herb_prism_node_T) { .node = NULL, .parser = NULL, .source_start = 0, .source_end = 0 })
15
+
16
+ void herb_prism_node_serialize(herb_prism_node_T prism_node, pm_buffer_t* buffer);
12
17
 
13
18
  #endif
@@ -1,6 +1,6 @@
1
1
  #ifndef HERB_VERSION_H
2
2
  #define HERB_VERSION_H
3
3
 
4
- #define HERB_VERSION "0.11.0"
4
+ #define HERB_VERSION "0.11.1"
5
5
 
6
6
  #endif
data/src/lexer.c CHANGED
@@ -430,6 +430,38 @@ static token_T* lexer_parse_erb_close(lexer_T* lexer) {
430
430
  return lexer_advance_with(lexer, hb_string("%>"), TOKEN_ERB_END);
431
431
  }
432
432
 
433
+ void lexer_skip_data_to(lexer_T* lexer, uint32_t position) {
434
+ if (position > lexer->source.length) { position = lexer->source.length; }
435
+
436
+ while (lexer->current_position < position && !lexer_eof(lexer)) {
437
+ char character = lexer->current_character;
438
+
439
+ if (character == '\r' && lexer_peek(lexer, 1) == '\n') {
440
+ lexer->current_position += 2;
441
+ lexer->current_line++;
442
+ lexer->current_column = 0;
443
+ } else if (is_newline(character)) {
444
+ lexer->current_position++;
445
+ lexer->current_line++;
446
+ lexer->current_column = 0;
447
+ } else if ((unsigned char) character < 0x80) {
448
+ lexer->current_position++;
449
+ lexer->current_column++;
450
+ } else {
451
+ uint32_t length = utf8_sequence_length(hb_string_slice(lexer->source, lexer->current_position));
452
+
453
+ lexer->current_position += length > 0 ? length : 1;
454
+ lexer->current_column++;
455
+ }
456
+
457
+ lexer->current_character = lexer->source.data[lexer->current_position];
458
+ }
459
+
460
+ lexer->previous_line = lexer->current_line;
461
+ lexer->previous_column = lexer->current_column;
462
+ lexer->previous_position = lexer->current_position;
463
+ }
464
+
433
465
  // ===== Tokenizing Function
434
466
 
435
467
  token_T* lexer_next_token(lexer_T* lexer) {