@herb-tools/node 0.1.1 → 0.3.0
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.
- package/CHANGELOG.md +8 -0
- package/bin/vendor.cjs +103 -0
- package/dist/herb-node.esm.js +1 -1
- package/extension/extension_helpers.cpp +2 -3
- package/extension/herb.cpp +9 -0
- package/extension/libherb/analyze.c +138 -43
- package/extension/libherb/analyze.h +39 -0
- package/extension/libherb/analyze_helpers.c +44 -1
- package/extension/libherb/analyze_helpers.h +49 -0
- package/extension/libherb/analyzed_ruby.c +10 -1
- package/extension/libherb/analyzed_ruby.h +36 -0
- package/extension/libherb/array.h +33 -0
- package/extension/libherb/ast_node.h +35 -0
- package/extension/libherb/ast_nodes.c +103 -1
- package/extension/libherb/ast_nodes.h +335 -0
- package/extension/libherb/ast_pretty_print.c +60 -0
- package/extension/libherb/ast_pretty_print.h +17 -0
- package/extension/libherb/buffer.c +60 -27
- package/extension/libherb/buffer.h +39 -0
- package/extension/libherb/errors.h +125 -0
- package/extension/libherb/extract.c +57 -20
- package/extension/libherb/extract.h +20 -0
- package/extension/libherb/herb.h +32 -0
- package/extension/libherb/html_util.h +13 -0
- package/extension/libherb/include/analyze.h +3 -0
- package/extension/libherb/include/analyze_helpers.h +6 -0
- package/extension/libherb/include/analyzed_ruby.h +3 -0
- package/extension/libherb/include/ast_nodes.h +32 -0
- package/extension/libherb/include/buffer.h +5 -2
- package/extension/libherb/include/lexer_peek_helpers.h +2 -2
- package/extension/libherb/include/macros.h +2 -2
- package/extension/libherb/include/version.h +1 -1
- package/extension/libherb/io.h +9 -0
- package/extension/libherb/json.h +28 -0
- package/extension/libherb/lexer.c +1 -1
- package/extension/libherb/lexer.h +13 -0
- package/extension/libherb/lexer_peek_helpers.h +23 -0
- package/extension/libherb/lexer_struct.h +32 -0
- package/extension/libherb/location.h +25 -0
- package/extension/libherb/macros.h +10 -0
- package/extension/libherb/memory.h +12 -0
- package/extension/libherb/parser.c +17 -7
- package/extension/libherb/parser.h +22 -0
- package/extension/libherb/parser_helpers.h +33 -0
- package/extension/libherb/position.h +22 -0
- package/extension/libherb/pretty_print.h +53 -0
- package/extension/libherb/prism_helpers.h +18 -0
- package/extension/libherb/range.h +23 -0
- package/extension/libherb/ruby_parser.h +6 -0
- package/extension/libherb/token.c +1 -1
- package/extension/libherb/token.h +25 -0
- package/extension/libherb/token_matchers.h +21 -0
- package/extension/libherb/token_struct.h +51 -0
- package/extension/libherb/util.c +3 -1
- package/extension/libherb/util.h +25 -0
- package/extension/libherb/version.h +6 -0
- package/extension/libherb/visitor.c +36 -0
- package/extension/libherb/visitor.h +11 -0
- package/extension/nodes.cpp +117 -0
- package/extension/nodes.h +3 -0
- package/package.json +12 -20
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#ifndef HERB_MEMORY_H
|
|
2
|
+
#define HERB_MEMORY_H
|
|
3
|
+
|
|
4
|
+
#include <stddef.h>
|
|
5
|
+
|
|
6
|
+
void* safe_malloc(size_t size);
|
|
7
|
+
void* safe_realloc(void* pointer, size_t new_size);
|
|
8
|
+
|
|
9
|
+
void* nullable_safe_malloc(size_t size);
|
|
10
|
+
void* nullable_safe_realloc(void* pointer, size_t new_size);
|
|
11
|
+
|
|
12
|
+
#endif
|
|
@@ -124,10 +124,9 @@ static AST_HTML_DOCTYPE_NODE_T* parser_parse_html_doctype(parser_T* parser) {
|
|
|
124
124
|
return doctype;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser) {
|
|
127
|
+
static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser, array_T* document_errors) {
|
|
128
128
|
position_T* start = position_copy(parser->current_token->location->start);
|
|
129
129
|
|
|
130
|
-
array_T* errors = array_init(8);
|
|
131
130
|
buffer_T content = buffer_new();
|
|
132
131
|
|
|
133
132
|
while (token_is_none_of(
|
|
@@ -142,16 +141,18 @@ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser) {
|
|
|
142
141
|
if (token_is(parser, TOKEN_ERROR)) {
|
|
143
142
|
buffer_free(&content);
|
|
144
143
|
|
|
145
|
-
token_T* token = parser_consume_expected(parser, TOKEN_ERROR,
|
|
144
|
+
token_T* token = parser_consume_expected(parser, TOKEN_ERROR, document_errors);
|
|
146
145
|
append_unexpected_error(
|
|
147
146
|
"Token Error",
|
|
148
147
|
"not TOKEN_ERROR",
|
|
149
148
|
token->value,
|
|
150
149
|
token->location->start,
|
|
151
150
|
token->location->end,
|
|
152
|
-
|
|
151
|
+
document_errors
|
|
153
152
|
);
|
|
153
|
+
|
|
154
154
|
token_free(token);
|
|
155
|
+
position_free(start);
|
|
155
156
|
|
|
156
157
|
return NULL;
|
|
157
158
|
}
|
|
@@ -161,6 +162,8 @@ static AST_HTML_TEXT_NODE_T* parser_parse_text_content(parser_T* parser) {
|
|
|
161
162
|
token_free(token);
|
|
162
163
|
}
|
|
163
164
|
|
|
165
|
+
array_T* errors = array_init(8);
|
|
166
|
+
|
|
164
167
|
if (buffer_length(&content) > 0) {
|
|
165
168
|
AST_HTML_TEXT_NODE_T* text_node =
|
|
166
169
|
ast_html_text_node_init(buffer_value(&content), start, parser->current_token->location->start, errors);
|
|
@@ -265,7 +268,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser
|
|
|
265
268
|
false,
|
|
266
269
|
erb_node->base.location->start,
|
|
267
270
|
erb_node->base.location->end,
|
|
268
|
-
|
|
271
|
+
errors
|
|
269
272
|
);
|
|
270
273
|
}
|
|
271
274
|
|
|
@@ -284,7 +287,7 @@ static AST_HTML_ATTRIBUTE_VALUE_NODE_T* parser_parse_html_attribute_value(parser
|
|
|
284
287
|
false,
|
|
285
288
|
literal->base.location->start,
|
|
286
289
|
literal->base.location->end,
|
|
287
|
-
|
|
290
|
+
errors
|
|
288
291
|
);
|
|
289
292
|
}
|
|
290
293
|
|
|
@@ -400,6 +403,9 @@ static AST_HTML_OPEN_TAG_NODE_T* parser_parse_html_open_tag(parser_T* parser) {
|
|
|
400
403
|
token_free(tag_start);
|
|
401
404
|
token_free(tag_name);
|
|
402
405
|
|
|
406
|
+
array_free(&children);
|
|
407
|
+
array_free(&errors);
|
|
408
|
+
|
|
403
409
|
return NULL;
|
|
404
410
|
}
|
|
405
411
|
|
|
@@ -617,7 +623,7 @@ static void parser_parse_in_data_state(parser_T* parser, array_T* children, arra
|
|
|
617
623
|
TOKEN_UNDERSCORE,
|
|
618
624
|
TOKEN_WHITESPACE
|
|
619
625
|
)) {
|
|
620
|
-
array_append(children, parser_parse_text_content(parser));
|
|
626
|
+
array_append(children, parser_parse_text_content(parser, errors));
|
|
621
627
|
continue;
|
|
622
628
|
}
|
|
623
629
|
|
|
@@ -650,6 +656,10 @@ static void parser_parse_stray_closing_tags(parser_T* parser, array_T* children,
|
|
|
650
656
|
while (token_is_not(parser, TOKEN_EOF)) {
|
|
651
657
|
if (token_is_not(parser, TOKEN_HTML_TAG_START_CLOSE)) {
|
|
652
658
|
parser_append_unexpected_token_error(parser, TOKEN_HTML_TAG_START_CLOSE, errors);
|
|
659
|
+
|
|
660
|
+
token_T* unexpected = parser_advance(parser);
|
|
661
|
+
token_free(unexpected);
|
|
662
|
+
|
|
653
663
|
continue;
|
|
654
664
|
}
|
|
655
665
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#ifndef HERB_PARSER_H
|
|
2
|
+
#define HERB_PARSER_H
|
|
3
|
+
|
|
4
|
+
#include "array.h"
|
|
5
|
+
#include "ast_node.h"
|
|
6
|
+
#include "lexer.h"
|
|
7
|
+
|
|
8
|
+
typedef struct PARSER_STRUCT {
|
|
9
|
+
lexer_T* lexer;
|
|
10
|
+
token_T* current_token;
|
|
11
|
+
array_T* open_tags_stack;
|
|
12
|
+
} parser_T;
|
|
13
|
+
|
|
14
|
+
parser_T* parser_init(lexer_T* lexer);
|
|
15
|
+
|
|
16
|
+
AST_DOCUMENT_NODE_T* parser_parse(parser_T* parser);
|
|
17
|
+
|
|
18
|
+
size_t parser_sizeof(void);
|
|
19
|
+
|
|
20
|
+
void parser_free(parser_T* parser);
|
|
21
|
+
|
|
22
|
+
#endif
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#ifndef HERB_PARSER_HELPERS_H
|
|
2
|
+
#define HERB_PARSER_HELPERS_H
|
|
3
|
+
|
|
4
|
+
#include "array.h"
|
|
5
|
+
#include "ast_nodes.h"
|
|
6
|
+
#include "buffer.h"
|
|
7
|
+
#include "errors.h"
|
|
8
|
+
#include "parser.h"
|
|
9
|
+
#include "token.h"
|
|
10
|
+
|
|
11
|
+
void parser_push_open_tag(const parser_T* parser, token_T* tag_name);
|
|
12
|
+
bool parser_check_matching_tag(const parser_T* parser, const char* tag_name);
|
|
13
|
+
token_T* parser_pop_open_tag(const parser_T* parser);
|
|
14
|
+
|
|
15
|
+
void parser_append_unexpected_error(parser_T* parser, const char* description, const char* expected, array_T* errors);
|
|
16
|
+
void parser_append_unexpected_token_error(parser_T* parser, token_type_T expected_type, array_T* errors);
|
|
17
|
+
|
|
18
|
+
void parser_append_literal_node_from_buffer(
|
|
19
|
+
const parser_T* parser, buffer_T* buffer, array_T* children, position_T* start
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
bool parser_in_svg_context(const parser_T* parser);
|
|
23
|
+
|
|
24
|
+
token_T* parser_advance(parser_T* parser);
|
|
25
|
+
token_T* parser_consume_if_present(parser_T* parser, token_type_T type);
|
|
26
|
+
token_T* parser_consume_expected(parser_T* parser, token_type_T type, array_T* array);
|
|
27
|
+
|
|
28
|
+
AST_HTML_ELEMENT_NODE_T* parser_handle_missing_close_tag(
|
|
29
|
+
AST_HTML_OPEN_TAG_NODE_T* open_tag, array_T* body, array_T* errors
|
|
30
|
+
);
|
|
31
|
+
void parser_handle_mismatched_tags(const parser_T* parser, const AST_HTML_CLOSE_TAG_NODE_T* close_tag, array_T* errors);
|
|
32
|
+
|
|
33
|
+
#endif
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#ifndef HERB_POSITION_H
|
|
2
|
+
#define HERB_POSITION_H
|
|
3
|
+
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
|
|
6
|
+
typedef struct POSITION_STRUCT {
|
|
7
|
+
size_t line;
|
|
8
|
+
size_t column;
|
|
9
|
+
} position_T;
|
|
10
|
+
|
|
11
|
+
position_T* position_init(size_t line, size_t column);
|
|
12
|
+
|
|
13
|
+
size_t position_line(const position_T* position);
|
|
14
|
+
size_t position_column(const position_T* position);
|
|
15
|
+
|
|
16
|
+
size_t position_sizeof(void);
|
|
17
|
+
|
|
18
|
+
position_T* position_copy(position_T* position);
|
|
19
|
+
|
|
20
|
+
void position_free(position_T* position);
|
|
21
|
+
|
|
22
|
+
#endif
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#ifndef HERB_PRETTY_PRINT_H
|
|
2
|
+
#define HERB_PRETTY_PRINT_H
|
|
3
|
+
|
|
4
|
+
#include "analyzed_ruby.h"
|
|
5
|
+
#include "ast_nodes.h"
|
|
6
|
+
#include "buffer.h"
|
|
7
|
+
#include "location.h"
|
|
8
|
+
|
|
9
|
+
#include <stdbool.h>
|
|
10
|
+
|
|
11
|
+
void pretty_print_indent(buffer_T* buffer, size_t indent);
|
|
12
|
+
void pretty_print_newline(size_t indent, size_t relative_indent, buffer_T* buffer);
|
|
13
|
+
void pretty_print_label(const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer);
|
|
14
|
+
|
|
15
|
+
void pretty_print_position_property(
|
|
16
|
+
position_T* position, const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
void pretty_print_location(location_T* location, buffer_T* buffer);
|
|
20
|
+
|
|
21
|
+
void pretty_print_property(
|
|
22
|
+
const char* name, const char* value, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
void pretty_print_size_t_property(
|
|
26
|
+
size_t value, const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
void pretty_print_string_property(
|
|
30
|
+
const char* string, const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
void pretty_print_quoted_property(
|
|
34
|
+
const char* name, const char* value, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
void pretty_print_boolean_property(
|
|
38
|
+
const char* name, bool value, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
void pretty_print_token_property(
|
|
42
|
+
token_T* token, const char* name, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
void pretty_print_array(
|
|
46
|
+
const char* name, array_T* array, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
void pretty_print_errors(AST_NODE_T* node, size_t indent, size_t relative_indent, bool last_property, buffer_T* buffer);
|
|
50
|
+
|
|
51
|
+
void pretty_print_analyed_ruby(analyzed_ruby_T* analyzed, const char* source);
|
|
52
|
+
|
|
53
|
+
#endif
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#ifndef HERB_PRISM_HELPERS_H
|
|
2
|
+
#define HERB_PRISM_HELPERS_H
|
|
3
|
+
|
|
4
|
+
#include "ast_nodes.h"
|
|
5
|
+
#include "errors.h"
|
|
6
|
+
#include "position.h"
|
|
7
|
+
|
|
8
|
+
#include <prism.h>
|
|
9
|
+
|
|
10
|
+
const char* pm_error_level_to_string(pm_error_level_t level);
|
|
11
|
+
|
|
12
|
+
RUBY_PARSE_ERROR_T* ruby_parse_error_from_prism_error(
|
|
13
|
+
const pm_diagnostic_t* error, const AST_NODE_T* node, const char* source, pm_parser_t* parser
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
position_T* position_from_source_with_offset(const char* source, size_t offset);
|
|
17
|
+
|
|
18
|
+
#endif
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#ifndef HERB_RANGE_H
|
|
2
|
+
#define HERB_RANGE_H
|
|
3
|
+
|
|
4
|
+
#include <stdlib.h>
|
|
5
|
+
|
|
6
|
+
typedef struct RANGE_STRUCT {
|
|
7
|
+
size_t from;
|
|
8
|
+
size_t to;
|
|
9
|
+
} range_T;
|
|
10
|
+
|
|
11
|
+
range_T* range_init(size_t from, size_t to);
|
|
12
|
+
|
|
13
|
+
size_t range_from(const range_T* range);
|
|
14
|
+
size_t range_to(const range_T* range);
|
|
15
|
+
size_t range_length(range_T* range);
|
|
16
|
+
|
|
17
|
+
range_T* range_copy(range_T* range);
|
|
18
|
+
|
|
19
|
+
size_t range_sizeof(void);
|
|
20
|
+
|
|
21
|
+
void range_free(range_T* range);
|
|
22
|
+
|
|
23
|
+
#endif
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#ifndef HERB_TOKEN_H
|
|
2
|
+
#define HERB_TOKEN_H
|
|
3
|
+
|
|
4
|
+
#include "lexer_struct.h"
|
|
5
|
+
#include "position.h"
|
|
6
|
+
#include "token_struct.h"
|
|
7
|
+
|
|
8
|
+
token_T* token_init(const char* value, token_type_T type, lexer_T* lexer);
|
|
9
|
+
char* token_to_string(const token_T* token);
|
|
10
|
+
char* token_to_json(const token_T* token);
|
|
11
|
+
const char* token_type_to_string(token_type_T type);
|
|
12
|
+
|
|
13
|
+
char* token_value(const token_T* token);
|
|
14
|
+
int token_type(const token_T* token);
|
|
15
|
+
|
|
16
|
+
position_T* token_start_position(token_T* token);
|
|
17
|
+
position_T* token_end_position(token_T* token);
|
|
18
|
+
|
|
19
|
+
size_t token_sizeof(void);
|
|
20
|
+
|
|
21
|
+
token_T* token_copy(token_T* token);
|
|
22
|
+
|
|
23
|
+
void token_free(token_T* token);
|
|
24
|
+
|
|
25
|
+
#endif
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#ifndef HERB_TOKEN_MATCHERS_H
|
|
2
|
+
#define HERB_TOKEN_MATCHERS_H
|
|
3
|
+
|
|
4
|
+
#include "parser.h"
|
|
5
|
+
#include "token.h"
|
|
6
|
+
|
|
7
|
+
#include <stdarg.h>
|
|
8
|
+
#include <stdbool.h>
|
|
9
|
+
|
|
10
|
+
// This "TOKEN" is used to terminate the va_list arguments in the token_matches_any function
|
|
11
|
+
#define TOKEN_SENTINEL 99999999
|
|
12
|
+
|
|
13
|
+
bool token_is(parser_T* parser, token_type_T expected_type);
|
|
14
|
+
bool token_is_not(parser_T* parser, token_type_T type);
|
|
15
|
+
|
|
16
|
+
bool token_matches_any(token_type_T current_token, token_type_T first_token, ...);
|
|
17
|
+
|
|
18
|
+
#define token_is_any_of(parser, ...) (token_matches_any((parser)->current_token->type, __VA_ARGS__, TOKEN_SENTINEL))
|
|
19
|
+
#define token_is_none_of(parser, ...) (!token_matches_any((parser)->current_token->type, __VA_ARGS__, TOKEN_SENTINEL))
|
|
20
|
+
|
|
21
|
+
#endif
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#ifndef HERB_TOKEN_STRUCT_H
|
|
2
|
+
#define HERB_TOKEN_STRUCT_H
|
|
3
|
+
|
|
4
|
+
#include "location.h"
|
|
5
|
+
#include "range.h"
|
|
6
|
+
|
|
7
|
+
typedef enum {
|
|
8
|
+
TOKEN_WHITESPACE, // ' '
|
|
9
|
+
TOKEN_NBSP, // \xC2\xA0
|
|
10
|
+
TOKEN_NEWLINE, // \n
|
|
11
|
+
TOKEN_IDENTIFIER,
|
|
12
|
+
|
|
13
|
+
TOKEN_HTML_DOCTYPE, // <!DOCTYPE, <!doctype, <!DoCtYpE, <!dOcTyPe
|
|
14
|
+
|
|
15
|
+
TOKEN_HTML_TAG_START, // <
|
|
16
|
+
TOKEN_HTML_TAG_START_CLOSE, // </
|
|
17
|
+
TOKEN_HTML_TAG_END, // >
|
|
18
|
+
TOKEN_HTML_TAG_SELF_CLOSE, // />
|
|
19
|
+
|
|
20
|
+
TOKEN_HTML_COMMENT_START, // <!--
|
|
21
|
+
TOKEN_HTML_COMMENT_END, // -->
|
|
22
|
+
|
|
23
|
+
TOKEN_ERB_START, // <%, <%=, <%#, <%-, <%==, <%%
|
|
24
|
+
TOKEN_ERB_CONTENT, // Ruby Code
|
|
25
|
+
TOKEN_ERB_END, // %>, -%>, %%>
|
|
26
|
+
|
|
27
|
+
TOKEN_LT, // <
|
|
28
|
+
TOKEN_SLASH, // /
|
|
29
|
+
TOKEN_EQUALS, // =
|
|
30
|
+
TOKEN_QUOTE, // ", '
|
|
31
|
+
TOKEN_DASH, // -
|
|
32
|
+
TOKEN_UNDERSCORE, // _
|
|
33
|
+
TOKEN_EXCLAMATION, // !
|
|
34
|
+
TOKEN_SEMICOLON, // ;
|
|
35
|
+
TOKEN_COLON, // :
|
|
36
|
+
TOKEN_PERCENT, // %
|
|
37
|
+
TOKEN_AMPERSAND, // &
|
|
38
|
+
|
|
39
|
+
TOKEN_CHARACTER,
|
|
40
|
+
TOKEN_ERROR,
|
|
41
|
+
TOKEN_EOF,
|
|
42
|
+
} token_type_T;
|
|
43
|
+
|
|
44
|
+
typedef struct TOKEN_STRUCT {
|
|
45
|
+
char* value;
|
|
46
|
+
range_T* range;
|
|
47
|
+
location_T* location;
|
|
48
|
+
token_type_T type;
|
|
49
|
+
} token_T;
|
|
50
|
+
|
|
51
|
+
#endif
|
package/extension/libherb/util.c
CHANGED
|
@@ -43,13 +43,15 @@ int count_newlines(const char* string) {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
char* replace_char(char* string, const char find, const char replace) {
|
|
46
|
+
char* original_string = string;
|
|
47
|
+
|
|
46
48
|
while (*string != '\0') {
|
|
47
49
|
if (*string == find) { *string = replace; }
|
|
48
50
|
|
|
49
51
|
string++;
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
return
|
|
54
|
+
return original_string;
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
char* escape_newlines(const char* input) {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#ifndef HERB_UTIL_H
|
|
2
|
+
#define HERB_UTIL_H
|
|
3
|
+
|
|
4
|
+
#include <stdbool.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
|
|
7
|
+
int is_whitespace(int character);
|
|
8
|
+
int is_newline(int character);
|
|
9
|
+
|
|
10
|
+
int count_in_string(const char* string, char character);
|
|
11
|
+
int count_newlines(const char* string);
|
|
12
|
+
|
|
13
|
+
char* replace_char(char* string, char find, char replace);
|
|
14
|
+
char* escape_newlines(const char* input);
|
|
15
|
+
char* quoted_string(const char* input);
|
|
16
|
+
char* wrap_string(const char* input, char character);
|
|
17
|
+
|
|
18
|
+
bool string_blank(const char* input);
|
|
19
|
+
bool string_present(const char* input);
|
|
20
|
+
|
|
21
|
+
char* herb_strdup(const char* s);
|
|
22
|
+
|
|
23
|
+
char* size_t_to_string(size_t value);
|
|
24
|
+
|
|
25
|
+
#endif
|
|
@@ -199,6 +199,31 @@ void herb_visit_child_nodes(const AST_NODE_T *node, bool (*visitor)(const AST_NO
|
|
|
199
199
|
|
|
200
200
|
} break;
|
|
201
201
|
|
|
202
|
+
case AST_ERB_CASE_MATCH_NODE: {
|
|
203
|
+
const AST_ERB_CASE_MATCH_NODE_T* erb_case_match_node = ((const AST_ERB_CASE_MATCH_NODE_T *) node);
|
|
204
|
+
|
|
205
|
+
if (erb_case_match_node->children != NULL) {
|
|
206
|
+
for (size_t index = 0; index < array_size(erb_case_match_node->children); index++) {
|
|
207
|
+
herb_visit_node(array_get(erb_case_match_node->children, index), visitor, data);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (erb_case_match_node->conditions != NULL) {
|
|
212
|
+
for (size_t index = 0; index < array_size(erb_case_match_node->conditions); index++) {
|
|
213
|
+
herb_visit_node(array_get(erb_case_match_node->conditions, index), visitor, data);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (erb_case_match_node->else_clause != NULL) {
|
|
218
|
+
herb_visit_node((AST_NODE_T *) erb_case_match_node->else_clause, visitor, data);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (erb_case_match_node->end_node != NULL) {
|
|
222
|
+
herb_visit_node((AST_NODE_T *) erb_case_match_node->end_node, visitor, data);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
} break;
|
|
226
|
+
|
|
202
227
|
case AST_ERB_WHILE_NODE: {
|
|
203
228
|
const AST_ERB_WHILE_NODE_T* erb_while_node = ((const AST_ERB_WHILE_NODE_T *) node);
|
|
204
229
|
|
|
@@ -316,6 +341,17 @@ void herb_visit_child_nodes(const AST_NODE_T *node, bool (*visitor)(const AST_NO
|
|
|
316
341
|
|
|
317
342
|
} break;
|
|
318
343
|
|
|
344
|
+
case AST_ERB_IN_NODE: {
|
|
345
|
+
const AST_ERB_IN_NODE_T* erb_in_node = ((const AST_ERB_IN_NODE_T *) node);
|
|
346
|
+
|
|
347
|
+
if (erb_in_node->statements != NULL) {
|
|
348
|
+
for (size_t index = 0; index < array_size(erb_in_node->statements); index++) {
|
|
349
|
+
herb_visit_node(array_get(erb_in_node->statements, index), visitor, data);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
} break;
|
|
354
|
+
|
|
319
355
|
default: break;
|
|
320
356
|
}
|
|
321
357
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#ifndef HERB_VISITOR_H
|
|
2
|
+
#define HERB_VISITOR_H
|
|
3
|
+
|
|
4
|
+
#include "array.h"
|
|
5
|
+
#include "ast_node.h"
|
|
6
|
+
#include "ast_nodes.h"
|
|
7
|
+
|
|
8
|
+
void herb_visit_node(const AST_NODE_T* node, bool (*visitor)(const AST_NODE_T*, void*), void* data);
|
|
9
|
+
void herb_visit_child_nodes(const AST_NODE_T* node, bool (*visitor)(const AST_NODE_T* node, void* data), void* data);
|
|
10
|
+
|
|
11
|
+
#endif
|
package/extension/nodes.cpp
CHANGED
|
@@ -675,6 +675,49 @@ napi_value erb_case_nodeNodeFromCStruct(napi_env env, AST_ERB_CASE_NODE_T* erb_c
|
|
|
675
675
|
napi_set_named_property(env, result, "end_node", end_node);
|
|
676
676
|
|
|
677
677
|
|
|
678
|
+
return result;
|
|
679
|
+
}
|
|
680
|
+
napi_value erb_case_match_nodeNodeFromCStruct(napi_env env, AST_ERB_CASE_MATCH_NODE_T* erb_case_match_node) {
|
|
681
|
+
if (!erb_case_match_node) {
|
|
682
|
+
napi_value null_value;
|
|
683
|
+
napi_get_null(env, &null_value);
|
|
684
|
+
return null_value;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
napi_value result;
|
|
688
|
+
napi_create_object(env, &result);
|
|
689
|
+
|
|
690
|
+
napi_value type = CreateString(env, ast_node_type_to_string(&erb_case_match_node->base));
|
|
691
|
+
napi_set_named_property(env, result, "type", type);
|
|
692
|
+
|
|
693
|
+
napi_value location = CreateLocation(env, erb_case_match_node->base.location);
|
|
694
|
+
napi_set_named_property(env, result, "location", location);
|
|
695
|
+
|
|
696
|
+
napi_value errors = ErrorsArrayFromCArray(env, erb_case_match_node->base.errors);
|
|
697
|
+
napi_set_named_property(env, result, "errors", errors);
|
|
698
|
+
|
|
699
|
+
napi_value tag_opening = CreateToken(env, erb_case_match_node->tag_opening);
|
|
700
|
+
napi_set_named_property(env, result, "tag_opening", tag_opening);
|
|
701
|
+
|
|
702
|
+
napi_value content = CreateToken(env, erb_case_match_node->content);
|
|
703
|
+
napi_set_named_property(env, result, "content", content);
|
|
704
|
+
|
|
705
|
+
napi_value tag_closing = CreateToken(env, erb_case_match_node->tag_closing);
|
|
706
|
+
napi_set_named_property(env, result, "tag_closing", tag_closing);
|
|
707
|
+
|
|
708
|
+
napi_value children = NodesArrayFromCArray(env, erb_case_match_node->children);
|
|
709
|
+
napi_set_named_property(env, result, "children", children);
|
|
710
|
+
|
|
711
|
+
napi_value conditions = NodesArrayFromCArray(env, erb_case_match_node->conditions);
|
|
712
|
+
napi_set_named_property(env, result, "conditions", conditions);
|
|
713
|
+
|
|
714
|
+
napi_value else_clause = NodeFromCStruct(env, (AST_NODE_T*) erb_case_match_node->else_clause);
|
|
715
|
+
napi_set_named_property(env, result, "else_clause", else_clause);
|
|
716
|
+
|
|
717
|
+
napi_value end_node = NodeFromCStruct(env, (AST_NODE_T*) erb_case_match_node->end_node);
|
|
718
|
+
napi_set_named_property(env, result, "end_node", end_node);
|
|
719
|
+
|
|
720
|
+
|
|
678
721
|
return result;
|
|
679
722
|
}
|
|
680
723
|
napi_value erb_while_nodeNodeFromCStruct(napi_env env, AST_ERB_WHILE_NODE_T* erb_while_node) {
|
|
@@ -943,6 +986,71 @@ napi_value erb_unless_nodeNodeFromCStruct(napi_env env, AST_ERB_UNLESS_NODE_T* e
|
|
|
943
986
|
napi_set_named_property(env, result, "end_node", end_node);
|
|
944
987
|
|
|
945
988
|
|
|
989
|
+
return result;
|
|
990
|
+
}
|
|
991
|
+
napi_value erb_yield_nodeNodeFromCStruct(napi_env env, AST_ERB_YIELD_NODE_T* erb_yield_node) {
|
|
992
|
+
if (!erb_yield_node) {
|
|
993
|
+
napi_value null_value;
|
|
994
|
+
napi_get_null(env, &null_value);
|
|
995
|
+
return null_value;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
napi_value result;
|
|
999
|
+
napi_create_object(env, &result);
|
|
1000
|
+
|
|
1001
|
+
napi_value type = CreateString(env, ast_node_type_to_string(&erb_yield_node->base));
|
|
1002
|
+
napi_set_named_property(env, result, "type", type);
|
|
1003
|
+
|
|
1004
|
+
napi_value location = CreateLocation(env, erb_yield_node->base.location);
|
|
1005
|
+
napi_set_named_property(env, result, "location", location);
|
|
1006
|
+
|
|
1007
|
+
napi_value errors = ErrorsArrayFromCArray(env, erb_yield_node->base.errors);
|
|
1008
|
+
napi_set_named_property(env, result, "errors", errors);
|
|
1009
|
+
|
|
1010
|
+
napi_value tag_opening = CreateToken(env, erb_yield_node->tag_opening);
|
|
1011
|
+
napi_set_named_property(env, result, "tag_opening", tag_opening);
|
|
1012
|
+
|
|
1013
|
+
napi_value content = CreateToken(env, erb_yield_node->content);
|
|
1014
|
+
napi_set_named_property(env, result, "content", content);
|
|
1015
|
+
|
|
1016
|
+
napi_value tag_closing = CreateToken(env, erb_yield_node->tag_closing);
|
|
1017
|
+
napi_set_named_property(env, result, "tag_closing", tag_closing);
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
return result;
|
|
1021
|
+
}
|
|
1022
|
+
napi_value erb_in_nodeNodeFromCStruct(napi_env env, AST_ERB_IN_NODE_T* erb_in_node) {
|
|
1023
|
+
if (!erb_in_node) {
|
|
1024
|
+
napi_value null_value;
|
|
1025
|
+
napi_get_null(env, &null_value);
|
|
1026
|
+
return null_value;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
napi_value result;
|
|
1030
|
+
napi_create_object(env, &result);
|
|
1031
|
+
|
|
1032
|
+
napi_value type = CreateString(env, ast_node_type_to_string(&erb_in_node->base));
|
|
1033
|
+
napi_set_named_property(env, result, "type", type);
|
|
1034
|
+
|
|
1035
|
+
napi_value location = CreateLocation(env, erb_in_node->base.location);
|
|
1036
|
+
napi_set_named_property(env, result, "location", location);
|
|
1037
|
+
|
|
1038
|
+
napi_value errors = ErrorsArrayFromCArray(env, erb_in_node->base.errors);
|
|
1039
|
+
napi_set_named_property(env, result, "errors", errors);
|
|
1040
|
+
|
|
1041
|
+
napi_value tag_opening = CreateToken(env, erb_in_node->tag_opening);
|
|
1042
|
+
napi_set_named_property(env, result, "tag_opening", tag_opening);
|
|
1043
|
+
|
|
1044
|
+
napi_value content = CreateToken(env, erb_in_node->content);
|
|
1045
|
+
napi_set_named_property(env, result, "content", content);
|
|
1046
|
+
|
|
1047
|
+
napi_value tag_closing = CreateToken(env, erb_in_node->tag_closing);
|
|
1048
|
+
napi_set_named_property(env, result, "tag_closing", tag_closing);
|
|
1049
|
+
|
|
1050
|
+
napi_value statements = NodesArrayFromCArray(env, erb_in_node->statements);
|
|
1051
|
+
napi_set_named_property(env, result, "statements", statements);
|
|
1052
|
+
|
|
1053
|
+
|
|
946
1054
|
return result;
|
|
947
1055
|
}
|
|
948
1056
|
|
|
@@ -1031,6 +1139,9 @@ napi_value NodeFromCStruct(napi_env env, AST_NODE_T* node) {
|
|
|
1031
1139
|
case AST_ERB_CASE_NODE:
|
|
1032
1140
|
return erb_case_nodeNodeFromCStruct(env, (AST_ERB_CASE_NODE_T*) node);
|
|
1033
1141
|
break;
|
|
1142
|
+
case AST_ERB_CASE_MATCH_NODE:
|
|
1143
|
+
return erb_case_match_nodeNodeFromCStruct(env, (AST_ERB_CASE_MATCH_NODE_T*) node);
|
|
1144
|
+
break;
|
|
1034
1145
|
case AST_ERB_WHILE_NODE:
|
|
1035
1146
|
return erb_while_nodeNodeFromCStruct(env, (AST_ERB_WHILE_NODE_T*) node);
|
|
1036
1147
|
break;
|
|
@@ -1052,6 +1163,12 @@ napi_value NodeFromCStruct(napi_env env, AST_NODE_T* node) {
|
|
|
1052
1163
|
case AST_ERB_UNLESS_NODE:
|
|
1053
1164
|
return erb_unless_nodeNodeFromCStruct(env, (AST_ERB_UNLESS_NODE_T*) node);
|
|
1054
1165
|
break;
|
|
1166
|
+
case AST_ERB_YIELD_NODE:
|
|
1167
|
+
return erb_yield_nodeNodeFromCStruct(env, (AST_ERB_YIELD_NODE_T*) node);
|
|
1168
|
+
break;
|
|
1169
|
+
case AST_ERB_IN_NODE:
|
|
1170
|
+
return erb_in_nodeNodeFromCStruct(env, (AST_ERB_IN_NODE_T*) node);
|
|
1171
|
+
break;
|
|
1055
1172
|
default:
|
|
1056
1173
|
napi_value null_value;
|
|
1057
1174
|
napi_get_null(env, &null_value);
|
package/extension/nodes.h
CHANGED
|
@@ -33,6 +33,7 @@ napi_value erb_if_nodeNodeFromCStruct(napi_env env, AST_ERB_IF_NODE_T* erb_if_no
|
|
|
33
33
|
napi_value erb_block_nodeNodeFromCStruct(napi_env env, AST_ERB_BLOCK_NODE_T* erb_block_node);
|
|
34
34
|
napi_value erb_when_nodeNodeFromCStruct(napi_env env, AST_ERB_WHEN_NODE_T* erb_when_node);
|
|
35
35
|
napi_value erb_case_nodeNodeFromCStruct(napi_env env, AST_ERB_CASE_NODE_T* erb_case_node);
|
|
36
|
+
napi_value erb_case_match_nodeNodeFromCStruct(napi_env env, AST_ERB_CASE_MATCH_NODE_T* erb_case_match_node);
|
|
36
37
|
napi_value erb_while_nodeNodeFromCStruct(napi_env env, AST_ERB_WHILE_NODE_T* erb_while_node);
|
|
37
38
|
napi_value erb_until_nodeNodeFromCStruct(napi_env env, AST_ERB_UNTIL_NODE_T* erb_until_node);
|
|
38
39
|
napi_value erb_for_nodeNodeFromCStruct(napi_env env, AST_ERB_FOR_NODE_T* erb_for_node);
|
|
@@ -40,5 +41,7 @@ napi_value erb_rescue_nodeNodeFromCStruct(napi_env env, AST_ERB_RESCUE_NODE_T* e
|
|
|
40
41
|
napi_value erb_ensure_nodeNodeFromCStruct(napi_env env, AST_ERB_ENSURE_NODE_T* erb_ensure_node);
|
|
41
42
|
napi_value erb_begin_nodeNodeFromCStruct(napi_env env, AST_ERB_BEGIN_NODE_T* erb_begin_node);
|
|
42
43
|
napi_value erb_unless_nodeNodeFromCStruct(napi_env env, AST_ERB_UNLESS_NODE_T* erb_unless_node);
|
|
44
|
+
napi_value erb_yield_nodeNodeFromCStruct(napi_env env, AST_ERB_YIELD_NODE_T* erb_yield_node);
|
|
45
|
+
napi_value erb_in_nodeNodeFromCStruct(napi_env env, AST_ERB_IN_NODE_T* erb_in_node);
|
|
43
46
|
|
|
44
47
|
#endif
|