herb 0.8.7 → 0.8.8
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/Rakefile +7 -0
- data/config.yml +12 -0
- data/ext/herb/extconf.rb +0 -4
- data/ext/herb/nodes.c +17 -9
- data/lib/herb/ast/nodes.rb +32 -8
- data/lib/herb/engine/debug_visitor.rb +1 -1
- data/lib/herb/version.rb +1 -1
- data/lib/herb.rb +30 -3
- data/sig/herb/ast/nodes.rbs +16 -8
- data/sig/serialized_ast_nodes.rbs +4 -0
- data/src/analyze.c +110 -15
- data/src/analyze_helpers.c +80 -12
- data/src/analyzed_ruby.c +1 -0
- data/src/ast_nodes.c +12 -4
- data/src/ast_pretty_print.c +52 -0
- data/src/include/analyze_helpers.h +7 -0
- data/src/include/analyzed_ruby.h +1 -0
- data/src/include/ast_nodes.h +8 -4
- data/src/include/location.h +4 -0
- data/src/include/prism_helpers.h +6 -0
- data/src/include/version.h +1 -1
- data/src/location.c +16 -0
- data/src/prism_helpers.c +188 -0
- data/templates/ext/herb/nodes.c.erb +2 -0
- data/templates/java/nodes.c.erb +3 -1
- data/templates/java/org/herb/ast/Nodes.java.erb +11 -0
- data/templates/javascript/packages/core/src/nodes.ts.erb +14 -0
- data/templates/javascript/packages/node/extension/nodes.cpp.erb +9 -0
- data/templates/lib/herb/ast/nodes.rb.erb +4 -0
- data/templates/rust/src/ast/nodes.rs.erb +10 -0
- data/templates/rust/src/nodes.rs.erb +4 -0
- data/templates/src/ast_nodes.c.erb +4 -0
- data/templates/src/ast_pretty_print.c.erb +14 -0
- data/templates/template.rb +11 -0
- data/templates/wasm/nodes.cpp.erb +6 -0
- data/vendor/prism/include/prism/version.h +2 -2
- data/vendor/prism/src/prism.c +48 -27
- data/vendor/prism/templates/java/org/prism/Loader.java.erb +1 -1
- data/vendor/prism/templates/javascript/src/deserialize.js.erb +1 -1
- data/vendor/prism/templates/lib/prism/compiler.rb.erb +2 -2
- data/vendor/prism/templates/lib/prism/node.rb.erb +24 -1
- data/vendor/prism/templates/lib/prism/serialize.rb.erb +1 -1
- data/vendor/prism/templates/lib/prism/visitor.rb.erb +2 -2
- data/vendor/prism/templates/sig/prism/node.rbs.erb +1 -0
- metadata +1 -1
data/src/include/ast_nodes.h
CHANGED
|
@@ -183,6 +183,7 @@ typedef struct AST_ERB_IF_NODE_STRUCT {
|
|
|
183
183
|
token_T* tag_opening;
|
|
184
184
|
token_T* content;
|
|
185
185
|
token_T* tag_closing;
|
|
186
|
+
location_T* then_keyword;
|
|
186
187
|
hb_array_T* statements;
|
|
187
188
|
struct AST_NODE_STRUCT* subsequent;
|
|
188
189
|
struct AST_ERB_END_NODE_STRUCT* end_node;
|
|
@@ -202,6 +203,7 @@ typedef struct AST_ERB_WHEN_NODE_STRUCT {
|
|
|
202
203
|
token_T* tag_opening;
|
|
203
204
|
token_T* content;
|
|
204
205
|
token_T* tag_closing;
|
|
206
|
+
location_T* then_keyword;
|
|
205
207
|
hb_array_T* statements;
|
|
206
208
|
} AST_ERB_WHEN_NODE_T;
|
|
207
209
|
|
|
@@ -288,6 +290,7 @@ typedef struct AST_ERB_UNLESS_NODE_STRUCT {
|
|
|
288
290
|
token_T* tag_opening;
|
|
289
291
|
token_T* content;
|
|
290
292
|
token_T* tag_closing;
|
|
293
|
+
location_T* then_keyword;
|
|
291
294
|
hb_array_T* statements;
|
|
292
295
|
struct AST_ERB_ELSE_NODE_STRUCT* else_clause;
|
|
293
296
|
struct AST_ERB_END_NODE_STRUCT* end_node;
|
|
@@ -305,6 +308,7 @@ typedef struct AST_ERB_IN_NODE_STRUCT {
|
|
|
305
308
|
token_T* tag_opening;
|
|
306
309
|
token_T* content;
|
|
307
310
|
token_T* tag_closing;
|
|
311
|
+
location_T* then_keyword;
|
|
308
312
|
hb_array_T* statements;
|
|
309
313
|
} AST_ERB_IN_NODE_T;
|
|
310
314
|
|
|
@@ -325,9 +329,9 @@ AST_WHITESPACE_NODE_T* ast_whitespace_node_init(token_T* value, position_T start
|
|
|
325
329
|
AST_ERB_CONTENT_NODE_T* ast_erb_content_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, analyzed_ruby_T* analyzed_ruby, bool parsed, bool valid, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
326
330
|
AST_ERB_END_NODE_T* ast_erb_end_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);
|
|
327
331
|
AST_ERB_ELSE_NODE_T* ast_erb_else_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
328
|
-
AST_ERB_IF_NODE_T* ast_erb_if_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, struct AST_NODE_STRUCT* subsequent, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
332
|
+
AST_ERB_IF_NODE_T* ast_erb_if_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, location_T* then_keyword, hb_array_T* statements, struct AST_NODE_STRUCT* subsequent, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
329
333
|
AST_ERB_BLOCK_NODE_T* ast_erb_block_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* body, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
330
|
-
AST_ERB_WHEN_NODE_T* ast_erb_when_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
334
|
+
AST_ERB_WHEN_NODE_T* ast_erb_when_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);
|
|
331
335
|
AST_ERB_CASE_NODE_T* ast_erb_case_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* children, hb_array_T* conditions, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
332
336
|
AST_ERB_CASE_MATCH_NODE_T* ast_erb_case_match_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* children, hb_array_T* conditions, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
333
337
|
AST_ERB_WHILE_NODE_T* ast_erb_while_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
@@ -336,9 +340,9 @@ AST_ERB_FOR_NODE_T* ast_erb_for_node_init(token_T* tag_opening, token_T* content
|
|
|
336
340
|
AST_ERB_RESCUE_NODE_T* ast_erb_rescue_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, struct AST_ERB_RESCUE_NODE_STRUCT* subsequent, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
337
341
|
AST_ERB_ENSURE_NODE_T* ast_erb_ensure_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
338
342
|
AST_ERB_BEGIN_NODE_T* ast_erb_begin_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, 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);
|
|
339
|
-
AST_ERB_UNLESS_NODE_T* ast_erb_unless_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
343
|
+
AST_ERB_UNLESS_NODE_T* ast_erb_unless_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, location_T* then_keyword, hb_array_T* statements, struct AST_ERB_ELSE_NODE_STRUCT* else_clause, struct AST_ERB_END_NODE_STRUCT* end_node, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
340
344
|
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);
|
|
341
|
-
AST_ERB_IN_NODE_T* ast_erb_in_node_init(token_T* tag_opening, token_T* content, token_T* tag_closing, hb_array_T* statements, position_T start_position, position_T end_position, hb_array_T* errors);
|
|
345
|
+
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);
|
|
342
346
|
|
|
343
347
|
hb_string_T ast_node_type_to_string(AST_NODE_T* node);
|
|
344
348
|
hb_string_T ast_node_human_type(AST_NODE_T* node);
|
data/src/include/location.h
CHANGED
data/src/include/prism_helpers.h
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#ifndef HERB_PRISM_HELPERS_H
|
|
2
2
|
#define HERB_PRISM_HELPERS_H
|
|
3
3
|
|
|
4
|
+
#include "analyzed_ruby.h"
|
|
4
5
|
#include "ast_nodes.h"
|
|
5
6
|
#include "errors.h"
|
|
7
|
+
#include "location.h"
|
|
6
8
|
#include "position.h"
|
|
7
9
|
|
|
8
10
|
#include <prism.h>
|
|
@@ -22,4 +24,8 @@ RUBY_PARSE_ERROR_T* ruby_parse_error_from_prism_error_with_positions(
|
|
|
22
24
|
position_T end
|
|
23
25
|
);
|
|
24
26
|
|
|
27
|
+
location_T* get_then_keyword_location(analyzed_ruby_T* analyzed, const char* source);
|
|
28
|
+
location_T* get_then_keyword_location_wrapped(const char* source, bool is_in_clause);
|
|
29
|
+
location_T* get_then_keyword_location_elsif_wrapped(const char* source);
|
|
30
|
+
|
|
25
31
|
#endif
|
data/src/include/version.h
CHANGED
data/src/location.c
CHANGED
|
@@ -11,3 +11,19 @@ void location_from(
|
|
|
11
11
|
location->start = (position_T) { .line = start_line, .column = start_column };
|
|
12
12
|
location->end = (position_T) { .line = end_line, .column = end_column };
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
void location_from_positions(location_T* location, position_T start, position_T end) {
|
|
16
|
+
location->start = start;
|
|
17
|
+
location->end = end;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
location_T* location_create(position_T start, position_T end) {
|
|
21
|
+
location_T* location = malloc(sizeof(location_T));
|
|
22
|
+
|
|
23
|
+
if (location != NULL) {
|
|
24
|
+
location->start = start;
|
|
25
|
+
location->end = end;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return location;
|
|
29
|
+
}
|
data/src/prism_helpers.c
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
#include "include/prism_helpers.h"
|
|
2
2
|
#include "include/ast_nodes.h"
|
|
3
3
|
#include "include/errors.h"
|
|
4
|
+
#include "include/location.h"
|
|
4
5
|
#include "include/position.h"
|
|
5
6
|
#include "include/util.h"
|
|
7
|
+
#include "include/util/hb_buffer.h"
|
|
6
8
|
|
|
7
9
|
#include <prism.h>
|
|
10
|
+
#include <stdlib.h>
|
|
11
|
+
#include <string.h>
|
|
8
12
|
|
|
9
13
|
const char* pm_error_level_to_string(pm_error_level_t level) {
|
|
10
14
|
switch (level) {
|
|
@@ -50,3 +54,187 @@ RUBY_PARSE_ERROR_T* ruby_parse_error_from_prism_error_with_positions(
|
|
|
50
54
|
end
|
|
51
55
|
);
|
|
52
56
|
}
|
|
57
|
+
|
|
58
|
+
typedef struct {
|
|
59
|
+
pm_location_t then_keyword_loc;
|
|
60
|
+
bool found;
|
|
61
|
+
} then_keyword_search_context_T;
|
|
62
|
+
|
|
63
|
+
static bool has_pm_location(pm_location_t location) {
|
|
64
|
+
return location.start != NULL && location.end != NULL && (location.end - location.start) > 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static bool search_then_keyword_location(const pm_node_t* node, void* data) {
|
|
68
|
+
then_keyword_search_context_T* context = (then_keyword_search_context_T*) data;
|
|
69
|
+
|
|
70
|
+
if (context->found) { return false; }
|
|
71
|
+
|
|
72
|
+
switch (node->type) {
|
|
73
|
+
case PM_IF_NODE: {
|
|
74
|
+
const pm_if_node_t* if_node = (const pm_if_node_t*) node;
|
|
75
|
+
if (has_pm_location(if_node->then_keyword_loc)) {
|
|
76
|
+
context->then_keyword_loc = if_node->then_keyword_loc;
|
|
77
|
+
context->found = true;
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
case PM_UNLESS_NODE: {
|
|
84
|
+
const pm_unless_node_t* unless_node = (const pm_unless_node_t*) node;
|
|
85
|
+
if (has_pm_location(unless_node->then_keyword_loc)) {
|
|
86
|
+
context->then_keyword_loc = unless_node->then_keyword_loc;
|
|
87
|
+
context->found = true;
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
case PM_WHEN_NODE: {
|
|
94
|
+
const pm_when_node_t* when_node = (const pm_when_node_t*) node;
|
|
95
|
+
if (has_pm_location(when_node->then_keyword_loc)) {
|
|
96
|
+
context->then_keyword_loc = when_node->then_keyword_loc;
|
|
97
|
+
context->found = true;
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
case PM_IN_NODE: {
|
|
104
|
+
const pm_in_node_t* in_node = (const pm_in_node_t*) node;
|
|
105
|
+
if (has_pm_location(in_node->then_loc)) {
|
|
106
|
+
context->then_keyword_loc = in_node->then_loc;
|
|
107
|
+
context->found = true;
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
default: break;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
pm_visit_child_nodes(node, search_then_keyword_location, context);
|
|
117
|
+
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
location_T* get_then_keyword_location(analyzed_ruby_T* analyzed, const char* source) {
|
|
122
|
+
if (analyzed == NULL || analyzed->root == NULL || source == NULL) { return NULL; }
|
|
123
|
+
|
|
124
|
+
then_keyword_search_context_T context = { .then_keyword_loc = { .start = NULL, .end = NULL }, .found = false };
|
|
125
|
+
|
|
126
|
+
pm_visit_child_nodes(analyzed->root, search_then_keyword_location, &context);
|
|
127
|
+
|
|
128
|
+
if (!context.found) { return NULL; }
|
|
129
|
+
|
|
130
|
+
size_t start_offset = (size_t) (context.then_keyword_loc.start - analyzed->parser.start);
|
|
131
|
+
size_t end_offset = (size_t) (context.then_keyword_loc.end - analyzed->parser.start);
|
|
132
|
+
|
|
133
|
+
position_T start_position = position_from_source_with_offset(source, start_offset);
|
|
134
|
+
position_T end_position = position_from_source_with_offset(source, end_offset);
|
|
135
|
+
|
|
136
|
+
return location_create(start_position, end_position);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
static location_T* parse_wrapped_and_find_then_keyword(
|
|
140
|
+
hb_buffer_T* buffer,
|
|
141
|
+
const char* source,
|
|
142
|
+
size_t source_length,
|
|
143
|
+
size_t prefix_length,
|
|
144
|
+
size_t adjustment_threshold,
|
|
145
|
+
size_t adjustment_amount
|
|
146
|
+
) {
|
|
147
|
+
pm_parser_t parser;
|
|
148
|
+
pm_parser_init(&parser, (const uint8_t*) hb_buffer_value(buffer), hb_buffer_length(buffer), NULL);
|
|
149
|
+
pm_node_t* root = pm_parse(&parser);
|
|
150
|
+
|
|
151
|
+
if (root == NULL) {
|
|
152
|
+
pm_parser_free(&parser);
|
|
153
|
+
|
|
154
|
+
return NULL;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
then_keyword_search_context_T context = { .then_keyword_loc = { .start = NULL, .end = NULL }, .found = false };
|
|
158
|
+
|
|
159
|
+
pm_visit_child_nodes(root, search_then_keyword_location, &context);
|
|
160
|
+
|
|
161
|
+
location_T* location = NULL;
|
|
162
|
+
|
|
163
|
+
if (context.found) {
|
|
164
|
+
size_t start_offset = (size_t) (context.then_keyword_loc.start - parser.start);
|
|
165
|
+
size_t end_offset = (size_t) (context.then_keyword_loc.end - parser.start);
|
|
166
|
+
|
|
167
|
+
if (start_offset >= prefix_length && end_offset >= prefix_length) {
|
|
168
|
+
start_offset -= prefix_length;
|
|
169
|
+
end_offset -= prefix_length;
|
|
170
|
+
|
|
171
|
+
if (start_offset > adjustment_threshold) {
|
|
172
|
+
start_offset += adjustment_amount;
|
|
173
|
+
end_offset += adjustment_amount;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (start_offset <= source_length && end_offset <= source_length) {
|
|
177
|
+
position_T start_position = position_from_source_with_offset(source, start_offset);
|
|
178
|
+
position_T end_position = position_from_source_with_offset(source, end_offset);
|
|
179
|
+
|
|
180
|
+
location = location_create(start_position, end_position);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
pm_node_destroy(&parser, root);
|
|
186
|
+
pm_parser_free(&parser);
|
|
187
|
+
|
|
188
|
+
return location;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
location_T* get_then_keyword_location_wrapped(const char* source, bool is_in_clause) {
|
|
192
|
+
if (source == NULL) { return NULL; }
|
|
193
|
+
|
|
194
|
+
size_t source_length = strlen(source);
|
|
195
|
+
|
|
196
|
+
hb_buffer_T buffer;
|
|
197
|
+
|
|
198
|
+
if (!hb_buffer_init(&buffer, source_length + 16)) { return NULL; }
|
|
199
|
+
|
|
200
|
+
hb_buffer_append(&buffer, "case x\n");
|
|
201
|
+
size_t prefix_length = hb_buffer_length(&buffer);
|
|
202
|
+
hb_buffer_append(&buffer, source);
|
|
203
|
+
hb_buffer_append(&buffer, "\nend");
|
|
204
|
+
|
|
205
|
+
location_T* location =
|
|
206
|
+
parse_wrapped_and_find_then_keyword(&buffer, source, source_length, prefix_length, SIZE_MAX, 0);
|
|
207
|
+
|
|
208
|
+
free(buffer.value);
|
|
209
|
+
|
|
210
|
+
return location;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
location_T* get_then_keyword_location_elsif_wrapped(const char* source) {
|
|
214
|
+
if (source == NULL) { return NULL; }
|
|
215
|
+
|
|
216
|
+
const char* elsif_position = strstr(source, "elsif");
|
|
217
|
+
|
|
218
|
+
if (elsif_position == NULL) { return NULL; }
|
|
219
|
+
|
|
220
|
+
size_t source_length = strlen(source);
|
|
221
|
+
size_t elsif_offset = (size_t) (elsif_position - source);
|
|
222
|
+
size_t replacement_diff = strlen("elsif") - strlen("if");
|
|
223
|
+
|
|
224
|
+
hb_buffer_T buffer;
|
|
225
|
+
|
|
226
|
+
if (!hb_buffer_init(&buffer, source_length + 8)) { return NULL; }
|
|
227
|
+
|
|
228
|
+
hb_buffer_append_with_length(&buffer, source, elsif_offset);
|
|
229
|
+
hb_buffer_append(&buffer, "if");
|
|
230
|
+
size_t if_end_offset = hb_buffer_length(&buffer);
|
|
231
|
+
hb_buffer_append(&buffer, source + elsif_offset + strlen("elsif"));
|
|
232
|
+
hb_buffer_append(&buffer, "\nend");
|
|
233
|
+
|
|
234
|
+
location_T* location =
|
|
235
|
+
parse_wrapped_and_find_then_keyword(&buffer, source, source_length, 0, if_end_offset, replacement_diff);
|
|
236
|
+
|
|
237
|
+
free(buffer.value);
|
|
238
|
+
|
|
239
|
+
return location;
|
|
240
|
+
}
|
|
@@ -45,6 +45,8 @@ static VALUE rb_<%= node.human %>_from_c_struct(<%= node.struct_type %>* <%= nod
|
|
|
45
45
|
hb_string_T element_source_string = element_source_to_string(<%= node.human %>-><%= field.name %>);
|
|
46
46
|
<%= node.human %>_<%= field.name %> = rb_utf8_str_new(element_source_string.data, element_source_string.length);
|
|
47
47
|
}
|
|
48
|
+
<%- when Herb::Template::LocationField -%>
|
|
49
|
+
VALUE <%= node.human %>_<%= field.name %> = (<%= node.human %>-><%= field.name %> != NULL) ? rb_location_from_c_struct(*<%= node.human %>-><%= field.name %>) : Qnil;
|
|
48
50
|
<%- else -%>
|
|
49
51
|
/* <%= field.inspect %> */
|
|
50
52
|
VALUE <%= node.human %>_<%= field.name %> = Qnil;
|
data/templates/java/nodes.c.erb
CHANGED
|
@@ -37,12 +37,14 @@ jobject <%= node.name %>FromCStruct(JNIEnv* env, <%= node.struct_type %>* <%= no
|
|
|
37
37
|
<%- elsif field.is_a?(Herb::Template::ElementSourceField) -%>
|
|
38
38
|
// TODO: Convert element_source to string
|
|
39
39
|
jstring <%= field.name %> = (*env)->NewStringUTF(env, "");
|
|
40
|
+
<%- elsif field.is_a?(Herb::Template::LocationField) -%>
|
|
41
|
+
jobject <%= field.name %> = <%= node.human %>-><%= field.name %> ? CreateLocation(env, *<%= node.human %>-><%= field.name %>) : NULL;
|
|
40
42
|
<%- elsif field.is_a?(Herb::Template::AnalyzedRubyField) || field.is_a?(Herb::Template::PrismNodeField) -%>
|
|
41
43
|
// Skip <%= field.name %> (<%= field.class.name.split('::').last %>) - not supported in Java yet
|
|
42
44
|
<%- end -%>
|
|
43
45
|
<%- end -%>
|
|
44
46
|
|
|
45
|
-
const char* signature = "(Ljava/lang/String;Lorg/herb/Location;Ljava/util/List;<%- node.fields.each do |f| -%><%- unless f.is_a?(Herb::Template::AnalyzedRubyField) || f.is_a?(Herb::Template::PrismNodeField) -%><%- if f.is_a?(Herb::Template::StringField) -%>Ljava/lang/String;<%- elsif f.is_a?(Herb::Template::TokenField) -%>Lorg/herb/Token;<%- elsif f.is_a?(Herb::Template::BooleanField) -%>Z<%- elsif f.is_a?(Herb::Template::ArrayField) -%>Ljava/util/List;<%- elsif f.is_a?(Herb::Template::NodeField) -%>Lorg/herb/ast/<%= f.specific_kind || 'Node' %>;<%- elsif f.is_a?(Herb::Template::ElementSourceField) -%>Ljava/lang/String;<%- end -%><%- end -%><%- end -%>)V";
|
|
47
|
+
const char* signature = "(Ljava/lang/String;Lorg/herb/Location;Ljava/util/List;<%- node.fields.each do |f| -%><%- unless f.is_a?(Herb::Template::AnalyzedRubyField) || f.is_a?(Herb::Template::PrismNodeField) -%><%- if f.is_a?(Herb::Template::StringField) -%>Ljava/lang/String;<%- elsif f.is_a?(Herb::Template::TokenField) -%>Lorg/herb/Token;<%- elsif f.is_a?(Herb::Template::BooleanField) -%>Z<%- elsif f.is_a?(Herb::Template::ArrayField) -%>Ljava/util/List;<%- elsif f.is_a?(Herb::Template::NodeField) -%>Lorg/herb/ast/<%= f.specific_kind || 'Node' %>;<%- elsif f.is_a?(Herb::Template::ElementSourceField) -%>Ljava/lang/String;<%- elsif f.is_a?(Herb::Template::LocationField) -%>Lorg/herb/Location;<%- end -%><%- end -%><%- end -%>)V";
|
|
46
48
|
jmethodID constructor = (*env)->GetMethodID(env, nodeClass, "<init>", signature);
|
|
47
49
|
if (!constructor) { return NULL; }
|
|
48
50
|
|
|
@@ -26,6 +26,8 @@ class <%= node.name %> extends BaseNode {
|
|
|
26
26
|
<%- end -%>
|
|
27
27
|
<%- elsif field.is_a?(Herb::Template::ElementSourceField) -%>
|
|
28
28
|
private final String <%= field.name %>;
|
|
29
|
+
<%- elsif field.is_a?(Herb::Template::LocationField) -%>
|
|
30
|
+
private final Location <%= field.name %>;
|
|
29
31
|
<%- else -%>
|
|
30
32
|
// private final Object <%= field.name %>;
|
|
31
33
|
<%- end -%>
|
|
@@ -50,6 +52,8 @@ class <%= node.name %> extends BaseNode {
|
|
|
50
52
|
<%= field.specific_kind || 'Node' %> <%= field.name %><%- if node.fields.last != field %>,<% end %>
|
|
51
53
|
<%- elsif field.is_a?(Herb::Template::ElementSourceField) -%>
|
|
52
54
|
String <%= field.name %><%- if node.fields.last != field %>,<% end %>
|
|
55
|
+
<%- elsif field.is_a?(Herb::Template::LocationField) -%>
|
|
56
|
+
Location <%= field.name %><%- if node.fields.last != field %>,<% end %>
|
|
53
57
|
<%- else -%>
|
|
54
58
|
// <%= field.c_type %> <%= field.name %>
|
|
55
59
|
<%- end -%>
|
|
@@ -101,6 +105,11 @@ class <%= node.name %> extends BaseNode {
|
|
|
101
105
|
return <%= field.name %>;
|
|
102
106
|
}
|
|
103
107
|
|
|
108
|
+
<%- elsif field.is_a?(Herb::Template::LocationField) -%>
|
|
109
|
+
public Location get<%= field.name.split('_').map(&:capitalize).join %>() {
|
|
110
|
+
return <%= field.name %>;
|
|
111
|
+
}
|
|
112
|
+
|
|
104
113
|
<%- else -%>
|
|
105
114
|
/*
|
|
106
115
|
public Object get<%= field.name.split('_').map(&:capitalize).join %>() {
|
|
@@ -157,6 +166,8 @@ class <%= node.name %> extends BaseNode {
|
|
|
157
166
|
output.append("<%= symbol %><%= field.name %>: ").append(<%= field.name %> != null ? <%= field.name %>.treeInspect() : "∅").append("\n");
|
|
158
167
|
<%- elsif field.is_a?(Herb::Template::BooleanField) -%>
|
|
159
168
|
output.append("<%= symbol %><%= field.name %>: ").append(<%= field.name %>).append("\n");
|
|
169
|
+
<%- elsif field.is_a?(Herb::Template::LocationField) -%>
|
|
170
|
+
output.append("<%= symbol %><%= field.name %>: ").append(<%= field.name %> != null ? "(location: " + <%= field.name %>.treeInspect() + ")" : "∅").append("\n");
|
|
160
171
|
<%- elsif field.is_a?(Herb::Template::ArrayField) -%>
|
|
161
172
|
output.append("<%= symbol %><%= field.name %>: ").append(inspectArray(<%= field.name %>, "<%= prefix %>"));
|
|
162
173
|
<%- elsif field.is_a?(Herb::Template::NodeField) -%>
|
|
@@ -143,6 +143,8 @@ export interface Serialized<%= node.name %> extends SerializedNode {
|
|
|
143
143
|
<%= field.name %>: boolean;
|
|
144
144
|
<%- when Herb::Template::ElementSourceField -%>
|
|
145
145
|
<%= field.name %>: string;
|
|
146
|
+
<%- when Herb::Template::LocationField -%>
|
|
147
|
+
<%= field.name %>: SerializedLocation | null;
|
|
146
148
|
<%- when Herb::Template::NodeField -%>
|
|
147
149
|
<%- if field.specific_kind -%>
|
|
148
150
|
<%= field.name %>: Serialized<%= field.specific_kind %> | null;
|
|
@@ -170,6 +172,8 @@ export interface <%= node.name %>Props extends BaseNodeProps {
|
|
|
170
172
|
<%= field.name %>: boolean;
|
|
171
173
|
<%- when Herb::Template::ElementSourceField -%>
|
|
172
174
|
<%= field.name %>: string;
|
|
175
|
+
<%- when Herb::Template::LocationField -%>
|
|
176
|
+
<%= field.name %>: Location | null;
|
|
173
177
|
<%- when Herb::Template::NodeField -%>
|
|
174
178
|
<%- if field.specific_kind -%>
|
|
175
179
|
<%= field.name %>: <%= field.specific_kind %> | null;
|
|
@@ -201,6 +205,8 @@ export class <%= node.name %> extends Node {
|
|
|
201
205
|
readonly <%= field.name %>: boolean;
|
|
202
206
|
<%- when Herb::Template::ElementSourceField -%>
|
|
203
207
|
readonly <%= field.name %>: string;
|
|
208
|
+
<%- when Herb::Template::LocationField -%>
|
|
209
|
+
readonly <%= field.name %>: Location | null;
|
|
204
210
|
<%- when Herb::Template::NodeField -%>
|
|
205
211
|
<%- if field.specific_kind -%>
|
|
206
212
|
readonly <%= field.name %>: <%= field.specific_kind %> | null;
|
|
@@ -239,6 +245,8 @@ export class <%= node.name %> extends Node {
|
|
|
239
245
|
<%= field.name %>: data.<%= field.name %>,
|
|
240
246
|
<%- when Herb::Template::ElementSourceField -%>
|
|
241
247
|
<%= field.name %>: data.<%= field.name %>,
|
|
248
|
+
<%- when Herb::Template::LocationField -%>
|
|
249
|
+
<%= field.name %>: data.<%= field.name %> ? Location.from(data.<%= field.name %>) : null,
|
|
242
250
|
<%- when Herb::Template::NodeField -%>
|
|
243
251
|
<%= field.name %>: data.<%= field.name %> ? fromSerializedNode((data.<%= field.name %>)) : null,
|
|
244
252
|
<%- when Herb::Template::ArrayField -%>
|
|
@@ -268,6 +276,8 @@ export class <%= node.name %> extends Node {
|
|
|
268
276
|
this.<%= field.name %> = props.<%= field.name %>;
|
|
269
277
|
<%- when Herb::Template::ElementSourceField -%>
|
|
270
278
|
this.<%= field.name %> = props.<%= field.name %>;
|
|
279
|
+
<%- when Herb::Template::LocationField -%>
|
|
280
|
+
this.<%= field.name %> = props.<%= field.name %>;
|
|
271
281
|
<%- when Herb::Template::PrismNodeField, Herb::Template::AnalyzedRubyField -%>
|
|
272
282
|
// no-op for <%= field.name %>
|
|
273
283
|
<%- else -%>
|
|
@@ -325,6 +335,8 @@ export class <%= node.name %> extends Node {
|
|
|
325
335
|
<%= field.name %>: this.<%= field.name %>,
|
|
326
336
|
<%- when Herb::Template::ElementSourceField -%>
|
|
327
337
|
<%= field.name %>: this.<%= field.name %>,
|
|
338
|
+
<%- when Herb::Template::LocationField -%>
|
|
339
|
+
<%= field.name %>: this.<%= field.name %> ? this.<%= field.name %>.toJSON() : null,
|
|
328
340
|
<%- when Herb::Template::NodeField -%>
|
|
329
341
|
<%= field.name %>: this.<%= field.name %> ? this.<%= field.name %>.toJSON() : null,
|
|
330
342
|
<%- when Herb::Template::ArrayField -%>
|
|
@@ -355,6 +367,8 @@ export class <%= node.name %> extends Node {
|
|
|
355
367
|
output += `<%= name %>${typeof this.<%= field.name %> === 'boolean' ? String(this.<%= field.name %>) : "∅"}\n`;
|
|
356
368
|
<%- when Herb::Template::ElementSourceField -%>
|
|
357
369
|
output += `<%= name %>${this.<%= field.name %> ? JSON.stringify(this.<%= field.name %>) : "∅"}\n`;
|
|
370
|
+
<%- when Herb::Template::LocationField -%>
|
|
371
|
+
output += `<%= name %>${this.<%= field.name %> ? "(location: " + this.<%= field.name %>.treeInspect() + ")" : "∅"}\n`;
|
|
358
372
|
<%- when Herb::Template::NodeField -%>
|
|
359
373
|
output += `<%= name %>${this.inspectNode(this.<%= field.name %>, "<%= (node.fields.last == field) ? " " : "│ " %>")}`;
|
|
360
374
|
<%- when Herb::Template::ArrayField -%>
|
|
@@ -61,6 +61,15 @@ napi_value <%= node.human %>NodeFromCStruct(napi_env env, <%= node.struct_type %
|
|
|
61
61
|
napi_value <%= field.name %> = CreateStringFromHbString(env, element_source_to_string(<%= node.human %>-><%= field.name %>));
|
|
62
62
|
napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
|
|
63
63
|
|
|
64
|
+
<%- when Herb::Template::LocationField -%>
|
|
65
|
+
napi_value <%= field.name %>;
|
|
66
|
+
if (<%= node.human %>-><%= field.name %> != NULL) {
|
|
67
|
+
<%= field.name %> = CreateLocation(env, *<%= node.human %>-><%= field.name %>);
|
|
68
|
+
} else {
|
|
69
|
+
napi_get_null(env, &<%= field.name %>);
|
|
70
|
+
}
|
|
71
|
+
napi_set_named_property(env, result, "<%= field.name %>", <%= field.name %>);
|
|
72
|
+
|
|
64
73
|
<%- else -%>
|
|
65
74
|
napi_value <%= field.name %>;
|
|
66
75
|
napi_get_null(env, &<%= field.name %>);
|
|
@@ -85,6 +85,10 @@ module Herb
|
|
|
85
85
|
output += white("<%= symbol %> <%= field.name %>: ")
|
|
86
86
|
output += [true, false].include?(<%= field.name %>) ? bold(magenta(<%= field.name %>.to_s)) : magenta("∅")
|
|
87
87
|
output += "\n"
|
|
88
|
+
<%- when Herb::Template::LocationField -%>
|
|
89
|
+
output += white("<%= symbol %> <%= field.name %>: ")
|
|
90
|
+
output += <%= field.name %> ? dimmed("(location: #{<%= field.name %>.tree_inspect})") : magenta("∅")
|
|
91
|
+
output += "\n"
|
|
88
92
|
<%- when Herb::Template::ElementSourceField -%>
|
|
89
93
|
output += white("<%= symbol %> <%= field.name %>: #{green(<%= field.name %>.inspect)}\n")
|
|
90
94
|
<%- when Herb::Template::PrismNodeField -%>
|
|
@@ -105,6 +105,14 @@ unsafe fn convert_token_field(token_ptr: *mut token_T) -> Option<crate::Token> {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
unsafe fn convert_location_field(location_ptr: *const location_T) -> Option<Location> {
|
|
109
|
+
if location_ptr.is_null() {
|
|
110
|
+
None
|
|
111
|
+
} else {
|
|
112
|
+
Some(convert_location(*location_ptr))
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
108
116
|
unsafe fn convert_children(children_array: *mut hb_array_T) -> Vec<AnyNode> {
|
|
109
117
|
if children_array.is_null() {
|
|
110
118
|
return Vec::new();
|
|
@@ -212,6 +220,8 @@ unsafe fn convert_node(node_ptr: *const c_void) -> Option<AnyNode> {
|
|
|
212
220
|
<%- else -%>
|
|
213
221
|
<%= field.name %>: convert_node_field((*c_node_ptr).<%= field.name %> as *mut c_void),
|
|
214
222
|
<%- end -%>
|
|
223
|
+
<%- when Herb::Template::LocationField -%>
|
|
224
|
+
<%= field.name %>: convert_location_field((*c_node_ptr).<%= field.name %>),
|
|
215
225
|
<%- end -%>
|
|
216
226
|
<%- end -%>
|
|
217
227
|
})
|
|
@@ -253,6 +253,8 @@ pub struct <%= node.name %> {
|
|
|
253
253
|
<%- end -%>
|
|
254
254
|
<%- when Herb::Template::ElementSourceField -%>
|
|
255
255
|
pub <%= field.name %>: String,
|
|
256
|
+
<%- when Herb::Template::LocationField -%>
|
|
257
|
+
pub <%= field.name %>: Option<Location>,
|
|
256
258
|
<%- end -%>
|
|
257
259
|
<%- end -%>
|
|
258
260
|
}
|
|
@@ -361,6 +363,8 @@ impl Node for <%= node.name %> {
|
|
|
361
363
|
output.push_str(&format!("{}{}: {}", "<%= symbol %>".white(), "<%= field.name %>".white(), format_array_value(&self.<%= field.name %>, &"<%= is_last ? " " : "│ " %>".white().to_string())));
|
|
362
364
|
<%- when Herb::Template::NodeField -%>
|
|
363
365
|
output.push_str(&format!("{}{}: {}", "<%= symbol %>".white(), "<%= field.name %>".white(), format_node_value(&self.<%= field.name %>, &"<%= is_last ? " " : "│ " %>".white().to_string(), <%= !is_last %>)));
|
|
366
|
+
<%- when Herb::Template::LocationField -%>
|
|
367
|
+
output.push_str(&format!("{}{}: {}\n", "<%= symbol %>".white(), "<%= field.name %>".white(), self.<%= field.name %>.as_ref().map(|l| format!("(location: {})", l).dimmed().to_string()).unwrap_or_else(|| "∅".magenta().to_string())));
|
|
364
368
|
<%- end -%>
|
|
365
369
|
<%- end -%>
|
|
366
370
|
<%- else -%>
|
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
<%= node.human %>-><%= field.name %> = <%= field.name %>;
|
|
41
41
|
<%- when Herb::Template::VoidPointerField -%>
|
|
42
42
|
<%= node.human %>-><%= field.name %> = <%= field.name %>;
|
|
43
|
+
<%- when Herb::Template::LocationField -%>
|
|
44
|
+
<%= node.human %>-><%= field.name %> = <%= field.name %>;
|
|
43
45
|
<%- else -%>
|
|
44
46
|
<%= field.inspect %>
|
|
45
47
|
<%- end -%>
|
|
@@ -123,6 +125,8 @@ static void ast_free_<%= node.human %>(<%= node.struct_type %>* <%= node.human %
|
|
|
123
125
|
free(<%= node.human %>-><%= field.name %>);
|
|
124
126
|
<%- when Herb::Template::BooleanField -%>
|
|
125
127
|
<%- when Herb::Template::ElementSourceField -%>
|
|
128
|
+
<%- when Herb::Template::LocationField -%>
|
|
129
|
+
if (<%= node.human %>-><%= field.name %> != NULL) { free(<%= node.human %>-><%= field.name %>); }
|
|
126
130
|
<%- else -%>
|
|
127
131
|
<%= field.inspect %>
|
|
128
132
|
<%- end -%>
|
|
@@ -87,6 +87,20 @@ void ast_pretty_print_node(AST_NODE_T* node, const size_t indent, const size_t r
|
|
|
87
87
|
pretty_print_label(hb_string("<%= field.name %>"), indent, relative_indent, <%= last %>, buffer);
|
|
88
88
|
hb_buffer_append(buffer, " ?\n");
|
|
89
89
|
|
|
90
|
+
<%- when Herb::Template::LocationField -%>
|
|
91
|
+
pretty_print_label(hb_string("<%= field.name %>"), indent, relative_indent, <%= last %>, buffer);
|
|
92
|
+
if (<%= node.human %>-><%= field.name %>) {
|
|
93
|
+
char <%= field.name %>_location_string[128];
|
|
94
|
+
sprintf(<%= field.name %>_location_string, " (location: (%u:%u)-(%u:%u))\n",
|
|
95
|
+
<%= node.human %>-><%= field.name %>->start.line,
|
|
96
|
+
<%= node.human %>-><%= field.name %>->start.column,
|
|
97
|
+
<%= node.human %>-><%= field.name %>->end.line,
|
|
98
|
+
<%= node.human %>-><%= field.name %>->end.column);
|
|
99
|
+
hb_buffer_append(buffer, <%= field.name %>_location_string);
|
|
100
|
+
} else {
|
|
101
|
+
hb_buffer_append(buffer, " ∅\n");
|
|
102
|
+
}
|
|
103
|
+
|
|
90
104
|
<%- else -%>
|
|
91
105
|
<%= field.inspect %>
|
|
92
106
|
<%- end -%>
|
data/templates/template.rb
CHANGED
|
@@ -117,6 +117,16 @@ module Herb
|
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
+
class LocationField < Field
|
|
121
|
+
def ruby_type
|
|
122
|
+
"Herb::Location"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def c_type
|
|
126
|
+
"location_T*"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
120
130
|
class IntegerField < Field
|
|
121
131
|
def ruby_type
|
|
122
132
|
"Integer"
|
|
@@ -210,6 +220,7 @@ module Herb
|
|
|
210
220
|
when "token_type" then TokenTypeField
|
|
211
221
|
when "string" then StringField
|
|
212
222
|
when "position" then PositionField
|
|
223
|
+
when "location" then LocationField
|
|
213
224
|
when "size_t" then SizeTField
|
|
214
225
|
when "boolean" then BooleanField
|
|
215
226
|
when "prism_node" then PrismNodeField
|
|
@@ -39,6 +39,12 @@ val <%= node.name %>FromCStruct(<%= node.struct_type %>* <%= node.human %>) {
|
|
|
39
39
|
result.set("<%= field.name %>", NodesArrayFromCArray(<%= node.human %>-><%= field.name %>));
|
|
40
40
|
<%- when Herb::Template::ElementSourceField -%>
|
|
41
41
|
result.set("<%= field.name %>", CreateStringFromHbString(element_source_to_string(<%= node.human %>-><%= field.name %>)));
|
|
42
|
+
<%- when Herb::Template::LocationField -%>
|
|
43
|
+
if (<%= node.human %>-><%= field.name %>) {
|
|
44
|
+
result.set("<%= field.name %>", CreateLocation(*<%= node.human %>-><%= field.name %>));
|
|
45
|
+
} else {
|
|
46
|
+
result.set("<%= field.name %>", val::null());
|
|
47
|
+
}
|
|
42
48
|
<%- else -%>
|
|
43
49
|
result.set("<%= field.name %>", val::null());
|
|
44
50
|
<%- end -%>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
/**
|
|
15
15
|
* The minor version of the Prism library as an int.
|
|
16
16
|
*/
|
|
17
|
-
#define PRISM_VERSION_MINOR
|
|
17
|
+
#define PRISM_VERSION_MINOR 8
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* The patch version of the Prism library as an int.
|
|
@@ -24,6 +24,6 @@
|
|
|
24
24
|
/**
|
|
25
25
|
* The version of the Prism library as a constant string.
|
|
26
26
|
*/
|
|
27
|
-
#define PRISM_VERSION "1.
|
|
27
|
+
#define PRISM_VERSION "1.8.0"
|
|
28
28
|
|
|
29
29
|
#endif
|