herb 0.11.0-aarch64-linux-gnu → 0.11.1-aarch64-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.
- checksums.yaml +4 -4
- data/config.yml +3 -0
- data/ext/herb/nodes.c +34 -17
- data/lib/herb/3.2/herb.so +0 -0
- data/lib/herb/3.3/herb.so +0 -0
- data/lib/herb/3.4/herb.so +0 -0
- data/lib/herb/4.0/herb.so +0 -0
- data/lib/herb/ast/nodes.rb +32 -6
- data/lib/herb/bootstrap.rb +6 -2
- data/lib/herb/dev/runner.rb +6 -1
- data/lib/herb/engine/compiler.rb +47 -11
- data/lib/herb/engine/slots/dynamics_compiler.rb +10 -0
- data/lib/herb/engine/slots/markers.rb +24 -0
- data/lib/herb/engine/slots/state_compiler.rb +1 -2
- data/lib/herb/engine/slots/visitor.rb +39 -28
- data/lib/herb/engine.rb +0 -2
- data/lib/herb/version.rb +1 -1
- data/sig/herb/ast/nodes.rbs +10 -4
- data/sig/herb/bootstrap.rbs +2 -0
- data/sig/herb/dev/runner.rbs +3 -0
- data/sig/herb/engine/compiler.rbs +14 -3
- data/sig/herb/engine/slots/dynamics_compiler.rbs +3 -0
- data/sig/herb/engine/slots/markers.rbs +14 -0
- data/sig/herb/engine/slots/visitor.rbs +17 -13
- data/sig/serialized_ast_nodes.rbs +1 -0
- data/src/analyze/action_view/tag_helper_node_builders.c +6 -3
- data/src/analyze/action_view/tag_helpers.c +76 -20
- data/src/analyze/analyze.c +5 -25
- data/src/analyze/analyze_helpers.c +94 -232
- data/src/analyze/analyzed_ruby.c +2 -0
- data/src/analyze/builders.c +1 -0
- data/src/analyze/control_type.c +17 -7
- data/src/analyze/prism_annotate.c +32 -9
- data/src/ast/ast_nodes.c +3 -1
- data/src/ast/ast_pretty_print.c +5 -1
- data/src/extract.c +204 -143
- data/src/include/analyze/analyze.h +0 -22
- data/src/include/analyze/analyzed_ruby.h +25 -0
- data/src/include/analyze/helpers.h +2 -22
- data/src/include/ast/ast_nodes.h +2 -1
- data/src/include/lexer/lexer.h +1 -0
- data/src/include/prism/herb_prism_node.h +6 -1
- data/src/include/version.h +1 -1
- data/src/lexer.c +32 -0
- data/src/prism/prism_helpers.c +91 -0
- data/templates/ext/herb/nodes.c.erb +1 -1
- data/templates/java/nodes.c.erb +1 -1
- data/templates/javascript/packages/core/src/nodes.ts.erb +21 -1
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +1 -1
- data/templates/rust/src/ast/nodes.rs.erb +1 -4
- data/templates/wasm/nodes.cpp.erb +5 -15
- 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
|
-
|
|
20
|
-
|
|
21
|
-
hb_buffer_T* output
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
48
|
-
|
|
44
|
+
if (state->options.preserve_positions) { hb_buffer_append_whitespace(state->output, to - run_start); }
|
|
45
|
+
}
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
56
|
-
|
|
55
|
+
case TOKEN_ERB_START: {
|
|
56
|
+
state->is_erb_comment_tag = hb_string_equals(token->value, hb_string("<%#"));
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
is_multiline = true;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
63
|
+
if (state->options.preserve_positions) {
|
|
64
|
+
bool is_multiline = false;
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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 =
|
|
91
|
-
is_comment_tag =
|
|
92
|
-
|
|
93
|
-
|
|
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
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
bool is_inline_comment = false;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
107
111
|
|
|
108
|
-
|
|
109
|
-
|
|
112
|
+
case TOKEN_ERB_CONTENT: {
|
|
113
|
+
if (state->skip_erb_content == false) {
|
|
114
|
+
bool is_inline_comment = false;
|
|
110
115
|
|
|
111
|
-
|
|
112
|
-
|
|
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 (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
199
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
data/src/include/ast/ast_nodes.h
CHANGED
|
@@ -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);
|
data/src/include/lexer/lexer.h
CHANGED
|
@@ -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
|
data/src/include/version.h
CHANGED
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) {
|