herb 0.10.1-x86_64-darwin → 0.10.2-x86_64-darwin
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Makefile +1 -1
- data/config.yml +10 -0
- data/ext/herb/error_helpers.c +24 -0
- data/ext/herb/extension.c +15 -0
- data/ext/herb/extension_helpers.c +7 -0
- data/herb.gemspec +1 -0
- data/lib/herb/3.2/herb.bundle +0 -0
- data/lib/herb/3.3/herb.bundle +0 -0
- data/lib/herb/3.4/herb.bundle +0 -0
- data/lib/herb/4.0/herb.bundle +0 -0
- data/lib/herb/action_view/render_analyzer.rb +1 -1
- data/lib/herb/errors.rb +39 -0
- data/lib/herb/parser_options.rb +14 -4
- data/lib/herb/version.rb +1 -1
- data/sig/herb/errors.rbs +18 -0
- data/sig/herb/parser_options.rbs +12 -4
- data/sig/manifest.yaml +13 -0
- data/sig/serialized_ast_errors.rbs +4 -0
- data/src/analyze/analyze_helpers.c +7 -1
- data/src/errors.c +51 -0
- data/src/herb.c +16 -0
- data/src/include/errors.h +8 -0
- data/src/include/lib/hb_clock.h +15 -0
- data/src/include/parser/parser.h +28 -0
- data/src/include/version.h +1 -1
- data/src/parser.c +64 -14
- metadata +4 -4
- data/sig/vendor/did_you_mean.rbs +0 -6
- data/sig/vendor/parallel.rbs +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 339fe63176d8126048bad3435a12b92249d8e4b9912a3709be574fd7878f4346
|
|
4
|
+
data.tar.gz: 76980764cbedbd760aa3415d31bb086a74fa97dc48040576362d65c5b7e29bad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 56e811713231a032ce2d5604d3b3ed6bbc3a78d515d0061d20edd0e61cb9ff40473fc049db0a5759e325529755cdc946fec56054cb30bdbe443a402bba18caf3
|
|
7
|
+
data.tar.gz: 2bf04e3faec918e760216b99653eff3bec8e595e1ab34973787467cf8c3a443e91ab50e6d219d8222cb971eb823e59daaa7ff2ade8deed0b019b9e149c581d68
|
data/Makefile
CHANGED
|
@@ -53,7 +53,7 @@ production_flags = $(warning_flags) -O3 -march=native -flto
|
|
|
53
53
|
shared_library_flags = -fPIC
|
|
54
54
|
|
|
55
55
|
# Default build mode (change this as needed)
|
|
56
|
-
flags = $(warning_flags) $(debug_flags) $(prism_flags) -std=
|
|
56
|
+
flags = $(warning_flags) $(debug_flags) $(prism_flags) -std=gnu99
|
|
57
57
|
|
|
58
58
|
# Separate test compilation flags
|
|
59
59
|
test_flags = $(debug_flags) $(prism_flags) -std=gnu99
|
data/config.yml
CHANGED
|
@@ -486,6 +486,16 @@ errors:
|
|
|
486
486
|
- name: segment
|
|
487
487
|
type: token
|
|
488
488
|
|
|
489
|
+
- name: TimeoutError
|
|
490
|
+
message:
|
|
491
|
+
template: "Parsing timed out after %zu ms."
|
|
492
|
+
arguments:
|
|
493
|
+
- timeout_ms
|
|
494
|
+
|
|
495
|
+
fields:
|
|
496
|
+
- name: timeout_ms
|
|
497
|
+
type: size_t
|
|
498
|
+
|
|
489
499
|
warnings:
|
|
490
500
|
fields: []
|
|
491
501
|
types: []
|
data/ext/herb/error_helpers.c
CHANGED
|
@@ -53,6 +53,7 @@ static VALUE cStrictLocalsMissingParenthesisError;
|
|
|
53
53
|
static VALUE cStrictLocalsDuplicateDeclarationError;
|
|
54
54
|
static VALUE cVoidElementContentError;
|
|
55
55
|
static VALUE cDotNotationCasingError;
|
|
56
|
+
static VALUE cTimeoutError;
|
|
56
57
|
|
|
57
58
|
void rb_init_error_classes(void) {
|
|
58
59
|
mErrors = rb_define_module_under(mHerb, "Errors");
|
|
@@ -94,6 +95,7 @@ void rb_init_error_classes(void) {
|
|
|
94
95
|
cStrictLocalsDuplicateDeclarationError = rb_define_class_under(mErrors, "StrictLocalsDuplicateDeclarationError", cError);
|
|
95
96
|
cVoidElementContentError = rb_define_class_under(mErrors, "VoidElementContentError", cError);
|
|
96
97
|
cDotNotationCasingError = rb_define_class_under(mErrors, "DotNotationCasingError", cError);
|
|
98
|
+
cTimeoutError = rb_define_class_under(mErrors, "TimeoutError", cError);
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
static VALUE rb_unexpected_error_from_c_struct(UNEXPECTED_ERROR_T* unexpected_error) {
|
|
@@ -906,6 +908,27 @@ static VALUE rb_dot_notation_casing_error_from_c_struct(DOT_NOTATION_CASING_ERRO
|
|
|
906
908
|
return rb_class_new_instance(4, args, cDotNotationCasingError);
|
|
907
909
|
};
|
|
908
910
|
|
|
911
|
+
static VALUE rb_timeout_error_from_c_struct(TIMEOUT_ERROR_T* timeout_error) {
|
|
912
|
+
if (timeout_error == NULL) { return Qnil; }
|
|
913
|
+
|
|
914
|
+
ERROR_T* error = &timeout_error->base;
|
|
915
|
+
|
|
916
|
+
VALUE type = rb_string_from_hb_string(error_type_to_string(error));
|
|
917
|
+
VALUE location = rb_location_from_c_struct(error->location);
|
|
918
|
+
VALUE message = rb_string_from_hb_string(error->message);
|
|
919
|
+
|
|
920
|
+
VALUE timeout_error_timeout_ms = ULONG2NUM(timeout_error->timeout_ms);
|
|
921
|
+
|
|
922
|
+
VALUE args[4] = {
|
|
923
|
+
type,
|
|
924
|
+
location,
|
|
925
|
+
message,
|
|
926
|
+
timeout_error_timeout_ms
|
|
927
|
+
};
|
|
928
|
+
|
|
929
|
+
return rb_class_new_instance(4, args, cTimeoutError);
|
|
930
|
+
};
|
|
931
|
+
|
|
909
932
|
|
|
910
933
|
VALUE rb_error_from_c_struct(ERROR_T* error) {
|
|
911
934
|
if (!error) { return Qnil; }
|
|
@@ -948,6 +971,7 @@ VALUE rb_error_from_c_struct(ERROR_T* error) {
|
|
|
948
971
|
case STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR: return rb_strict_locals_duplicate_declaration_error_from_c_struct((STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR_T*) error); break;
|
|
949
972
|
case VOID_ELEMENT_CONTENT_ERROR: return rb_void_element_content_error_from_c_struct((VOID_ELEMENT_CONTENT_ERROR_T*) error); break;
|
|
950
973
|
case DOT_NOTATION_CASING_ERROR: return rb_dot_notation_casing_error_from_c_struct((DOT_NOTATION_CASING_ERROR_T*) error); break;
|
|
974
|
+
case TIMEOUT_ERROR: return rb_timeout_error_from_c_struct((TIMEOUT_ERROR_T*) error); break;
|
|
951
975
|
}
|
|
952
976
|
|
|
953
977
|
return Qnil;
|
data/ext/herb/extension.c
CHANGED
|
@@ -174,6 +174,21 @@ static VALUE Herb_parse(int argc, VALUE* argv, VALUE self) {
|
|
|
174
174
|
if (NIL_P(html)) { html = rb_hash_lookup(options, ID2SYM(rb_intern("html"))); }
|
|
175
175
|
if (!NIL_P(html) && !RTEST(html)) { parser_options.html = false; }
|
|
176
176
|
|
|
177
|
+
VALUE timeout = rb_hash_lookup(options, rb_utf8_str_new_cstr("timeout"));
|
|
178
|
+
if (NIL_P(timeout)) { timeout = rb_hash_lookup(options, ID2SYM(rb_intern("timeout"))); }
|
|
179
|
+
if (!NIL_P(timeout)) { parser_options.timeout_ms = (uint32_t) (NUM2DBL(timeout) * 1000); }
|
|
180
|
+
|
|
181
|
+
VALUE max_errors_sentinel = ID2SYM(rb_intern("__not_set__"));
|
|
182
|
+
VALUE max_errors = rb_hash_lookup2(options, rb_utf8_str_new_cstr("max_errors"), max_errors_sentinel);
|
|
183
|
+
|
|
184
|
+
if (max_errors == max_errors_sentinel) {
|
|
185
|
+
max_errors = rb_hash_lookup2(options, ID2SYM(rb_intern("max_errors")), max_errors_sentinel);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (max_errors != max_errors_sentinel) {
|
|
189
|
+
parser_options.max_errors = NIL_P(max_errors) ? 0 : (uint32_t) NUM2UINT(max_errors);
|
|
190
|
+
}
|
|
191
|
+
|
|
177
192
|
VALUE arena_stats = rb_hash_lookup(options, rb_utf8_str_new_cstr("arena_stats"));
|
|
178
193
|
if (NIL_P(arena_stats)) { arena_stats = rb_hash_lookup(options, ID2SYM(rb_intern("arena_stats"))); }
|
|
179
194
|
if (!NIL_P(arena_stats) && RTEST(arena_stats)) { print_arena_stats = true; }
|
|
@@ -95,6 +95,13 @@ VALUE create_parse_result(AST_DOCUMENT_NODE_T* root, VALUE source, const parser_
|
|
|
95
95
|
rb_hash_aset(kwargs, ID2SYM(rb_intern("prism_nodes")), options->prism_nodes ? Qtrue : Qfalse);
|
|
96
96
|
rb_hash_aset(kwargs, ID2SYM(rb_intern("prism_nodes_deep")), options->prism_nodes_deep ? Qtrue : Qfalse);
|
|
97
97
|
rb_hash_aset(kwargs, ID2SYM(rb_intern("prism_program")), options->prism_program ? Qtrue : Qfalse);
|
|
98
|
+
rb_hash_aset(kwargs, ID2SYM(rb_intern("timeout")), DBL2NUM((double) options->timeout_ms / 1000.0));
|
|
99
|
+
|
|
100
|
+
rb_hash_aset(
|
|
101
|
+
kwargs,
|
|
102
|
+
ID2SYM(rb_intern("max_errors")),
|
|
103
|
+
options->max_errors == 0 ? Qnil : UINT2NUM(options->max_errors)
|
|
104
|
+
);
|
|
98
105
|
|
|
99
106
|
VALUE parser_options_args[1] = { kwargs };
|
|
100
107
|
VALUE parser_options = rb_class_new_instance_kw(1, parser_options_args, cParserOptions, RB_PASS_KEYWORDS);
|
data/herb.gemspec
CHANGED
data/lib/herb/3.2/herb.bundle
CHANGED
|
Binary file
|
data/lib/herb/3.3/herb.bundle
CHANGED
|
Binary file
|
data/lib/herb/3.4/herb.bundle
CHANGED
|
Binary file
|
data/lib/herb/4.0/herb.bundle
CHANGED
|
Binary file
|
data/lib/herb/errors.rb
CHANGED
|
@@ -1526,5 +1526,44 @@ module Herb
|
|
|
1526
1526
|
end
|
|
1527
1527
|
end
|
|
1528
1528
|
|
|
1529
|
+
class TimeoutError < Error
|
|
1530
|
+
include Colors
|
|
1531
|
+
|
|
1532
|
+
#| timeout_ms: Integer?,
|
|
1533
|
+
#| }
|
|
1534
|
+
|
|
1535
|
+
attr_reader :timeout_ms #: Integer?
|
|
1536
|
+
|
|
1537
|
+
#: (String, Location?, String, Integer) -> void
|
|
1538
|
+
def initialize(type, location, message, timeout_ms)
|
|
1539
|
+
super(type, location, message)
|
|
1540
|
+
@timeout_ms = timeout_ms
|
|
1541
|
+
end
|
|
1542
|
+
|
|
1543
|
+
#: () -> String
|
|
1544
|
+
def inspect
|
|
1545
|
+
tree_inspect.rstrip.gsub(/\s+$/, "")
|
|
1546
|
+
end
|
|
1547
|
+
|
|
1548
|
+
#: () -> serialized_timeout_error
|
|
1549
|
+
def to_hash
|
|
1550
|
+
super.merge(
|
|
1551
|
+
timeout_ms: timeout_ms
|
|
1552
|
+
) #: Herb::serialized_timeout_error
|
|
1553
|
+
end
|
|
1554
|
+
|
|
1555
|
+
#: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
1556
|
+
def tree_inspect(indent: 0, depth: 0, depth_limit: 25)
|
|
1557
|
+
output = +""
|
|
1558
|
+
|
|
1559
|
+
output += white("@ #{bold(red(error_name))} #{dimmed("(location: #{location&.tree_inspect})\n")}")
|
|
1560
|
+
output += white("├── message: #{green(message.inspect)}\n")
|
|
1561
|
+
output += white("└── timeout_ms: #{green(timeout_ms.inspect)}\n")
|
|
1562
|
+
output += %(\n)
|
|
1563
|
+
|
|
1564
|
+
output.gsub(/^/, " " * indent)
|
|
1565
|
+
end
|
|
1566
|
+
end
|
|
1567
|
+
|
|
1529
1568
|
end
|
|
1530
1569
|
end
|
data/lib/herb/parser_options.rb
CHANGED
|
@@ -12,6 +12,8 @@ module Herb
|
|
|
12
12
|
attr_reader :prism_program #: bool
|
|
13
13
|
attr_reader :prism_nodes #: bool
|
|
14
14
|
attr_reader :prism_nodes_deep #: bool
|
|
15
|
+
attr_reader :timeout #: Numeric
|
|
16
|
+
attr_reader :max_errors #: Integer?
|
|
15
17
|
|
|
16
18
|
DEFAULT_STRICT = true #: bool
|
|
17
19
|
DEFAULT_TRACK_WHITESPACE = false #: bool
|
|
@@ -23,9 +25,11 @@ module Herb
|
|
|
23
25
|
DEFAULT_PRISM_PROGRAM = false #: bool
|
|
24
26
|
DEFAULT_PRISM_NODES = false #: bool
|
|
25
27
|
DEFAULT_PRISM_NODES_DEEP = false #: bool
|
|
28
|
+
DEFAULT_TIMEOUT = 1 #: Numeric
|
|
29
|
+
DEFAULT_MAX_ERRORS = 25 #: Integer
|
|
26
30
|
|
|
27
|
-
#: (?strict: bool, ?track_whitespace: bool, ?analyze: bool, ?action_view_helpers: bool, ?transform_conditionals: bool, ?render_nodes: bool, ?strict_locals: bool, ?prism_nodes: bool, ?prism_nodes_deep: bool, ?prism_program: bool) -> void
|
|
28
|
-
def initialize(strict: DEFAULT_STRICT, track_whitespace: DEFAULT_TRACK_WHITESPACE, analyze: DEFAULT_ANALYZE, action_view_helpers: DEFAULT_ACTION_VIEW_HELPERS, transform_conditionals: DEFAULT_TRANSFORM_CONDITIONALS, render_nodes: DEFAULT_RENDER_NODES, strict_locals: DEFAULT_STRICT_LOCALS, prism_nodes: DEFAULT_PRISM_NODES, prism_nodes_deep: DEFAULT_PRISM_NODES_DEEP, prism_program: DEFAULT_PRISM_PROGRAM)
|
|
31
|
+
#: (?strict: bool, ?track_whitespace: bool, ?analyze: bool, ?action_view_helpers: bool, ?transform_conditionals: bool, ?render_nodes: bool, ?strict_locals: bool, ?prism_nodes: bool, ?prism_nodes_deep: bool, ?prism_program: bool, ?timeout: Numeric) -> void
|
|
32
|
+
def initialize(strict: DEFAULT_STRICT, track_whitespace: DEFAULT_TRACK_WHITESPACE, analyze: DEFAULT_ANALYZE, action_view_helpers: DEFAULT_ACTION_VIEW_HELPERS, transform_conditionals: DEFAULT_TRANSFORM_CONDITIONALS, render_nodes: DEFAULT_RENDER_NODES, strict_locals: DEFAULT_STRICT_LOCALS, prism_nodes: DEFAULT_PRISM_NODES, prism_nodes_deep: DEFAULT_PRISM_NODES_DEEP, prism_program: DEFAULT_PRISM_PROGRAM, timeout: DEFAULT_TIMEOUT, max_errors: DEFAULT_MAX_ERRORS)
|
|
29
33
|
@strict = strict
|
|
30
34
|
@track_whitespace = track_whitespace
|
|
31
35
|
@analyze = analyze
|
|
@@ -36,9 +40,11 @@ module Herb
|
|
|
36
40
|
@prism_nodes = prism_nodes
|
|
37
41
|
@prism_nodes_deep = prism_nodes_deep
|
|
38
42
|
@prism_program = prism_program
|
|
43
|
+
@timeout = timeout
|
|
44
|
+
@max_errors = max_errors
|
|
39
45
|
end
|
|
40
46
|
|
|
41
|
-
#: () -> Hash[Symbol, bool]
|
|
47
|
+
#: () -> Hash[Symbol, (bool | Numeric | nil)]
|
|
42
48
|
def to_h
|
|
43
49
|
{
|
|
44
50
|
strict: @strict,
|
|
@@ -51,6 +57,8 @@ module Herb
|
|
|
51
57
|
prism_nodes: @prism_nodes,
|
|
52
58
|
prism_nodes_deep: @prism_nodes_deep,
|
|
53
59
|
prism_program: @prism_program,
|
|
60
|
+
timeout: @timeout,
|
|
61
|
+
max_errors: @max_errors,
|
|
54
62
|
}
|
|
55
63
|
end
|
|
56
64
|
|
|
@@ -66,7 +74,9 @@ module Herb
|
|
|
66
74
|
"strict_locals=#{@strict_locals}\n " \
|
|
67
75
|
"prism_nodes=#{@prism_nodes}\n " \
|
|
68
76
|
"prism_nodes_deep=#{@prism_nodes_deep}\n " \
|
|
69
|
-
"prism_program=#{@prism_program}
|
|
77
|
+
"prism_program=#{@prism_program}\n " \
|
|
78
|
+
"timeout=#{@timeout}\n " \
|
|
79
|
+
"max_errors=#{@max_errors}>"
|
|
70
80
|
end
|
|
71
81
|
end
|
|
72
82
|
end
|
data/lib/herb/version.rb
CHANGED
data/sig/herb/errors.rbs
CHANGED
|
@@ -694,5 +694,23 @@ module Herb
|
|
|
694
694
|
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
695
695
|
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
696
696
|
end
|
|
697
|
+
|
|
698
|
+
class TimeoutError < Error
|
|
699
|
+
include Colors
|
|
700
|
+
|
|
701
|
+
attr_reader timeout_ms: Integer?
|
|
702
|
+
|
|
703
|
+
# : (String, Location?, String, Integer) -> void
|
|
704
|
+
def initialize: (String, Location?, String, Integer) -> void
|
|
705
|
+
|
|
706
|
+
# : () -> String
|
|
707
|
+
def inspect: () -> String
|
|
708
|
+
|
|
709
|
+
# : () -> serialized_timeout_error
|
|
710
|
+
def to_hash: () -> serialized_timeout_error
|
|
711
|
+
|
|
712
|
+
# : (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
713
|
+
def tree_inspect: (?indent: Integer, ?depth: Integer, ?depth_limit: Integer) -> String
|
|
714
|
+
end
|
|
697
715
|
end
|
|
698
716
|
end
|
data/sig/herb/parser_options.rbs
CHANGED
|
@@ -22,6 +22,10 @@ module Herb
|
|
|
22
22
|
|
|
23
23
|
attr_reader prism_nodes_deep: bool
|
|
24
24
|
|
|
25
|
+
attr_reader timeout: Numeric
|
|
26
|
+
|
|
27
|
+
attr_reader max_errors: Integer?
|
|
28
|
+
|
|
25
29
|
DEFAULT_STRICT: bool
|
|
26
30
|
|
|
27
31
|
DEFAULT_TRACK_WHITESPACE: bool
|
|
@@ -42,11 +46,15 @@ module Herb
|
|
|
42
46
|
|
|
43
47
|
DEFAULT_PRISM_NODES_DEEP: bool
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
DEFAULT_TIMEOUT: Numeric
|
|
50
|
+
|
|
51
|
+
DEFAULT_MAX_ERRORS: Integer
|
|
52
|
+
|
|
53
|
+
# : (?strict: bool, ?track_whitespace: bool, ?analyze: bool, ?action_view_helpers: bool, ?transform_conditionals: bool, ?render_nodes: bool, ?strict_locals: bool, ?prism_nodes: bool, ?prism_nodes_deep: bool, ?prism_program: bool, ?timeout: Numeric) -> void
|
|
54
|
+
def initialize: (?strict: bool, ?track_whitespace: bool, ?analyze: bool, ?action_view_helpers: bool, ?transform_conditionals: bool, ?render_nodes: bool, ?strict_locals: bool, ?prism_nodes: bool, ?prism_nodes_deep: bool, ?prism_program: bool, ?timeout: Numeric) -> void
|
|
47
55
|
|
|
48
|
-
# : () -> Hash[Symbol, bool]
|
|
49
|
-
def to_h: () -> Hash[Symbol, bool]
|
|
56
|
+
# : () -> Hash[Symbol, (bool | Numeric | nil)]
|
|
57
|
+
def to_h: () -> Hash[Symbol, bool | Numeric | nil]
|
|
50
58
|
|
|
51
59
|
# : () -> String
|
|
52
60
|
def inspect: () -> String
|
data/sig/manifest.yaml
ADDED
|
@@ -277,7 +277,13 @@ bool search_in_nodes(const pm_node_t* node, void* data) {
|
|
|
277
277
|
analyzed_ruby_T* analyzed = (analyzed_ruby_T*) data;
|
|
278
278
|
|
|
279
279
|
if (node->type == PM_IN_NODE) { analyzed->in_node_count++; }
|
|
280
|
-
if (node->type ==
|
|
280
|
+
if (node->type == PM_CASE_MATCH_NODE) {
|
|
281
|
+
const pm_case_match_node_t* case_match_node = (const pm_case_match_node_t*) node;
|
|
282
|
+
|
|
283
|
+
if (case_match_node->predicate != NULL && case_match_node->predicate->type == PM_MATCH_PREDICATE_NODE) {
|
|
284
|
+
analyzed->in_node_count++;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
281
287
|
|
|
282
288
|
pm_visit_child_nodes(node, search_in_nodes, analyzed);
|
|
283
289
|
|
data/src/errors.c
CHANGED
|
@@ -1248,6 +1248,33 @@ void append_dot_notation_casing_error(token_T* segment, position_T start, positi
|
|
|
1248
1248
|
hb_array_append(errors, dot_notation_casing_error_init(segment, start, end, allocator));
|
|
1249
1249
|
}
|
|
1250
1250
|
|
|
1251
|
+
TIMEOUT_ERROR_T* timeout_error_init(size_t timeout_ms, position_T start, position_T end, hb_allocator_T* allocator) {
|
|
1252
|
+
TIMEOUT_ERROR_T* timeout_error = hb_allocator_alloc(allocator, sizeof(TIMEOUT_ERROR_T));
|
|
1253
|
+
|
|
1254
|
+
if (!timeout_error) { return NULL; }
|
|
1255
|
+
|
|
1256
|
+
error_init(&timeout_error->base, TIMEOUT_ERROR, start, end);
|
|
1257
|
+
|
|
1258
|
+
const char* message_template = "Parsing timed out after %zu ms.";
|
|
1259
|
+
|
|
1260
|
+
char message[52];
|
|
1261
|
+
snprintf(
|
|
1262
|
+
message,
|
|
1263
|
+
sizeof(message),
|
|
1264
|
+
message_template,
|
|
1265
|
+
timeout_ms
|
|
1266
|
+
);
|
|
1267
|
+
|
|
1268
|
+
timeout_error->base.message = hb_string_copy(hb_string(message), allocator);
|
|
1269
|
+
|
|
1270
|
+
timeout_error->timeout_ms = timeout_ms;
|
|
1271
|
+
return timeout_error;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
void append_timeout_error(size_t timeout_ms, position_T start, position_T end, hb_allocator_T* allocator, hb_array_T* errors) {
|
|
1275
|
+
hb_array_append(errors, timeout_error_init(timeout_ms, start, end, allocator));
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1251
1278
|
hb_string_T error_type_to_string(ERROR_T* error) {
|
|
1252
1279
|
switch (error->type) {
|
|
1253
1280
|
case UNEXPECTED_ERROR: return hb_string("UNEXPECTED_ERROR");
|
|
@@ -1287,6 +1314,7 @@ hb_string_T error_type_to_string(ERROR_T* error) {
|
|
|
1287
1314
|
case STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR: return hb_string("STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR");
|
|
1288
1315
|
case VOID_ELEMENT_CONTENT_ERROR: return hb_string("VOID_ELEMENT_CONTENT_ERROR");
|
|
1289
1316
|
case DOT_NOTATION_CASING_ERROR: return hb_string("DOT_NOTATION_CASING_ERROR");
|
|
1317
|
+
case TIMEOUT_ERROR: return hb_string("TIMEOUT_ERROR");
|
|
1290
1318
|
}
|
|
1291
1319
|
|
|
1292
1320
|
return hb_string("Unknown error_type_T");
|
|
@@ -1331,6 +1359,7 @@ hb_string_T error_human_type(ERROR_T* error) {
|
|
|
1331
1359
|
case STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR: return hb_string("StrictLocalsDuplicateDeclarationError");
|
|
1332
1360
|
case VOID_ELEMENT_CONTENT_ERROR: return hb_string("VoidElementContentError");
|
|
1333
1361
|
case DOT_NOTATION_CASING_ERROR: return hb_string("DotNotationCasingError");
|
|
1362
|
+
case TIMEOUT_ERROR: return hb_string("TimeoutError");
|
|
1334
1363
|
}
|
|
1335
1364
|
|
|
1336
1365
|
return hb_string("Unknown error_type_T");
|
|
@@ -1588,6 +1617,12 @@ static void error_free_dot_notation_casing_error(DOT_NOTATION_CASING_ERROR_T* do
|
|
|
1588
1617
|
error_free_base_error(&dot_notation_casing_error->base, allocator);
|
|
1589
1618
|
}
|
|
1590
1619
|
|
|
1620
|
+
static void error_free_timeout_error(TIMEOUT_ERROR_T* timeout_error, hb_allocator_T* allocator) {
|
|
1621
|
+
// size_t is part of struct
|
|
1622
|
+
|
|
1623
|
+
error_free_base_error(&timeout_error->base, allocator);
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1591
1626
|
void error_free(ERROR_T* error, hb_allocator_T* allocator) {
|
|
1592
1627
|
if (!error) { return; }
|
|
1593
1628
|
|
|
@@ -1629,6 +1664,7 @@ void error_free(ERROR_T* error, hb_allocator_T* allocator) {
|
|
|
1629
1664
|
case STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR: error_free_strict_locals_duplicate_declaration_error((STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR_T*) error, allocator); break;
|
|
1630
1665
|
case VOID_ELEMENT_CONTENT_ERROR: error_free_void_element_content_error((VOID_ELEMENT_CONTENT_ERROR_T*) error, allocator); break;
|
|
1631
1666
|
case DOT_NOTATION_CASING_ERROR: error_free_dot_notation_casing_error((DOT_NOTATION_CASING_ERROR_T*) error, allocator); break;
|
|
1667
|
+
case TIMEOUT_ERROR: error_free_timeout_error((TIMEOUT_ERROR_T*) error, allocator); break;
|
|
1632
1668
|
}
|
|
1633
1669
|
}
|
|
1634
1670
|
|
|
@@ -2212,6 +2248,20 @@ static void error_pretty_print_dot_notation_casing_error(DOT_NOTATION_CASING_ERR
|
|
|
2212
2248
|
pretty_print_token_property(error->segment, hb_string("segment"), indent, relative_indent, true, buffer);
|
|
2213
2249
|
}
|
|
2214
2250
|
|
|
2251
|
+
static void error_pretty_print_timeout_error(TIMEOUT_ERROR_T* error, const size_t indent, const size_t relative_indent, hb_buffer_T* buffer) {
|
|
2252
|
+
if (!error) { return; }
|
|
2253
|
+
|
|
2254
|
+
hb_buffer_append(buffer, "@ ");
|
|
2255
|
+
hb_buffer_append_string(buffer, error_human_type((ERROR_T*) error));
|
|
2256
|
+
hb_buffer_append(buffer, " ");
|
|
2257
|
+
|
|
2258
|
+
pretty_print_location(error->base.location, buffer);
|
|
2259
|
+
hb_buffer_append(buffer, "\n");
|
|
2260
|
+
|
|
2261
|
+
pretty_print_quoted_property(hb_string("message"), error->base.message, indent, relative_indent, false, buffer);
|
|
2262
|
+
pretty_print_size_t_property(error->timeout_ms, hb_string("timeout_ms"), indent, relative_indent, true, buffer);
|
|
2263
|
+
}
|
|
2264
|
+
|
|
2215
2265
|
void error_pretty_print(ERROR_T* error, const size_t indent, const size_t relative_indent, hb_buffer_T* buffer) {
|
|
2216
2266
|
if (!error) { return; }
|
|
2217
2267
|
|
|
@@ -2253,6 +2303,7 @@ void error_pretty_print(ERROR_T* error, const size_t indent, const size_t relati
|
|
|
2253
2303
|
case STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR: error_pretty_print_strict_locals_duplicate_declaration_error((STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR_T*) error, indent, relative_indent, buffer); break;
|
|
2254
2304
|
case VOID_ELEMENT_CONTENT_ERROR: error_pretty_print_void_element_content_error((VOID_ELEMENT_CONTENT_ERROR_T*) error, indent, relative_indent, buffer); break;
|
|
2255
2305
|
case DOT_NOTATION_CASING_ERROR: error_pretty_print_dot_notation_casing_error((DOT_NOTATION_CASING_ERROR_T*) error, indent, relative_indent, buffer); break;
|
|
2306
|
+
case TIMEOUT_ERROR: error_pretty_print_timeout_error((TIMEOUT_ERROR_T*) error, indent, relative_indent, buffer); break;
|
|
2256
2307
|
}
|
|
2257
2308
|
}
|
|
2258
2309
|
|
data/src/herb.c
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include "include/herb.h"
|
|
2
2
|
#include "include/analyze/analyze.h"
|
|
3
3
|
#include "include/analyze/prism_annotate.h"
|
|
4
|
+
#include "include/errors.h"
|
|
4
5
|
#include "include/lexer/lexer.h"
|
|
5
6
|
#include "include/lexer/token.h"
|
|
6
7
|
#include "include/lib/hb_allocator.h"
|
|
@@ -44,6 +45,11 @@ HERB_EXPORTED_FUNCTION AST_DOCUMENT_NODE_T* herb_parse(
|
|
|
44
45
|
parser_options_T parser_options = HERB_DEFAULT_PARSER_OPTIONS;
|
|
45
46
|
if (options != NULL) { parser_options = *options; }
|
|
46
47
|
|
|
48
|
+
uint32_t error_count = 0;
|
|
49
|
+
parser_options.error_count = &error_count;
|
|
50
|
+
|
|
51
|
+
parser_options_set_deadline(&parser_options);
|
|
52
|
+
|
|
47
53
|
if (parser_options.start_line > 0) {
|
|
48
54
|
lexer.current_line = parser_options.start_line;
|
|
49
55
|
lexer.previous_line = parser_options.start_line;
|
|
@@ -73,6 +79,16 @@ HERB_EXPORTED_FUNCTION AST_DOCUMENT_NODE_T* herb_parse(
|
|
|
73
79
|
);
|
|
74
80
|
}
|
|
75
81
|
|
|
82
|
+
if (parser_options_past_deadline(&parser_options)) {
|
|
83
|
+
append_timeout_error(
|
|
84
|
+
parser_options.timeout_ms,
|
|
85
|
+
document->base.location.start,
|
|
86
|
+
document->base.location.end,
|
|
87
|
+
allocator,
|
|
88
|
+
document->base.errors
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
return document;
|
|
77
93
|
}
|
|
78
94
|
|
data/src/include/errors.h
CHANGED
|
@@ -51,6 +51,7 @@ typedef enum {
|
|
|
51
51
|
STRICT_LOCALS_DUPLICATE_DECLARATION_ERROR,
|
|
52
52
|
VOID_ELEMENT_CONTENT_ERROR,
|
|
53
53
|
DOT_NOTATION_CASING_ERROR,
|
|
54
|
+
TIMEOUT_ERROR,
|
|
54
55
|
} error_type_T;
|
|
55
56
|
|
|
56
57
|
typedef struct ERROR_STRUCT {
|
|
@@ -267,6 +268,11 @@ typedef struct {
|
|
|
267
268
|
token_T* segment;
|
|
268
269
|
} DOT_NOTATION_CASING_ERROR_T;
|
|
269
270
|
|
|
271
|
+
typedef struct {
|
|
272
|
+
ERROR_T base;
|
|
273
|
+
size_t timeout_ms;
|
|
274
|
+
} TIMEOUT_ERROR_T;
|
|
275
|
+
|
|
270
276
|
UNEXPECTED_ERROR_T* unexpected_error_init(hb_string_T description, hb_string_T expected, hb_string_T found, position_T start, position_T end, hb_allocator_T* allocator);
|
|
271
277
|
void append_unexpected_error(hb_string_T description, hb_string_T expected, hb_string_T found, position_T start, position_T end, hb_allocator_T* allocator, hb_array_T* errors);
|
|
272
278
|
UNEXPECTED_TOKEN_ERROR_T* unexpected_token_error_init(token_type_T expected_type, token_T* found, position_T start, position_T end, hb_allocator_T* allocator);
|
|
@@ -341,6 +347,8 @@ VOID_ELEMENT_CONTENT_ERROR_T* void_element_content_error_init(token_T* tag_name,
|
|
|
341
347
|
void append_void_element_content_error(token_T* tag_name, hb_string_T helper_name, hb_string_T content_type, position_T start, position_T end, hb_allocator_T* allocator, hb_array_T* errors);
|
|
342
348
|
DOT_NOTATION_CASING_ERROR_T* dot_notation_casing_error_init(token_T* segment, position_T start, position_T end, hb_allocator_T* allocator);
|
|
343
349
|
void append_dot_notation_casing_error(token_T* segment, position_T start, position_T end, hb_allocator_T* allocator, hb_array_T* errors);
|
|
350
|
+
TIMEOUT_ERROR_T* timeout_error_init(size_t timeout_ms, position_T start, position_T end, hb_allocator_T* allocator);
|
|
351
|
+
void append_timeout_error(size_t timeout_ms, position_T start, position_T end, hb_allocator_T* allocator, hb_array_T* errors);
|
|
344
352
|
|
|
345
353
|
void error_init(ERROR_T* error, error_type_T type, position_T start, position_T end);
|
|
346
354
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#ifndef HERB_CLOCK_H
|
|
2
|
+
#define HERB_CLOCK_H
|
|
3
|
+
|
|
4
|
+
#include <stdint.h>
|
|
5
|
+
#include <time.h>
|
|
6
|
+
|
|
7
|
+
static inline uint64_t hb_monotonic_ms(void) {
|
|
8
|
+
struct timespec now;
|
|
9
|
+
|
|
10
|
+
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
11
|
+
|
|
12
|
+
return (uint64_t) now.tv_sec * 1000 + (uint64_t) now.tv_nsec / 1000000;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#endif
|
data/src/include/parser/parser.h
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#include "../lexer/lexer.h"
|
|
6
6
|
#include "../lib/hb_allocator.h"
|
|
7
7
|
#include "../lib/hb_array.h"
|
|
8
|
+
#include "../lib/hb_clock.h"
|
|
8
9
|
|
|
9
10
|
#include <stdint.h>
|
|
10
11
|
|
|
@@ -33,6 +34,10 @@ typedef struct PARSER_OPTIONS_STRUCT {
|
|
|
33
34
|
bool html;
|
|
34
35
|
uint32_t start_line;
|
|
35
36
|
uint32_t start_column;
|
|
37
|
+
uint32_t timeout_ms;
|
|
38
|
+
uint32_t max_errors;
|
|
39
|
+
uint32_t* error_count;
|
|
40
|
+
uint64_t deadline_ms;
|
|
36
41
|
} parser_options_T;
|
|
37
42
|
|
|
38
43
|
typedef struct MATCH_TAGS_CONTEXT_STRUCT {
|
|
@@ -43,6 +48,29 @@ typedef struct MATCH_TAGS_CONTEXT_STRUCT {
|
|
|
43
48
|
|
|
44
49
|
extern const parser_options_T HERB_DEFAULT_PARSER_OPTIONS;
|
|
45
50
|
|
|
51
|
+
static inline bool parser_options_past_deadline(const parser_options_T* options) {
|
|
52
|
+
if (options == NULL || options->timeout_ms == 0) { return false; }
|
|
53
|
+
|
|
54
|
+
return hb_monotonic_ms() >= options->deadline_ms;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
static inline bool parser_options_errors_exceeded(const parser_options_T* options) {
|
|
58
|
+
if (options == NULL || options->error_count == NULL) { return false; }
|
|
59
|
+
if (options->max_errors == 0) { return false; }
|
|
60
|
+
|
|
61
|
+
return *options->error_count >= options->max_errors;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static inline void parser_options_increment_error_count(const parser_options_T* options) {
|
|
65
|
+
if (options != NULL && options->error_count != NULL) { (*options->error_count)++; }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static inline void parser_options_set_deadline(parser_options_T* options) {
|
|
69
|
+
if (options->timeout_ms == 0) { return; }
|
|
70
|
+
|
|
71
|
+
options->deadline_ms = hb_monotonic_ms() + options->timeout_ms;
|
|
72
|
+
}
|
|
73
|
+
|
|
46
74
|
typedef struct PARSER_STRUCT {
|
|
47
75
|
hb_allocator_T* allocator;
|
|
48
76
|
lexer_T* lexer;
|
data/src/include/version.h
CHANGED
data/src/parser.c
CHANGED
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
#include <strings.h>
|
|
24
24
|
|
|
25
25
|
#define MAX_CONSECUTIVE_ERRORS 10
|
|
26
|
-
|
|
27
26
|
static void parser_parse_in_data_state(parser_T* parser, hb_array_T* children, hb_array_T* errors);
|
|
28
27
|
static void parser_parse_foreign_content(parser_T* parser, hb_array_T* children, hb_array_T* errors);
|
|
29
28
|
static AST_ERB_CONTENT_NODE_T* parser_parse_erb_tag(parser_T* parser);
|
|
@@ -48,7 +47,10 @@ const parser_options_T HERB_DEFAULT_PARSER_OPTIONS = { .track_whitespace = false
|
|
|
48
47
|
.dot_notation_tags = false,
|
|
49
48
|
.html = true,
|
|
50
49
|
.start_line = 0,
|
|
51
|
-
.start_column = 0
|
|
50
|
+
.start_column = 0,
|
|
51
|
+
.timeout_ms = 1000,
|
|
52
|
+
.max_errors = 25,
|
|
53
|
+
.deadline_ms = 0 };
|
|
52
54
|
|
|
53
55
|
size_t parser_sizeof(void) {
|
|
54
56
|
return sizeof(struct PARSER_STRUCT);
|
|
@@ -1498,6 +1500,7 @@ static void parser_parse_in_data_state(parser_T* parser, hb_array_T* children, h
|
|
|
1498
1500
|
}
|
|
1499
1501
|
|
|
1500
1502
|
while (token_is_not(parser, TOKEN_EOF)) {
|
|
1503
|
+
if (parser_options_past_deadline(&parser->options)) { break; }
|
|
1501
1504
|
|
|
1502
1505
|
if (token_is(parser, TOKEN_ERB_START)) {
|
|
1503
1506
|
hb_array_append(children, parser_parse_erb_tag(parser));
|
|
@@ -1601,11 +1604,18 @@ static void parser_parse_in_data_state(parser_T* parser, hb_array_T* children, h
|
|
|
1601
1604
|
}
|
|
1602
1605
|
}
|
|
1603
1606
|
|
|
1604
|
-
static size_t find_matching_close_tag(
|
|
1607
|
+
static size_t find_matching_close_tag(
|
|
1608
|
+
hb_array_T* nodes,
|
|
1609
|
+
size_t start_index,
|
|
1610
|
+
hb_string_T tag_name,
|
|
1611
|
+
const parser_options_T* options
|
|
1612
|
+
) {
|
|
1605
1613
|
int depth = 0;
|
|
1606
1614
|
|
|
1607
|
-
for (size_t
|
|
1608
|
-
|
|
1615
|
+
for (size_t index = start_index + 1; index < hb_array_size(nodes); index++) {
|
|
1616
|
+
if (parser_options_past_deadline(options)) { return (size_t) -1; }
|
|
1617
|
+
|
|
1618
|
+
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, index);
|
|
1609
1619
|
if (node == NULL) { continue; }
|
|
1610
1620
|
|
|
1611
1621
|
if (node->type == AST_HTML_OPEN_TAG_NODE) {
|
|
@@ -1616,7 +1626,7 @@ static size_t find_matching_close_tag(hb_array_T* nodes, size_t start_idx, hb_st
|
|
|
1616
1626
|
AST_HTML_CLOSE_TAG_NODE_T* close = (AST_HTML_CLOSE_TAG_NODE_T*) node;
|
|
1617
1627
|
|
|
1618
1628
|
if (hb_string_equals_case_insensitive(close->tag_name->value, tag_name)) {
|
|
1619
|
-
if (depth == 0) { return
|
|
1629
|
+
if (depth == 0) { return index; }
|
|
1620
1630
|
depth--;
|
|
1621
1631
|
}
|
|
1622
1632
|
}
|
|
@@ -1625,23 +1635,23 @@ static size_t find_matching_close_tag(hb_array_T* nodes, size_t start_idx, hb_st
|
|
|
1625
1635
|
return (size_t) -1;
|
|
1626
1636
|
}
|
|
1627
1637
|
|
|
1628
|
-
static size_t find_implicit_close_index(hb_array_T* nodes, size_t
|
|
1638
|
+
static size_t find_implicit_close_index(hb_array_T* nodes, size_t start_index, hb_string_T tag_name) {
|
|
1629
1639
|
if (!has_optional_end_tag(tag_name)) { return (size_t) -1; }
|
|
1630
1640
|
|
|
1631
|
-
for (size_t
|
|
1632
|
-
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes,
|
|
1641
|
+
for (size_t index = start_index + 1; index < hb_array_size(nodes); index++) {
|
|
1642
|
+
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, index);
|
|
1633
1643
|
if (node == NULL) { continue; }
|
|
1634
1644
|
|
|
1635
1645
|
if (node->type == AST_HTML_OPEN_TAG_NODE) {
|
|
1636
1646
|
AST_HTML_OPEN_TAG_NODE_T* open = (AST_HTML_OPEN_TAG_NODE_T*) node;
|
|
1637
1647
|
hb_string_T next_tag_name = open->tag_name->value;
|
|
1638
1648
|
|
|
1639
|
-
if (should_implicitly_close(tag_name, next_tag_name)) { return
|
|
1649
|
+
if (should_implicitly_close(tag_name, next_tag_name)) { return index; }
|
|
1640
1650
|
} else if (node->type == AST_HTML_CLOSE_TAG_NODE) {
|
|
1641
1651
|
AST_HTML_CLOSE_TAG_NODE_T* close = (AST_HTML_CLOSE_TAG_NODE_T*) node;
|
|
1642
1652
|
hb_string_T close_tag_name = close->tag_name->value;
|
|
1643
1653
|
|
|
1644
|
-
if (parent_closes_element(tag_name, close_tag_name)) { return
|
|
1654
|
+
if (parent_closes_element(tag_name, close_tag_name)) { return index; }
|
|
1645
1655
|
}
|
|
1646
1656
|
}
|
|
1647
1657
|
|
|
@@ -1655,6 +1665,35 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1655
1665
|
hb_allocator_T* allocator
|
|
1656
1666
|
);
|
|
1657
1667
|
|
|
1668
|
+
static bool has_close_tag_for_name(hb_array_T* close_tag_names, hb_string_T tag_name) {
|
|
1669
|
+
for (size_t i = 0; i < hb_array_size(close_tag_names); i++) {
|
|
1670
|
+
hb_string_T* name = (hb_string_T*) hb_array_get(close_tag_names, i);
|
|
1671
|
+
if (name != NULL && hb_string_equals_case_insensitive(*name, tag_name)) { return true; }
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
return false;
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
static hb_array_T* collect_close_tag_names(hb_array_T* nodes, hb_allocator_T* allocator) {
|
|
1678
|
+
hb_array_T* close_tag_names = hb_array_init(16, allocator);
|
|
1679
|
+
|
|
1680
|
+
for (size_t i = 0; i < hb_array_size(nodes); i++) {
|
|
1681
|
+
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, i);
|
|
1682
|
+
if (node == NULL || node->type != AST_HTML_CLOSE_TAG_NODE) { continue; }
|
|
1683
|
+
|
|
1684
|
+
AST_HTML_CLOSE_TAG_NODE_T* close_tag = (AST_HTML_CLOSE_TAG_NODE_T*) node;
|
|
1685
|
+
hb_string_T name = close_tag->tag_name->value;
|
|
1686
|
+
|
|
1687
|
+
if (!has_close_tag_for_name(close_tag_names, name)) {
|
|
1688
|
+
hb_string_T* stored = hb_allocator_alloc(allocator, sizeof(hb_string_T));
|
|
1689
|
+
*stored = name;
|
|
1690
|
+
hb_array_append(close_tag_names, stored);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
return close_tag_names;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1658
1697
|
static hb_array_T* parser_build_elements_from_tags(
|
|
1659
1698
|
hb_array_T* nodes,
|
|
1660
1699
|
hb_array_T* errors,
|
|
@@ -1663,8 +1702,11 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1663
1702
|
) {
|
|
1664
1703
|
bool strict = options ? options->strict : false;
|
|
1665
1704
|
hb_array_T* result = hb_array_init(hb_array_size(nodes), allocator);
|
|
1705
|
+
hb_array_T* close_tag_names = collect_close_tag_names(nodes, allocator);
|
|
1666
1706
|
|
|
1667
1707
|
for (size_t index = 0; index < hb_array_size(nodes); index++) {
|
|
1708
|
+
if (parser_options_past_deadline(options)) { break; }
|
|
1709
|
+
|
|
1668
1710
|
AST_NODE_T* node = (AST_NODE_T*) hb_array_get(nodes, index);
|
|
1669
1711
|
if (node == NULL) { continue; }
|
|
1670
1712
|
|
|
@@ -1672,7 +1714,11 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1672
1714
|
AST_HTML_OPEN_TAG_NODE_T* open_tag = (AST_HTML_OPEN_TAG_NODE_T*) node;
|
|
1673
1715
|
hb_string_T tag_name = open_tag->tag_name->value;
|
|
1674
1716
|
|
|
1675
|
-
size_t close_index =
|
|
1717
|
+
size_t close_index = (size_t) -1;
|
|
1718
|
+
|
|
1719
|
+
if (has_close_tag_for_name(close_tag_names, tag_name)) {
|
|
1720
|
+
close_index = find_matching_close_tag(nodes, index, tag_name, options);
|
|
1721
|
+
}
|
|
1676
1722
|
|
|
1677
1723
|
if (close_index == (size_t) -1) {
|
|
1678
1724
|
size_t implicit_close_index = find_implicit_close_index(nodes, index, tag_name);
|
|
@@ -1732,7 +1778,7 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1732
1778
|
|
|
1733
1779
|
index = implicit_close_index - 1;
|
|
1734
1780
|
} else {
|
|
1735
|
-
if (hb_array_size(open_tag->base.errors) == 0) {
|
|
1781
|
+
if (hb_array_size(open_tag->base.errors) == 0 && !parser_options_errors_exceeded(options)) {
|
|
1736
1782
|
append_missing_closing_tag_error(
|
|
1737
1783
|
open_tag->tag_name,
|
|
1738
1784
|
open_tag->base.location.start,
|
|
@@ -1740,6 +1786,8 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1740
1786
|
allocator,
|
|
1741
1787
|
open_tag->base.errors
|
|
1742
1788
|
);
|
|
1789
|
+
|
|
1790
|
+
parser_options_increment_error_count(options);
|
|
1743
1791
|
}
|
|
1744
1792
|
|
|
1745
1793
|
hb_array_append(result, node);
|
|
@@ -1779,7 +1827,7 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1779
1827
|
AST_HTML_CLOSE_TAG_NODE_T* close_tag = (AST_HTML_CLOSE_TAG_NODE_T*) node;
|
|
1780
1828
|
|
|
1781
1829
|
if (!is_void_element(close_tag->tag_name->value)) {
|
|
1782
|
-
if (hb_array_size(close_tag->base.errors) == 0) {
|
|
1830
|
+
if (hb_array_size(close_tag->base.errors) == 0 && !parser_options_errors_exceeded(options)) {
|
|
1783
1831
|
append_missing_opening_tag_error(
|
|
1784
1832
|
close_tag->tag_name,
|
|
1785
1833
|
close_tag->base.location.start,
|
|
@@ -1787,6 +1835,8 @@ static hb_array_T* parser_build_elements_from_tags(
|
|
|
1787
1835
|
allocator,
|
|
1788
1836
|
close_tag->base.errors
|
|
1789
1837
|
);
|
|
1838
|
+
|
|
1839
|
+
parser_options_increment_error_count(options);
|
|
1790
1840
|
}
|
|
1791
1841
|
}
|
|
1792
1842
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: herb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.10.
|
|
4
|
+
version: 0.10.2
|
|
5
5
|
platform: x86_64-darwin
|
|
6
6
|
authors:
|
|
7
7
|
- Marco Roth
|
|
@@ -397,12 +397,11 @@ files:
|
|
|
397
397
|
- sig/herb/visitor.rbs
|
|
398
398
|
- sig/herb/warnings.rbs
|
|
399
399
|
- sig/herb_c_extension.rbs
|
|
400
|
+
- sig/manifest.yaml
|
|
400
401
|
- sig/rubyvm.rbs
|
|
401
402
|
- sig/serialized.rbs
|
|
402
403
|
- sig/serialized_ast_errors.rbs
|
|
403
404
|
- sig/serialized_ast_nodes.rbs
|
|
404
|
-
- sig/vendor/did_you_mean.rbs
|
|
405
|
-
- sig/vendor/parallel.rbs
|
|
406
405
|
- src/analyze/action_view/attribute_extraction_helpers.c
|
|
407
406
|
- src/analyze/action_view/generated_handlers.c
|
|
408
407
|
- src/analyze/action_view/generated_handlers.h
|
|
@@ -488,6 +487,7 @@ files:
|
|
|
488
487
|
- src/include/lib/hb_arena_debug.h
|
|
489
488
|
- src/include/lib/hb_array.h
|
|
490
489
|
- src/include/lib/hb_buffer.h
|
|
490
|
+
- src/include/lib/hb_clock.h
|
|
491
491
|
- src/include/lib/hb_foreach.h
|
|
492
492
|
- src/include/lib/hb_narray.h
|
|
493
493
|
- src/include/lib/hb_string.h
|
|
@@ -705,7 +705,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
705
705
|
- !ruby/object:Gem::Version
|
|
706
706
|
version: '0'
|
|
707
707
|
requirements: []
|
|
708
|
-
rubygems_version: 4.0.
|
|
708
|
+
rubygems_version: 4.0.6
|
|
709
709
|
specification_version: 4
|
|
710
710
|
summary: The modern HTML+ERB Toolchain
|
|
711
711
|
test_files: []
|
data/sig/vendor/did_you_mean.rbs
DELETED
data/sig/vendor/parallel.rbs
DELETED