@herb-tools/node 0.7.4 → 0.8.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/binding.gyp +8 -5
- package/dist/herb-node.esm.js +6 -6
- package/dist/herb-node.esm.js.map +1 -1
- package/extension/error_helpers.cpp +67 -9
- package/extension/error_helpers.h +4 -2
- package/extension/extension_helpers.cpp +20 -31
- package/extension/extension_helpers.h +7 -5
- package/extension/herb.cpp +10 -42
- package/extension/libherb/analyze.c +461 -249
- package/extension/libherb/analyze.h +10 -2
- package/extension/libherb/analyze_helpers.c +5 -0
- package/extension/libherb/analyze_helpers.h +3 -0
- package/extension/libherb/analyze_missing_end.c +147 -0
- package/extension/libherb/analyze_transform.c +196 -0
- package/extension/libherb/analyzed_ruby.c +23 -2
- package/extension/libherb/analyzed_ruby.h +4 -2
- package/extension/libherb/ast_node.c +14 -17
- package/extension/libherb/ast_node.h +4 -4
- package/extension/libherb/ast_nodes.c +180 -182
- package/extension/libherb/ast_nodes.h +69 -68
- package/extension/libherb/ast_pretty_print.c +233 -233
- package/extension/libherb/ast_pretty_print.h +3 -3
- package/extension/libherb/element_source.c +7 -6
- package/extension/libherb/element_source.h +3 -1
- package/extension/libherb/errors.c +273 -153
- package/extension/libherb/errors.h +43 -27
- package/extension/libherb/extract.c +92 -34
- package/extension/libherb/extract.h +4 -4
- package/extension/libherb/herb.c +37 -49
- package/extension/libherb/herb.h +6 -7
- package/extension/libherb/html_util.c +34 -96
- package/extension/libherb/html_util.h +4 -5
- package/extension/libherb/include/analyze.h +10 -2
- package/extension/libherb/include/analyze_helpers.h +3 -0
- package/extension/libherb/include/analyzed_ruby.h +4 -2
- package/extension/libherb/include/ast_node.h +4 -4
- package/extension/libherb/include/ast_nodes.h +69 -68
- package/extension/libherb/include/ast_pretty_print.h +3 -3
- package/extension/libherb/include/element_source.h +3 -1
- package/extension/libherb/include/errors.h +43 -27
- package/extension/libherb/include/extract.h +4 -4
- package/extension/libherb/include/herb.h +6 -7
- package/extension/libherb/include/html_util.h +4 -5
- package/extension/libherb/include/lexer.h +1 -3
- package/extension/libherb/include/lexer_peek_helpers.h +21 -19
- package/extension/libherb/include/lexer_struct.h +12 -10
- package/extension/libherb/include/location.h +10 -13
- package/extension/libherb/include/macros.h +4 -0
- package/extension/libherb/include/parser.h +12 -6
- package/extension/libherb/include/parser_helpers.h +26 -16
- package/extension/libherb/include/position.h +3 -14
- package/extension/libherb/include/pretty_print.h +38 -28
- package/extension/libherb/include/prism_helpers.h +1 -1
- package/extension/libherb/include/range.h +4 -13
- package/extension/libherb/include/token.h +5 -11
- package/extension/libherb/include/token_struct.h +2 -2
- package/extension/libherb/include/utf8.h +3 -2
- package/extension/libherb/include/util/hb_arena.h +31 -0
- package/extension/libherb/include/util/hb_arena_debug.h +8 -0
- package/extension/libherb/include/util/hb_array.h +33 -0
- package/extension/libherb/include/util/hb_buffer.h +34 -0
- package/extension/libherb/include/util/hb_string.h +29 -0
- package/extension/libherb/include/util/hb_system.h +9 -0
- package/extension/libherb/include/util.h +3 -14
- package/extension/libherb/include/version.h +1 -1
- package/extension/libherb/include/visitor.h +1 -1
- package/extension/libherb/io.c +7 -4
- package/extension/libherb/lexer.c +62 -88
- package/extension/libherb/lexer.h +1 -3
- package/extension/libherb/lexer_peek_helpers.c +42 -38
- package/extension/libherb/lexer_peek_helpers.h +21 -19
- package/extension/libherb/lexer_struct.h +12 -10
- package/extension/libherb/location.c +9 -37
- package/extension/libherb/location.h +10 -13
- package/extension/libherb/macros.h +4 -0
- package/extension/libherb/main.c +19 -23
- package/extension/libherb/parser.c +373 -313
- package/extension/libherb/parser.h +12 -6
- package/extension/libherb/parser_helpers.c +60 -54
- package/extension/libherb/parser_helpers.h +26 -16
- package/extension/libherb/parser_match_tags.c +316 -0
- package/extension/libherb/position.h +3 -14
- package/extension/libherb/pretty_print.c +88 -117
- package/extension/libherb/pretty_print.h +38 -28
- package/extension/libherb/prism_helpers.c +7 -7
- package/extension/libherb/prism_helpers.h +1 -1
- package/extension/libherb/range.c +2 -35
- package/extension/libherb/range.h +4 -13
- package/extension/libherb/token.c +36 -87
- package/extension/libherb/token.h +5 -11
- package/extension/libherb/token_struct.h +2 -2
- package/extension/libherb/utf8.c +4 -4
- package/extension/libherb/utf8.h +3 -2
- package/extension/libherb/util/hb_arena.c +179 -0
- package/extension/libherb/util/hb_arena.h +31 -0
- package/extension/libherb/util/hb_arena_debug.c +237 -0
- package/extension/libherb/util/hb_arena_debug.h +8 -0
- package/extension/libherb/{array.c → util/hb_array.c} +26 -27
- package/extension/libherb/util/hb_array.h +33 -0
- package/extension/libherb/util/hb_buffer.c +203 -0
- package/extension/libherb/util/hb_buffer.h +34 -0
- package/extension/libherb/util/hb_string.c +85 -0
- package/extension/libherb/util/hb_string.h +29 -0
- package/extension/libherb/util/hb_system.c +30 -0
- package/extension/libherb/util/hb_system.h +9 -0
- package/extension/libherb/util.c +29 -99
- package/extension/libherb/util.h +3 -14
- package/extension/libherb/version.h +1 -1
- package/extension/libherb/visitor.c +55 -55
- package/extension/libherb/visitor.h +1 -1
- package/extension/nodes.cpp +40 -40
- package/extension/nodes.h +2 -2
- package/extension/prism/include/prism/ast.h +31 -1
- package/extension/prism/include/prism/diagnostic.h +1 -0
- package/extension/prism/include/prism/version.h +3 -3
- package/extension/prism/src/diagnostic.c +3 -1
- package/extension/prism/src/prism.c +130 -71
- package/extension/prism/src/util/pm_string.c +6 -8
- package/package.json +3 -3
- package/extension/libherb/array.h +0 -33
- package/extension/libherb/buffer.c +0 -232
- package/extension/libherb/buffer.h +0 -39
- package/extension/libherb/include/array.h +0 -33
- package/extension/libherb/include/buffer.h +0 -39
- package/extension/libherb/include/json.h +0 -28
- package/extension/libherb/include/memory.h +0 -12
- package/extension/libherb/json.c +0 -205
- package/extension/libherb/json.h +0 -28
- package/extension/libherb/memory.c +0 -53
- package/extension/libherb/memory.h +0 -12
- package/extension/libherb/position.c +0 -33
|
@@ -2622,10 +2622,11 @@ pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_argument
|
|
|
2622
2622
|
// There are certain flags that we want to use internally but don't want to
|
|
2623
2623
|
// expose because they are not relevant beyond parsing. Therefore we'll define
|
|
2624
2624
|
// them here and not define them in config.yml/a header file.
|
|
2625
|
-
static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY =
|
|
2626
|
-
|
|
2627
|
-
static const pm_node_flags_t
|
|
2628
|
-
static const pm_node_flags_t
|
|
2625
|
+
static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
|
|
2626
|
+
|
|
2627
|
+
static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
|
|
2628
|
+
static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
|
|
2629
|
+
static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
|
|
2629
2630
|
|
|
2630
2631
|
/**
|
|
2631
2632
|
* Allocate and initialize a new CallNode node. This sets everything to NULL or
|
|
@@ -5279,6 +5280,12 @@ pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_
|
|
|
5279
5280
|
|
|
5280
5281
|
switch (PM_NODE_TYPE(part)) {
|
|
5281
5282
|
case PM_STRING_NODE:
|
|
5283
|
+
// If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
|
|
5284
|
+
// because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
|
|
5285
|
+
// as long as this interpolation only consists of other string literals.
|
|
5286
|
+
if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
|
|
5287
|
+
pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
|
|
5288
|
+
}
|
|
5282
5289
|
part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
|
|
5283
5290
|
break;
|
|
5284
5291
|
case PM_INTERPOLATED_STRING_NODE:
|
|
@@ -8584,64 +8591,64 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
|
|
|
8584
8591
|
|
|
8585
8592
|
static const uint32_t context_terminators[] = {
|
|
8586
8593
|
[PM_CONTEXT_NONE] = 0,
|
|
8587
|
-
[PM_CONTEXT_BEGIN] = (
|
|
8588
|
-
[PM_CONTEXT_BEGIN_ENSURE] = (
|
|
8589
|
-
[PM_CONTEXT_BEGIN_ELSE] = (
|
|
8590
|
-
[PM_CONTEXT_BEGIN_RESCUE] = (
|
|
8591
|
-
[PM_CONTEXT_BLOCK_BRACES] = (
|
|
8592
|
-
[PM_CONTEXT_BLOCK_KEYWORDS] = (
|
|
8593
|
-
[PM_CONTEXT_BLOCK_ENSURE] = (
|
|
8594
|
-
[PM_CONTEXT_BLOCK_ELSE] = (
|
|
8595
|
-
[PM_CONTEXT_BLOCK_RESCUE] = (
|
|
8596
|
-
[PM_CONTEXT_CASE_WHEN] = (
|
|
8597
|
-
[PM_CONTEXT_CASE_IN] = (
|
|
8598
|
-
[PM_CONTEXT_CLASS] = (
|
|
8599
|
-
[PM_CONTEXT_CLASS_ENSURE] = (
|
|
8600
|
-
[PM_CONTEXT_CLASS_ELSE] = (
|
|
8601
|
-
[PM_CONTEXT_CLASS_RESCUE] = (
|
|
8602
|
-
[PM_CONTEXT_DEF] = (
|
|
8603
|
-
[PM_CONTEXT_DEF_ENSURE] = (
|
|
8604
|
-
[PM_CONTEXT_DEF_ELSE] = (
|
|
8605
|
-
[PM_CONTEXT_DEF_RESCUE] = (
|
|
8606
|
-
[PM_CONTEXT_DEF_PARAMS] = (
|
|
8607
|
-
[PM_CONTEXT_DEFINED] = (
|
|
8608
|
-
[PM_CONTEXT_DEFAULT_PARAMS] = (
|
|
8609
|
-
[PM_CONTEXT_ELSE] = (
|
|
8610
|
-
[PM_CONTEXT_ELSIF] = (
|
|
8611
|
-
[PM_CONTEXT_EMBEXPR] = (
|
|
8612
|
-
[PM_CONTEXT_FOR] = (
|
|
8613
|
-
[PM_CONTEXT_FOR_INDEX] = (
|
|
8614
|
-
[PM_CONTEXT_IF] = (
|
|
8615
|
-
[PM_CONTEXT_LAMBDA_BRACES] = (
|
|
8616
|
-
[PM_CONTEXT_LAMBDA_DO_END] = (
|
|
8617
|
-
[PM_CONTEXT_LAMBDA_ENSURE] = (
|
|
8618
|
-
[PM_CONTEXT_LAMBDA_ELSE] = (
|
|
8619
|
-
[PM_CONTEXT_LAMBDA_RESCUE] = (
|
|
8620
|
-
[PM_CONTEXT_LOOP_PREDICATE] = (
|
|
8621
|
-
[PM_CONTEXT_MAIN] = (
|
|
8622
|
-
[PM_CONTEXT_MODULE] = (
|
|
8623
|
-
[PM_CONTEXT_MODULE_ENSURE] = (
|
|
8624
|
-
[PM_CONTEXT_MODULE_ELSE] = (
|
|
8625
|
-
[PM_CONTEXT_MODULE_RESCUE] = (
|
|
8626
|
-
[PM_CONTEXT_MULTI_TARGET] = (
|
|
8627
|
-
[PM_CONTEXT_PARENS] = (
|
|
8628
|
-
[PM_CONTEXT_POSTEXE] = (
|
|
8629
|
-
[PM_CONTEXT_PREDICATE] = (
|
|
8630
|
-
[PM_CONTEXT_PREEXE] = (
|
|
8631
|
-
[PM_CONTEXT_RESCUE_MODIFIER] = (
|
|
8632
|
-
[PM_CONTEXT_SCLASS] = (
|
|
8633
|
-
[PM_CONTEXT_SCLASS_ENSURE] = (
|
|
8634
|
-
[PM_CONTEXT_SCLASS_ELSE] = (
|
|
8635
|
-
[PM_CONTEXT_SCLASS_RESCUE] = (
|
|
8636
|
-
[PM_CONTEXT_TERNARY] = (
|
|
8637
|
-
[PM_CONTEXT_UNLESS] = (
|
|
8638
|
-
[PM_CONTEXT_UNTIL] = (
|
|
8639
|
-
[PM_CONTEXT_WHILE] = (
|
|
8594
|
+
[PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8595
|
+
[PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8596
|
+
[PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8597
|
+
[PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8598
|
+
[PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
|
|
8599
|
+
[PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
|
|
8600
|
+
[PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8601
|
+
[PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8602
|
+
[PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8603
|
+
[PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
|
|
8604
|
+
[PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
|
|
8605
|
+
[PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
|
|
8606
|
+
[PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8607
|
+
[PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8608
|
+
[PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8609
|
+
[PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
|
|
8610
|
+
[PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8611
|
+
[PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8612
|
+
[PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8613
|
+
[PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
|
|
8614
|
+
[PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
|
|
8615
|
+
[PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
|
|
8616
|
+
[PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8617
|
+
[PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8618
|
+
[PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
|
|
8619
|
+
[PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8620
|
+
[PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
|
|
8621
|
+
[PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8622
|
+
[PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
|
|
8623
|
+
[PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
|
|
8624
|
+
[PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8625
|
+
[PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8626
|
+
[PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8627
|
+
[PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
|
|
8628
|
+
[PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
|
|
8629
|
+
[PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
|
|
8630
|
+
[PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8631
|
+
[PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8632
|
+
[PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8633
|
+
[PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
|
|
8634
|
+
[PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
|
|
8635
|
+
[PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
|
|
8636
|
+
[PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
|
|
8637
|
+
[PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
|
|
8638
|
+
[PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
|
|
8639
|
+
[PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
|
|
8640
|
+
[PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8641
|
+
[PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8642
|
+
[PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8643
|
+
[PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
|
|
8644
|
+
[PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
|
|
8645
|
+
[PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8646
|
+
[PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
|
|
8640
8647
|
};
|
|
8641
8648
|
|
|
8642
8649
|
static inline bool
|
|
8643
8650
|
context_terminator(pm_context_t context, pm_token_t *token) {
|
|
8644
|
-
return token->type < 32 && (context_terminators[context] & (
|
|
8651
|
+
return token->type < 32 && (context_terminators[context] & (1U << token->type));
|
|
8645
8652
|
}
|
|
8646
8653
|
|
|
8647
8654
|
/**
|
|
@@ -14443,6 +14450,17 @@ parse_arguments(pm_parser_t *parser, pm_arguments_t *arguments, bool accepts_for
|
|
|
14443
14450
|
if (accepted_newline) {
|
|
14444
14451
|
pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
|
|
14445
14452
|
}
|
|
14453
|
+
|
|
14454
|
+
// If this is a command call and an argument takes a block,
|
|
14455
|
+
// there can be no further arguments. For example,
|
|
14456
|
+
// `foo(bar 1 do end, 2)` should be rejected.
|
|
14457
|
+
if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
|
|
14458
|
+
pm_call_node_t *call = (pm_call_node_t *) argument;
|
|
14459
|
+
if (call->opening_loc.start == NULL && call->arguments != NULL && call->block != NULL) {
|
|
14460
|
+
pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
|
|
14461
|
+
break;
|
|
14462
|
+
}
|
|
14463
|
+
}
|
|
14446
14464
|
} else {
|
|
14447
14465
|
// If there is no comma at the end of the argument list then we're
|
|
14448
14466
|
// done parsing arguments and can break out of this loop.
|
|
@@ -14594,6 +14612,18 @@ update_parameter_state(pm_parser_t *parser, pm_token_t *token, pm_parameters_ord
|
|
|
14594
14612
|
return true;
|
|
14595
14613
|
}
|
|
14596
14614
|
|
|
14615
|
+
/**
|
|
14616
|
+
* Ensures that after parsing a parameter, the next token is not `=`.
|
|
14617
|
+
* Some parameters like `def(* = 1)` cannot become optional. When no parens
|
|
14618
|
+
* are present like in `def * = 1`, this creates ambiguity with endless method definitions.
|
|
14619
|
+
*/
|
|
14620
|
+
static inline void
|
|
14621
|
+
refute_optional_parameter(pm_parser_t *parser) {
|
|
14622
|
+
if (match1(parser, PM_TOKEN_EQUAL)) {
|
|
14623
|
+
pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
|
|
14624
|
+
}
|
|
14625
|
+
}
|
|
14626
|
+
|
|
14597
14627
|
/**
|
|
14598
14628
|
* Parse a list of parameters on a method definition.
|
|
14599
14629
|
*/
|
|
@@ -14646,6 +14676,10 @@ parse_parameters(
|
|
|
14646
14676
|
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
|
|
14647
14677
|
}
|
|
14648
14678
|
|
|
14679
|
+
if (!uses_parentheses) {
|
|
14680
|
+
refute_optional_parameter(parser);
|
|
14681
|
+
}
|
|
14682
|
+
|
|
14649
14683
|
pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &operator);
|
|
14650
14684
|
if (repeated) {
|
|
14651
14685
|
pm_node_flag_set_repeated_parameter((pm_node_t *)param);
|
|
@@ -14667,6 +14701,10 @@ parse_parameters(
|
|
|
14667
14701
|
bool succeeded = update_parameter_state(parser, &parser->current, &order);
|
|
14668
14702
|
parser_lex(parser);
|
|
14669
14703
|
|
|
14704
|
+
if (!uses_parentheses) {
|
|
14705
|
+
refute_optional_parameter(parser);
|
|
14706
|
+
}
|
|
14707
|
+
|
|
14670
14708
|
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
|
|
14671
14709
|
pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->previous);
|
|
14672
14710
|
|
|
@@ -14848,6 +14886,10 @@ parse_parameters(
|
|
|
14848
14886
|
context_pop(parser);
|
|
14849
14887
|
pm_parameters_node_keywords_append(params, param);
|
|
14850
14888
|
|
|
14889
|
+
if (!uses_parentheses) {
|
|
14890
|
+
refute_optional_parameter(parser);
|
|
14891
|
+
}
|
|
14892
|
+
|
|
14851
14893
|
// If parsing the value of the parameter resulted in error recovery,
|
|
14852
14894
|
// then we can put a missing node in its place and stop parsing the
|
|
14853
14895
|
// parameters entirely now.
|
|
@@ -14879,6 +14921,10 @@ parse_parameters(
|
|
|
14879
14921
|
parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
|
|
14880
14922
|
}
|
|
14881
14923
|
|
|
14924
|
+
if (!uses_parentheses) {
|
|
14925
|
+
refute_optional_parameter(parser);
|
|
14926
|
+
}
|
|
14927
|
+
|
|
14882
14928
|
pm_node_t *param = (pm_node_t *) pm_rest_parameter_node_create(parser, &operator, &name);
|
|
14883
14929
|
if (repeated) {
|
|
14884
14930
|
pm_node_flag_set_repeated_parameter(param);
|
|
@@ -14927,6 +14973,10 @@ parse_parameters(
|
|
|
14927
14973
|
}
|
|
14928
14974
|
}
|
|
14929
14975
|
|
|
14976
|
+
if (!uses_parentheses) {
|
|
14977
|
+
refute_optional_parameter(parser);
|
|
14978
|
+
}
|
|
14979
|
+
|
|
14930
14980
|
if (params->keyword_rest == NULL) {
|
|
14931
14981
|
pm_parameters_node_keyword_rest_set(params, param);
|
|
14932
14982
|
} else {
|
|
@@ -18491,20 +18541,28 @@ parse_expression_prefix(pm_parser_t *parser, pm_binding_power_t binding_power, b
|
|
|
18491
18541
|
return (pm_node_t *) node;
|
|
18492
18542
|
}
|
|
18493
18543
|
case PM_TOKEN_CHARACTER_LITERAL: {
|
|
18494
|
-
parser_lex(parser);
|
|
18495
|
-
|
|
18496
|
-
pm_token_t opening = parser->previous;
|
|
18497
|
-
opening.type = PM_TOKEN_STRING_BEGIN;
|
|
18498
|
-
opening.end = opening.start + 1;
|
|
18499
|
-
|
|
18500
|
-
pm_token_t content = parser->previous;
|
|
18501
|
-
content.type = PM_TOKEN_STRING_CONTENT;
|
|
18502
|
-
content.start = content.start + 1;
|
|
18503
|
-
|
|
18504
18544
|
pm_token_t closing = not_provided(parser);
|
|
18505
|
-
pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(
|
|
18545
|
+
pm_node_t *node = (pm_node_t *) pm_string_node_create_current_string(
|
|
18546
|
+
parser,
|
|
18547
|
+
&(pm_token_t) {
|
|
18548
|
+
.type = PM_TOKEN_STRING_BEGIN,
|
|
18549
|
+
.start = parser->current.start,
|
|
18550
|
+
.end = parser->current.start + 1
|
|
18551
|
+
},
|
|
18552
|
+
&(pm_token_t) {
|
|
18553
|
+
.type = PM_TOKEN_STRING_CONTENT,
|
|
18554
|
+
.start = parser->current.start + 1,
|
|
18555
|
+
.end = parser->current.end
|
|
18556
|
+
},
|
|
18557
|
+
&closing
|
|
18558
|
+
);
|
|
18559
|
+
|
|
18506
18560
|
pm_node_flag_set(node, parse_unescaped_encoding(parser));
|
|
18507
18561
|
|
|
18562
|
+
// Skip past the character literal here, since now we have handled
|
|
18563
|
+
// parser->explicit_encoding correctly.
|
|
18564
|
+
parser_lex(parser);
|
|
18565
|
+
|
|
18508
18566
|
// Characters can be followed by strings in which case they are
|
|
18509
18567
|
// automatically concatenated.
|
|
18510
18568
|
if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
|
|
@@ -20901,7 +20959,7 @@ parse_assignment_values(pm_parser_t *parser, pm_binding_power_t previous_binding
|
|
|
20901
20959
|
bool permitted = true;
|
|
20902
20960
|
if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted = false;
|
|
20903
20961
|
|
|
20904
|
-
pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power <
|
|
20962
|
+
pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MODIFIER, diag_id, (uint16_t) (depth + 1));
|
|
20905
20963
|
if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
|
|
20906
20964
|
|
|
20907
20965
|
parse_assignment_value_local(parser, value);
|
|
@@ -22498,9 +22556,10 @@ parse_program(pm_parser_t *parser) {
|
|
|
22498
22556
|
statements = wrap_statements(parser, statements);
|
|
22499
22557
|
} else {
|
|
22500
22558
|
flush_block_exits(parser, previous_block_exits);
|
|
22501
|
-
pm_node_list_free(¤t_block_exits);
|
|
22502
22559
|
}
|
|
22503
22560
|
|
|
22561
|
+
pm_node_list_free(¤t_block_exits);
|
|
22562
|
+
|
|
22504
22563
|
// If this is an empty file, then we're still going to parse all of the
|
|
22505
22564
|
// statements in order to gather up all of the comments and such. Here we'll
|
|
22506
22565
|
// correct the location information.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#include "prism/util/pm_string.h"
|
|
2
2
|
|
|
3
|
+
static const uint8_t empty_source[] = "";
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Returns the size of the pm_string_t struct. This is necessary to allocate the
|
|
5
7
|
* correct amount of memory in the FFI backend.
|
|
@@ -133,8 +135,7 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) {
|
|
|
133
135
|
// the source to a constant empty string and return.
|
|
134
136
|
if (file_size == 0) {
|
|
135
137
|
pm_string_file_handle_close(&handle);
|
|
136
|
-
|
|
137
|
-
*string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
|
|
138
|
+
*string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 };
|
|
138
139
|
return PM_STRING_INIT_SUCCESS;
|
|
139
140
|
}
|
|
140
141
|
|
|
@@ -182,8 +183,7 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) {
|
|
|
182
183
|
|
|
183
184
|
if (size == 0) {
|
|
184
185
|
close(fd);
|
|
185
|
-
|
|
186
|
-
*string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
|
|
186
|
+
*string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 };
|
|
187
187
|
return PM_STRING_INIT_SUCCESS;
|
|
188
188
|
}
|
|
189
189
|
|
|
@@ -225,8 +225,7 @@ pm_string_file_init(pm_string_t *string, const char *filepath) {
|
|
|
225
225
|
// the source to a constant empty string and return.
|
|
226
226
|
if (file_size == 0) {
|
|
227
227
|
pm_string_file_handle_close(&handle);
|
|
228
|
-
|
|
229
|
-
*string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
|
|
228
|
+
*string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 };
|
|
230
229
|
return PM_STRING_INIT_SUCCESS;
|
|
231
230
|
}
|
|
232
231
|
|
|
@@ -278,8 +277,7 @@ pm_string_file_init(pm_string_t *string, const char *filepath) {
|
|
|
278
277
|
size_t size = (size_t) sb.st_size;
|
|
279
278
|
if (size == 0) {
|
|
280
279
|
close(fd);
|
|
281
|
-
|
|
282
|
-
*string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = source, .length = 0 };
|
|
280
|
+
*string = (pm_string_t) { .type = PM_STRING_CONSTANT, .source = empty_source, .length = 0 };
|
|
283
281
|
return PM_STRING_INIT_SUCCESS;
|
|
284
282
|
}
|
|
285
283
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herb-tools/node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Native Node.js addon for HTML-aware ERB parsing using Herb.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"host": "https://github.com/marcoroth/herb/releases/download/"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@herb-tools/core": "0.
|
|
51
|
+
"@herb-tools/core": "0.8.0",
|
|
52
52
|
"@mapbox/node-pre-gyp": "^2.0.0",
|
|
53
|
-
"node-addon-api": "^5.
|
|
53
|
+
"node-addon-api": "^8.5.0",
|
|
54
54
|
"node-pre-gyp-github": "^2.0.0"
|
|
55
55
|
},
|
|
56
56
|
"files": [
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
#ifndef HERB_ARRAY_H
|
|
2
|
-
#define HERB_ARRAY_H
|
|
3
|
-
|
|
4
|
-
#include <stdlib.h>
|
|
5
|
-
|
|
6
|
-
typedef struct ARRAY_STRUCT {
|
|
7
|
-
void** items;
|
|
8
|
-
size_t size;
|
|
9
|
-
size_t capacity;
|
|
10
|
-
} array_T;
|
|
11
|
-
|
|
12
|
-
array_T* array_init(size_t capacity);
|
|
13
|
-
|
|
14
|
-
void* array_get(const array_T* array, size_t index);
|
|
15
|
-
void* array_first(array_T* array);
|
|
16
|
-
void* array_last(array_T* array);
|
|
17
|
-
|
|
18
|
-
void array_append(array_T* array, void* item);
|
|
19
|
-
void array_set(const array_T* array, size_t index, void* item);
|
|
20
|
-
void array_free(array_T** array);
|
|
21
|
-
void array_remove(array_T* array, size_t index);
|
|
22
|
-
|
|
23
|
-
size_t array_index_of(array_T* array, void* item);
|
|
24
|
-
void array_remove_item(array_T* array, void* item);
|
|
25
|
-
|
|
26
|
-
void array_push(array_T* array, void* item);
|
|
27
|
-
void* array_pop(array_T* array);
|
|
28
|
-
|
|
29
|
-
size_t array_capacity(const array_T* array);
|
|
30
|
-
size_t array_size(const array_T* array);
|
|
31
|
-
size_t array_sizeof(void);
|
|
32
|
-
|
|
33
|
-
#endif
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
#include <stdint.h>
|
|
2
|
-
#include <stdio.h>
|
|
3
|
-
#include <string.h>
|
|
4
|
-
|
|
5
|
-
#include "include/buffer.h"
|
|
6
|
-
#include "include/macros.h"
|
|
7
|
-
#include "include/memory.h"
|
|
8
|
-
#include "include/util.h"
|
|
9
|
-
|
|
10
|
-
bool buffer_init(buffer_T* buffer) {
|
|
11
|
-
buffer->capacity = 1024;
|
|
12
|
-
buffer->length = 0;
|
|
13
|
-
buffer->value = nullable_safe_malloc((buffer->capacity + 1) * sizeof(char));
|
|
14
|
-
|
|
15
|
-
if (!buffer->value) {
|
|
16
|
-
fprintf(stderr, "Error: Failed to initialize buffer with capacity of %zu.\n", buffer->capacity);
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
buffer->value[0] = '\0';
|
|
21
|
-
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
buffer_T buffer_new(void) {
|
|
26
|
-
buffer_T buffer;
|
|
27
|
-
buffer_init(&buffer);
|
|
28
|
-
return buffer;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
char* buffer_value(const buffer_T* buffer) {
|
|
32
|
-
return buffer->value;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
size_t buffer_length(const buffer_T* buffer) {
|
|
36
|
-
return buffer->length;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
size_t buffer_capacity(const buffer_T* buffer) {
|
|
40
|
-
return buffer->capacity;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
size_t buffer_sizeof(void) {
|
|
44
|
-
return sizeof(buffer_T);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Increases the capacity of the buffer if needed to accommodate additional content.
|
|
49
|
-
* This function only handles memory allocation and does not modify the buffer content
|
|
50
|
-
* or null termination.
|
|
51
|
-
*
|
|
52
|
-
* @param buffer The buffer to increase capacity for
|
|
53
|
-
* @param additional_capacity The additional length needed beyond current buffer capacity
|
|
54
|
-
* @return true if capacity was increased, false if reallocation failed
|
|
55
|
-
*/
|
|
56
|
-
bool buffer_increase_capacity(buffer_T* buffer, const size_t additional_capacity) {
|
|
57
|
-
if (additional_capacity + 1 >= SIZE_MAX) {
|
|
58
|
-
fprintf(stderr, "Error: Buffer capacity would overflow system limits.\n");
|
|
59
|
-
exit(1);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const size_t new_capacity = buffer->capacity + additional_capacity;
|
|
63
|
-
|
|
64
|
-
return buffer_resize(buffer, new_capacity);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Resizes the capacity of the buffer to the specified new capacity.
|
|
69
|
-
*
|
|
70
|
-
* @param buffer The buffer to resize
|
|
71
|
-
* @param new_capacity The new capacity to resize the buffer to
|
|
72
|
-
* @return true if capacity was resized, false if reallocation failed
|
|
73
|
-
*/
|
|
74
|
-
bool buffer_resize(buffer_T* buffer, const size_t new_capacity) {
|
|
75
|
-
if (new_capacity + 1 >= SIZE_MAX) {
|
|
76
|
-
fprintf(stderr, "Error: Buffer capacity would overflow system limits.\n");
|
|
77
|
-
exit(1);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
char* new_value = nullable_safe_realloc(buffer->value, new_capacity + 1);
|
|
81
|
-
|
|
82
|
-
if (unlikely(new_value == NULL)) {
|
|
83
|
-
fprintf(stderr, "Error: Failed to resize buffer to %zu.\n", new_capacity);
|
|
84
|
-
exit(1);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
buffer->value = new_value;
|
|
88
|
-
buffer->capacity = new_capacity;
|
|
89
|
-
|
|
90
|
-
return true;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Expands the capacity of the buffer by doubling its current capacity.
|
|
95
|
-
* This function is a convenience function that calls buffer_increase_capacity
|
|
96
|
-
* with a factor of 2.
|
|
97
|
-
*
|
|
98
|
-
* @param buffer The buffer to expand capacity for
|
|
99
|
-
* @return true if capacity was increased, false if reallocation failed
|
|
100
|
-
*/
|
|
101
|
-
bool buffer_expand_capacity(buffer_T* buffer) {
|
|
102
|
-
return buffer_resize(buffer, buffer->capacity * 2);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Expands the capacity of the buffer if needed to accommodate additional content.
|
|
107
|
-
* This function is a convenience function that calls buffer_has_capacity and
|
|
108
|
-
* buffer_expand_capacity.
|
|
109
|
-
*
|
|
110
|
-
* @param buffer The buffer to expand capacity for
|
|
111
|
-
* @param required_length The additional length needed beyond current buffer capacity
|
|
112
|
-
* @return true if capacity was increased, false if reallocation failed
|
|
113
|
-
*/
|
|
114
|
-
bool buffer_expand_if_needed(buffer_T* buffer, const size_t required_length) {
|
|
115
|
-
if (buffer_has_capacity(buffer, required_length)) { return true; }
|
|
116
|
-
|
|
117
|
-
return buffer_resize(buffer, buffer->capacity + (required_length * 2));
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Appends a null-terminated string to the buffer.
|
|
122
|
-
* @note This function requires that 'text' is a properly null-terminated string.
|
|
123
|
-
* When reading data from files or other non-string sources, ensure the data is
|
|
124
|
-
* null-terminated before calling this function, or use buffer_append_with_length instead.
|
|
125
|
-
*
|
|
126
|
-
* @param buffer The buffer to append to
|
|
127
|
-
* @param text A null-terminated string to append
|
|
128
|
-
* @return void
|
|
129
|
-
*/
|
|
130
|
-
void buffer_append(buffer_T* buffer, const char* text) {
|
|
131
|
-
if (!buffer || !text) { return; }
|
|
132
|
-
if (text[0] == '\0') { return; }
|
|
133
|
-
|
|
134
|
-
size_t text_length = strlen(text);
|
|
135
|
-
|
|
136
|
-
if (!buffer_expand_if_needed(buffer, text_length)) { return; }
|
|
137
|
-
|
|
138
|
-
memcpy(buffer->value + buffer->length, text, text_length);
|
|
139
|
-
buffer->length += text_length;
|
|
140
|
-
buffer->value[buffer->length] = '\0';
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Appends a string of specified length to the buffer.
|
|
145
|
-
* Unlike buffer_append(), this function does not require the text to be
|
|
146
|
-
* null-terminated as it uses the provided length instead of strlen().
|
|
147
|
-
* This is particularly useful when working with data from files, network
|
|
148
|
-
* buffers, or other non-null-terminated sources.
|
|
149
|
-
*
|
|
150
|
-
* @param buffer The buffer to append to
|
|
151
|
-
* @param text The text to append (doesn't need to be null-terminated)
|
|
152
|
-
* @param length The number of bytes to append from text
|
|
153
|
-
* @return void
|
|
154
|
-
*/
|
|
155
|
-
void buffer_append_with_length(buffer_T* buffer, const char* text, const size_t length) {
|
|
156
|
-
if (!buffer || !text || length == 0) { return; }
|
|
157
|
-
if (!buffer_expand_if_needed(buffer, length)) { return; }
|
|
158
|
-
|
|
159
|
-
memcpy(buffer->value + buffer->length, text, length);
|
|
160
|
-
|
|
161
|
-
buffer->length += length;
|
|
162
|
-
buffer->value[buffer->length] = '\0';
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
void buffer_append_char(buffer_T* buffer, const char character) {
|
|
166
|
-
static char string[2];
|
|
167
|
-
|
|
168
|
-
string[0] = character;
|
|
169
|
-
string[1] = '\0';
|
|
170
|
-
|
|
171
|
-
buffer_append(buffer, string);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
void buffer_append_repeated(buffer_T* buffer, const char character, size_t length) {
|
|
175
|
-
if (length == 0) { return; }
|
|
176
|
-
|
|
177
|
-
char* spaces = malloc(length + 1);
|
|
178
|
-
if (!spaces) { return; }
|
|
179
|
-
|
|
180
|
-
memset(spaces, character, length);
|
|
181
|
-
spaces[length] = '\0';
|
|
182
|
-
|
|
183
|
-
buffer_append(buffer, spaces);
|
|
184
|
-
|
|
185
|
-
free(spaces);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
void buffer_append_whitespace(buffer_T* buffer, const size_t length) {
|
|
189
|
-
buffer_append_repeated(buffer, ' ', length);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
void buffer_prepend(buffer_T* buffer, const char* text) {
|
|
193
|
-
if (!buffer || !text) { return; }
|
|
194
|
-
if (text[0] == '\0') { return; }
|
|
195
|
-
|
|
196
|
-
size_t text_length = strlen(text);
|
|
197
|
-
|
|
198
|
-
if (!buffer_expand_if_needed(buffer, text_length)) { return; }
|
|
199
|
-
|
|
200
|
-
memmove(buffer->value + text_length, buffer->value, buffer->length + 1);
|
|
201
|
-
memcpy(buffer->value, text, text_length);
|
|
202
|
-
|
|
203
|
-
buffer->length += text_length;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
void buffer_concat(buffer_T* destination, buffer_T* source) {
|
|
207
|
-
if (source->length == 0) { return; }
|
|
208
|
-
if (!buffer_expand_if_needed(destination, source->length)) { return; }
|
|
209
|
-
|
|
210
|
-
memcpy(destination->value + destination->length, source->value, source->length);
|
|
211
|
-
|
|
212
|
-
destination->length += source->length;
|
|
213
|
-
destination->value[destination->length] = '\0';
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
bool buffer_has_capacity(buffer_T* buffer, const size_t required_length) {
|
|
217
|
-
return (buffer->length + required_length <= buffer->capacity);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
void buffer_clear(buffer_T* buffer) {
|
|
221
|
-
buffer->length = 0;
|
|
222
|
-
buffer->value[0] = '\0';
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
void buffer_free(buffer_T* buffer) {
|
|
226
|
-
if (!buffer) { return; }
|
|
227
|
-
|
|
228
|
-
if (buffer->value != NULL) { free(buffer->value); }
|
|
229
|
-
|
|
230
|
-
buffer->value = NULL;
|
|
231
|
-
buffer->length = buffer->capacity = 0;
|
|
232
|
-
}
|