prism 1.9.0 → 2.0.0.rc2
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/CHANGELOG.md +88 -0
- data/CODE_OF_CONDUCT.md +1 -1
- data/LICENSE.md +1 -1
- data/Makefile +41 -12
- data/README.md +35 -97
- data/config.yml +174 -161
- data/docs/build_system.md +2 -2
- data/docs/configuration.md +5 -4
- data/docs/encoding.md +2 -2
- data/docs/fuzzing.md +4 -11
- data/docs/javascript.md +19 -4
- data/docs/mapping.md +1 -1
- data/docs/releasing.md +77 -5
- data/docs/relocation.md +2 -4
- data/docs/serialization.md +22 -24
- data/docs/testing.md +46 -29
- data/ext/prism/api_node.c +1461 -1401
- data/ext/prism/extconf.rb +3 -4
- data/ext/prism/extension.c +796 -422
- data/ext/prism/extension.h +3 -3
- data/include/prism/arena.h +37 -0
- data/include/prism/ast.h +2727 -610
- data/include/prism/buffer.h +52 -0
- data/include/prism/comments.h +55 -0
- data/include/prism/compiler/accel.h +26 -0
- data/include/prism/compiler/align.h +36 -0
- data/include/prism/compiler/assume.h +25 -0
- data/include/prism/compiler/bswap.h +46 -0
- data/include/prism/compiler/endianness.h +34 -0
- data/include/prism/compiler/exported.h +24 -0
- data/include/prism/compiler/fallthrough.h +22 -0
- data/include/prism/compiler/filesystem.h +32 -0
- data/include/prism/compiler/flex_array.h +19 -0
- data/include/prism/compiler/force_inline.h +21 -0
- data/include/prism/compiler/format.h +25 -0
- data/include/prism/compiler/inline.h +17 -0
- data/include/prism/compiler/nodiscard.h +22 -0
- data/include/prism/compiler/nonnull.h +18 -0
- data/include/prism/compiler/unused.h +18 -0
- data/include/prism/constant_pool.h +81 -0
- data/include/prism/diagnostic.h +38 -403
- data/include/prism/errors_format.h +53 -0
- data/include/prism/excludes.h +29 -0
- data/include/prism/integer.h +41 -0
- data/include/prism/internal/allocator.h +68 -0
- data/include/prism/internal/allocator_debug.h +88 -0
- data/include/prism/internal/arena.h +108 -0
- data/include/prism/internal/bit.h +42 -0
- data/include/prism/internal/buffer.h +94 -0
- data/include/prism/internal/char.h +145 -0
- data/include/prism/internal/comments.h +53 -0
- data/include/prism/internal/constant_pool.h +152 -0
- data/include/prism/internal/diagnostic.h +389 -0
- data/include/prism/{encoding.h → internal/encoding.h} +27 -68
- data/include/prism/internal/integer.h +68 -0
- data/include/prism/internal/isinf.h +16 -0
- data/include/prism/internal/line_offset_list.h +34 -0
- data/include/prism/{util/pm_list.h → internal/list.h} +11 -52
- data/include/prism/internal/magic_comments.h +23 -0
- data/include/prism/internal/memchr.h +15 -0
- data/include/prism/internal/node.h +38 -0
- data/include/prism/internal/options.h +232 -0
- data/include/prism/internal/parser.h +1004 -0
- data/include/prism/internal/regexp.h +26 -0
- data/include/prism/internal/serialize.h +39 -0
- data/include/prism/internal/source.h +72 -0
- data/include/prism/{static_literals.h → internal/static_literals.h} +26 -47
- data/include/prism/internal/stringy.h +35 -0
- data/include/prism/{util/pm_strncasecmp.h → internal/strncasecmp.h} +3 -17
- data/include/prism/{util/pm_strpbrk.h → internal/strpbrk.h} +7 -20
- data/include/prism/internal/tokens.h +11 -0
- data/include/prism/internal/xxh3.h +16 -0
- data/include/prism/json.h +32 -0
- data/include/prism/line_offset_list.h +61 -0
- data/include/prism/magic_comments.h +35 -0
- data/include/prism/node.h +18 -53
- data/include/prism/options.h +146 -280
- data/include/prism/parser.h +356 -867
- data/include/prism/prettyprint.h +6 -9
- data/include/prism/serialize.h +115 -0
- data/include/prism/source.h +155 -0
- data/include/prism/stream.h +28 -0
- data/include/prism/string_query.h +74 -0
- data/include/prism/stringy.h +72 -0
- data/include/prism/version.h +12 -3
- data/include/prism.h +43 -320
- data/lib/prism/compiler.rb +319 -305
- data/lib/prism/desugar_compiler.rb +105 -34
- data/lib/prism/dispatcher.rb +646 -473
- data/lib/prism/dot_visitor.rb +592 -511
- data/lib/prism/dsl.rb +391 -25
- data/lib/prism/ffi.rb +258 -90
- data/lib/prism/inspect_visitor.rb +357 -325
- data/lib/prism/lex_compat.rb +254 -212
- data/lib/prism/mutation_compiler.rb +313 -305
- data/lib/prism/node.rb +20966 -6992
- data/lib/prism/node_ext.rb +180 -187
- data/lib/prism/node_find.rb +215 -0
- data/lib/prism/parse_result/errors.rb +7 -1
- data/lib/prism/parse_result/newlines.rb +276 -8
- data/lib/prism/parse_result.rb +468 -139
- data/lib/prism/pattern.rb +65 -20
- data/lib/prism/reflection.rb +23 -12
- data/lib/prism/relocation.rb +149 -87
- data/lib/prism/serialize.rb +3460 -539
- data/lib/prism/string_query.rb +24 -1
- data/lib/prism/translation/parser/builder.rb +10 -2
- data/lib/prism/translation/parser/compiler.rb +44 -52
- data/lib/prism/translation/parser/lexer.rb +41 -92
- data/lib/prism/translation/parser.rb +1 -1
- data/lib/prism/translation/parser_current.rb +1 -1
- data/lib/prism/translation/ripper/lexer.rb +8 -10
- data/lib/prism/translation/ripper/sexp.rb +2 -10
- data/lib/prism/translation/ripper/shim.rb +2 -0
- data/lib/prism/translation/ripper.rb +967 -209
- data/lib/prism/translation/ruby_parser.rb +73 -316
- data/lib/prism/translation.rb +2 -0
- data/lib/prism/visitor.rb +632 -5
- data/lib/prism.rb +79 -9
- data/prism.gemspec +128 -62
- data/rbi/generated/prism/compiler.rbi +489 -0
- data/rbi/generated/prism/desugar_compiler.rbi +306 -0
- data/rbi/generated/prism/dispatcher.rbi +1138 -0
- data/rbi/generated/prism/dot_visitor.rbi +618 -0
- data/rbi/generated/prism/dsl.rbi +751 -0
- data/rbi/generated/prism/inspect_visitor.rbi +503 -0
- data/rbi/generated/prism/lex_compat.rbi +162 -0
- data/rbi/generated/prism/mutation_compiler.rbi +464 -0
- data/rbi/generated/prism/node.rbi +14407 -0
- data/rbi/generated/prism/node_ext.rbi +259 -0
- data/rbi/generated/prism/node_find.rbi +79 -0
- data/rbi/generated/prism/parse_result/errors.rbi +21 -0
- data/rbi/generated/prism/parse_result/newlines.rbi +208 -0
- data/rbi/generated/prism/parse_result.rbi +776 -0
- data/rbi/generated/prism/pattern.rbi +134 -0
- data/rbi/generated/prism/reflection.rbi +89 -0
- data/rbi/generated/prism/relocation.rbi +329 -0
- data/rbi/generated/prism/serialize.rbi +184 -0
- data/rbi/generated/prism/string_query.rbi +43 -0
- data/rbi/generated/prism/translation.rbi +7 -0
- data/rbi/generated/prism/visitor.rbi +650 -0
- data/rbi/generated/prism.rbi +86 -0
- data/rbi/prism/translation/parser_versions.rbi +5 -0
- data/rbi/rubyvm/node_find.rbi +14 -0
- data/sig/generated/prism/compiler.rbs +492 -0
- data/sig/generated/prism/desugar_compiler.rbs +305 -0
- data/sig/generated/prism/dispatcher.rbs +1292 -0
- data/sig/generated/prism/dot_visitor.rbs +635 -0
- data/sig/generated/prism/dsl.rbs +928 -0
- data/sig/generated/prism/inspect_visitor.rbs +509 -0
- data/sig/generated/prism/lex_compat.rbs +166 -0
- data/sig/{prism → generated/prism}/mutation_compiler.rbs +309 -4
- data/sig/generated/prism/node.rbs +20896 -0
- data/sig/generated/prism/node_ext.rbs +290 -0
- data/sig/generated/prism/node_find.rbs +90 -0
- data/sig/generated/prism/parse_result/errors.rbs +22 -0
- data/sig/generated/prism/parse_result/newlines.rbs +223 -0
- data/sig/generated/prism/parse_result.rbs +871 -0
- data/sig/generated/prism/pattern.rbs +156 -0
- data/sig/generated/prism/reflection.rbs +101 -0
- data/sig/generated/prism/relocation.rbs +428 -0
- data/sig/generated/prism/serialize.rbs +198 -0
- data/sig/generated/prism/string_query.rbs +43 -0
- data/sig/generated/prism/translation.rbs +8 -0
- data/sig/generated/prism/visitor.rbs +1111 -0
- data/sig/generated/prism.rbs +84 -0
- data/sig/manifest.yaml +2 -0
- data/src/arena.c +117 -0
- data/src/{util/pm_buffer.c → buffer.c} +53 -21
- data/src/{util/pm_char.c → char.c} +28 -57
- data/src/comments.c +454 -0
- data/src/constant_pool.c +406 -0
- data/src/diagnostic.c +97 -65
- data/src/encoding.c +8 -3
- data/src/errors_format.c +519 -0
- data/src/{util/pm_integer.c → integer.c} +33 -22
- data/src/json.c +5733 -0
- data/src/line_offset_list.c +100 -0
- data/src/list.c +24 -0
- data/src/{util/pm_memchr.c → memchr.c} +8 -6
- data/src/node.c +3504 -7674
- data/src/options.c +162 -49
- data/src/parser.c +367 -0
- data/src/prettyprint.c +421 -354
- data/src/prism.c +8402 -7161
- data/src/regexp.c +961 -45
- data/src/serialize.c +460 -424
- data/src/source.c +518 -0
- data/src/static_literals.c +111 -43
- data/src/string_query.c +180 -0
- data/src/stringy.c +91 -0
- data/src/{util/pm_strncasecmp.c → strncasecmp.c} +5 -4
- data/src/strpbrk.c +447 -0
- data/src/{token_type.c → tokens.c} +39 -18
- data/src/xxh3.c +292 -0
- metadata +128 -63
- data/ext/prism/api_pack.c +0 -276
- data/include/prism/defines.h +0 -260
- data/include/prism/pack.h +0 -163
- data/include/prism/regexp.h +0 -43
- data/include/prism/util/pm_buffer.h +0 -236
- data/include/prism/util/pm_char.h +0 -204
- data/include/prism/util/pm_constant_pool.h +0 -218
- data/include/prism/util/pm_integer.h +0 -130
- data/include/prism/util/pm_memchr.h +0 -29
- data/include/prism/util/pm_newline_list.h +0 -113
- data/include/prism/util/pm_string.h +0 -200
- data/lib/prism/pack.rb +0 -230
- data/lib/prism/parse_result/comments.rb +0 -188
- data/rbi/prism/compiler.rbi +0 -12
- data/rbi/prism/dsl.rbi +0 -524
- data/rbi/prism/inspect_visitor.rbi +0 -12
- data/rbi/prism/node.rbi +0 -8750
- data/rbi/prism/node_ext.rbi +0 -107
- data/rbi/prism/parse_result.rbi +0 -404
- data/rbi/prism/reflection.rbi +0 -58
- data/rbi/prism/string_query.rbi +0 -12
- data/rbi/prism/visitor.rbi +0 -473
- data/rbi/prism.rbi +0 -63
- data/sig/prism/compiler.rbs +0 -9
- data/sig/prism/dispatcher.rbs +0 -19
- data/sig/prism/dot_visitor.rbs +0 -6
- data/sig/prism/dsl.rbs +0 -351
- data/sig/prism/inspect_visitor.rbs +0 -22
- data/sig/prism/lex_compat.rbs +0 -10
- data/sig/prism/node.rbs +0 -4042
- data/sig/prism/node_ext.rbs +0 -149
- data/sig/prism/pack.rbs +0 -43
- data/sig/prism/parse_result/comments.rbs +0 -38
- data/sig/prism/parse_result.rbs +0 -197
- data/sig/prism/pattern.rbs +0 -13
- data/sig/prism/reflection.rbs +0 -50
- data/sig/prism/relocation.rbs +0 -185
- data/sig/prism/serialize.rbs +0 -8
- data/sig/prism/string_query.rbs +0 -11
- data/sig/prism/visitor.rbs +0 -169
- data/sig/prism.rbs +0 -272
- data/src/pack.c +0 -509
- data/src/util/pm_constant_pool.c +0 -342
- data/src/util/pm_list.c +0 -49
- data/src/util/pm_newline_list.c +0 -125
- data/src/util/pm_string.c +0 -381
- data/src/util/pm_strpbrk.c +0 -206
data/src/errors_format.c
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
#include "prism/errors_format.h"
|
|
2
|
+
|
|
3
|
+
#include "prism/internal/allocator.h"
|
|
4
|
+
#include "prism/internal/buffer.h"
|
|
5
|
+
#include "prism/internal/diagnostic.h"
|
|
6
|
+
#include "prism/internal/encoding.h"
|
|
7
|
+
#include "prism/internal/line_offset_list.h"
|
|
8
|
+
#include "prism/internal/parser.h"
|
|
9
|
+
|
|
10
|
+
#include <assert.h>
|
|
11
|
+
#include <inttypes.h>
|
|
12
|
+
#include <stdbool.h>
|
|
13
|
+
#include <stdlib.h>
|
|
14
|
+
#include <string.h>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Check if the source touched by the given location is valid UTF-8. The
|
|
18
|
+
* location represents the location of the error, but the slice of the source
|
|
19
|
+
* that will be displayed includes the content of all of the lines that the
|
|
20
|
+
* error touches, so we need to check those parts as well.
|
|
21
|
+
*/
|
|
22
|
+
static bool
|
|
23
|
+
location_is_utf8(const pm_parser_t *parser, const pm_location_t *location) {
|
|
24
|
+
const pm_line_offset_list_t *line_offsets = &parser->line_offsets;
|
|
25
|
+
const size_t start_line = (size_t) pm_line_offset_list_line_column(line_offsets, location->start, 1).line;
|
|
26
|
+
const size_t end_line = (size_t) pm_line_offset_list_line_column(line_offsets, location->start + location->length, 1).line;
|
|
27
|
+
|
|
28
|
+
const uint8_t *cursor = parser->start + line_offsets->offsets[start_line - 1];
|
|
29
|
+
const uint8_t *end = (end_line == line_offsets->size) ? parser->end : (parser->start + line_offsets->offsets[end_line]);
|
|
30
|
+
|
|
31
|
+
while (cursor < end) {
|
|
32
|
+
size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
|
|
33
|
+
if (width == 0) return false;
|
|
34
|
+
|
|
35
|
+
cursor += width;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
typedef struct {
|
|
42
|
+
pm_diagnostic_t *diagnostic;
|
|
43
|
+
int32_t line;
|
|
44
|
+
uint32_t column_start;
|
|
45
|
+
uint32_t column_end;
|
|
46
|
+
size_t idx;
|
|
47
|
+
} pm_rich_error_t;
|
|
48
|
+
|
|
49
|
+
static int
|
|
50
|
+
pm_rich_error_compare(const void *a, const void *b) {
|
|
51
|
+
const pm_rich_error_t *left = (const pm_rich_error_t *) a;
|
|
52
|
+
const pm_rich_error_t *right = (const pm_rich_error_t *) b;
|
|
53
|
+
|
|
54
|
+
if (left->line != right->line) {
|
|
55
|
+
return (left->line < right->line) ? -1 : 1;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (left->column_start != right->column_start) {
|
|
59
|
+
return (left->column_start < right->column_start) ? -1 : 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (left->idx != right->idx) {
|
|
63
|
+
return (left->idx < right->idx) ? 1 : -1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#define COLOR_BOLD "\033[1m"
|
|
70
|
+
#define COLOR_GRAY "\033[2m"
|
|
71
|
+
#define COLOR_RED "\033[1;31m"
|
|
72
|
+
#define COLOR_RESET "\033[m"
|
|
73
|
+
#define TRUNCATE 30
|
|
74
|
+
|
|
75
|
+
typedef struct {
|
|
76
|
+
const char *number_prefix;
|
|
77
|
+
const char *blank_prefix;
|
|
78
|
+
const char *divider;
|
|
79
|
+
size_t blank_prefix_length;
|
|
80
|
+
size_t divider_length;
|
|
81
|
+
} pm_error_line_format_t;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Initialize the given line format struct based on whether or not to highlight
|
|
85
|
+
* the line and the first and last line numbers.
|
|
86
|
+
*/
|
|
87
|
+
static void
|
|
88
|
+
pm_error_line_format_init(pm_error_line_format_t *format, pm_errors_format_type_t format_type, int32_t first_line, int32_t last_line) {
|
|
89
|
+
/* If we have a maximum line number that is negative, then we are going to
|
|
90
|
+
* use the absolute value for comparison but multiply by 10 to additionally
|
|
91
|
+
* have a column for the negative sign. */
|
|
92
|
+
if (first_line < 0) first_line = (-first_line) * 10;
|
|
93
|
+
if (last_line < 0) last_line = (-last_line) * 10;
|
|
94
|
+
int32_t max_line = first_line > last_line ? first_line : last_line;
|
|
95
|
+
|
|
96
|
+
if (max_line < 10) {
|
|
97
|
+
if (format_type > PM_ERRORS_FORMAT_PLAIN) {
|
|
98
|
+
*format = (pm_error_line_format_t) {
|
|
99
|
+
.number_prefix = COLOR_GRAY "%1" PRIi32 " | " COLOR_RESET,
|
|
100
|
+
.blank_prefix = COLOR_GRAY " | " COLOR_RESET,
|
|
101
|
+
.divider = COLOR_GRAY " ~~~~~" COLOR_RESET "\n"
|
|
102
|
+
};
|
|
103
|
+
} else {
|
|
104
|
+
*format = (pm_error_line_format_t) {
|
|
105
|
+
.number_prefix = "%1" PRIi32 " | ",
|
|
106
|
+
.blank_prefix = " | ",
|
|
107
|
+
.divider = " ~~~~~\n"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
} else if (max_line < 100) {
|
|
111
|
+
if (format_type > PM_ERRORS_FORMAT_PLAIN) {
|
|
112
|
+
*format = (pm_error_line_format_t) {
|
|
113
|
+
.number_prefix = COLOR_GRAY "%2" PRIi32 " | " COLOR_RESET,
|
|
114
|
+
.blank_prefix = COLOR_GRAY " | " COLOR_RESET,
|
|
115
|
+
.divider = COLOR_GRAY " ~~~~~~" COLOR_RESET "\n"
|
|
116
|
+
};
|
|
117
|
+
} else {
|
|
118
|
+
*format = (pm_error_line_format_t) {
|
|
119
|
+
.number_prefix = "%2" PRIi32 " | ",
|
|
120
|
+
.blank_prefix = " | ",
|
|
121
|
+
.divider = " ~~~~~~\n"
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
} else if (max_line < 1000) {
|
|
125
|
+
if (format_type > PM_ERRORS_FORMAT_PLAIN) {
|
|
126
|
+
*format = (pm_error_line_format_t) {
|
|
127
|
+
.number_prefix = COLOR_GRAY "%3" PRIi32 " | " COLOR_RESET,
|
|
128
|
+
.blank_prefix = COLOR_GRAY " | " COLOR_RESET,
|
|
129
|
+
.divider = COLOR_GRAY " ~~~~~~~" COLOR_RESET "\n"
|
|
130
|
+
};
|
|
131
|
+
} else {
|
|
132
|
+
*format = (pm_error_line_format_t) {
|
|
133
|
+
.number_prefix = "%3" PRIi32 " | ",
|
|
134
|
+
.blank_prefix = " | ",
|
|
135
|
+
.divider = " ~~~~~~~\n"
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
} else if (max_line < 10000) {
|
|
139
|
+
if (format_type > PM_ERRORS_FORMAT_PLAIN) {
|
|
140
|
+
*format = (pm_error_line_format_t) {
|
|
141
|
+
.number_prefix = COLOR_GRAY "%4" PRIi32 " | " COLOR_RESET,
|
|
142
|
+
.blank_prefix = COLOR_GRAY " | " COLOR_RESET,
|
|
143
|
+
.divider = COLOR_GRAY " ~~~~~~~~" COLOR_RESET "\n"
|
|
144
|
+
};
|
|
145
|
+
} else {
|
|
146
|
+
*format = (pm_error_line_format_t) {
|
|
147
|
+
.number_prefix = "%4" PRIi32 " | ",
|
|
148
|
+
.blank_prefix = " | ",
|
|
149
|
+
.divider = " ~~~~~~~~\n"
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
if (format_type > PM_ERRORS_FORMAT_PLAIN) {
|
|
154
|
+
*format = (pm_error_line_format_t) {
|
|
155
|
+
.number_prefix = COLOR_GRAY "%5" PRIi32 " | " COLOR_RESET,
|
|
156
|
+
.blank_prefix = COLOR_GRAY " | " COLOR_RESET,
|
|
157
|
+
.divider = COLOR_GRAY " ~~~~~~~~" COLOR_RESET "\n"
|
|
158
|
+
};
|
|
159
|
+
} else {
|
|
160
|
+
*format = (pm_error_line_format_t) {
|
|
161
|
+
.number_prefix = "%5" PRIi32 " | ",
|
|
162
|
+
.blank_prefix = " | ",
|
|
163
|
+
.divider = " ~~~~~~~~\n"
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
format->blank_prefix_length = strlen(format->blank_prefix);
|
|
169
|
+
format->divider_length = strlen(format->divider);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
static void
|
|
173
|
+
pm_error_format_line(const pm_parser_t *parser, pm_buffer_t *buffer, const char *number_prefix, int32_t line, uint32_t column_start, uint32_t column_end) {
|
|
174
|
+
int32_t line_delta = line - parser->start_line;
|
|
175
|
+
assert(line_delta >= 0);
|
|
176
|
+
|
|
177
|
+
size_t index = (size_t) line_delta;
|
|
178
|
+
assert(index < parser->line_offsets.size);
|
|
179
|
+
|
|
180
|
+
const uint8_t *start = parser->start + parser->line_offsets.offsets[index];
|
|
181
|
+
const uint8_t *end;
|
|
182
|
+
|
|
183
|
+
if (index >= parser->line_offsets.size - 1) {
|
|
184
|
+
end = parser->end;
|
|
185
|
+
} else {
|
|
186
|
+
end = parser->start + parser->line_offsets.offsets[index + 1];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
pm_buffer_append_format(buffer, number_prefix, line);
|
|
190
|
+
|
|
191
|
+
/* Here we determine if we should truncate the end of the line. Note that
|
|
192
|
+
* this is written to avoid computing start + column_end, which could be
|
|
193
|
+
* more than one past the end of the source when the error is at the end
|
|
194
|
+
* of the input. */
|
|
195
|
+
bool truncate_end = false;
|
|
196
|
+
if ((column_end != 0) && ((end - start) - ((ptrdiff_t) column_end) >= TRUNCATE)) {
|
|
197
|
+
const uint8_t *end_candidate = start + column_end + TRUNCATE;
|
|
198
|
+
|
|
199
|
+
for (const uint8_t *cursor = start; cursor < end_candidate;) {
|
|
200
|
+
size_t char_width = pm_parser_encoding_char_width(parser, cursor, parser->end - cursor);
|
|
201
|
+
|
|
202
|
+
/* If we failed to decode a character, then just bail out and
|
|
203
|
+
* truncate at the fixed width. */
|
|
204
|
+
if (char_width == 0) break;
|
|
205
|
+
|
|
206
|
+
/* If this next character would go past the end candidate,
|
|
207
|
+
* then we need to truncate before it. */
|
|
208
|
+
if (cursor + char_width > end_candidate) {
|
|
209
|
+
end_candidate = cursor;
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
cursor += char_width;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
end = end_candidate;
|
|
217
|
+
truncate_end = true;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* Here we determine if we should truncate the start of the line. */
|
|
221
|
+
if (column_start >= TRUNCATE) {
|
|
222
|
+
pm_buffer_append_string(buffer, "... ", 4);
|
|
223
|
+
start += column_start;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
pm_buffer_append_string(buffer, (const char *) start, (size_t) (end - start));
|
|
227
|
+
|
|
228
|
+
if (truncate_end) {
|
|
229
|
+
pm_buffer_append_string(buffer, " ...\n", 5);
|
|
230
|
+
} else if (end == parser->end && end > parser->start && end[-1] != '\n') {
|
|
231
|
+
pm_buffer_append_byte(buffer, '\n');
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
static void
|
|
236
|
+
pm_rich_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, pm_errors_format_type_t format_type, size_t nerrors, pm_rich_error_t *rich_errors, bool inline_messages) {
|
|
237
|
+
pm_error_line_format_t format;
|
|
238
|
+
pm_error_line_format_init(&format, format_type, rich_errors[0].line, rich_errors[nerrors - 1].line);
|
|
239
|
+
|
|
240
|
+
/* We are going to iterate through every error in our error list and display
|
|
241
|
+
* it. While we are iterating, we will display some padding lines of the
|
|
242
|
+
* source before the error to give some context. We will be careful not to
|
|
243
|
+
* display the same line twice in case the errors are close enough in the
|
|
244
|
+
* source. */
|
|
245
|
+
int32_t last_line = parser->start_line - 1;
|
|
246
|
+
uint32_t last_column_start = 0;
|
|
247
|
+
|
|
248
|
+
for (size_t idx = 0; idx < nerrors; idx++) {
|
|
249
|
+
pm_rich_error_t *rich_error = rich_errors + idx;
|
|
250
|
+
|
|
251
|
+
/* Here we determine how many lines of padding of the source to display,
|
|
252
|
+
* based on the difference from the last line that was displayed. */
|
|
253
|
+
if (rich_error->line - last_line > 1) {
|
|
254
|
+
if (rich_error->line - last_line > 2) {
|
|
255
|
+
if ((idx != 0) && (rich_error->line - last_line > 3)) {
|
|
256
|
+
pm_buffer_append_string(buffer, format.divider, format.divider_length);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
pm_buffer_append_string(buffer, " ", 2);
|
|
260
|
+
pm_error_format_line(parser, buffer, format.number_prefix, rich_error->line - 2, 0, 0);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
pm_buffer_append_string(buffer, " ", 2);
|
|
264
|
+
pm_error_format_line(parser, buffer, format.number_prefix, rich_error->line - 1, 0, 0);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/* If this is the first error or we are on a new line, then we will
|
|
268
|
+
* display the line that has the error in it. */
|
|
269
|
+
if ((idx == 0) || (rich_error->line != last_line)) {
|
|
270
|
+
switch (format_type) {
|
|
271
|
+
case PM_ERRORS_FORMAT_PLAIN:
|
|
272
|
+
pm_buffer_append_string(buffer, "> ", 2);
|
|
273
|
+
break;
|
|
274
|
+
case PM_ERRORS_FORMAT_STYLE:
|
|
275
|
+
pm_buffer_append_format(buffer, "%s", COLOR_BOLD "> " COLOR_RESET);
|
|
276
|
+
break;
|
|
277
|
+
case PM_ERRORS_FORMAT_COLOR:
|
|
278
|
+
pm_buffer_append_format(buffer, "%s", COLOR_RED "> " COLOR_RESET);
|
|
279
|
+
break;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
last_column_start = rich_error->column_start;
|
|
283
|
+
|
|
284
|
+
/* Find the maximum column end of all the errors on this line. */
|
|
285
|
+
uint32_t column_end = rich_error->column_end;
|
|
286
|
+
for (size_t next_idx = idx + 1; next_idx < nerrors; next_idx++) {
|
|
287
|
+
if (rich_errors[next_idx].line != rich_error->line) break;
|
|
288
|
+
if (rich_errors[next_idx].column_end > column_end) column_end = rich_errors[next_idx].column_end;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
pm_error_format_line(parser, buffer, format.number_prefix, rich_error->line, rich_error->column_start, column_end);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const uint8_t *start = parser->start + parser->line_offsets.offsets[rich_error->line - parser->start_line];
|
|
295
|
+
if (start == parser->end) pm_buffer_append_byte(buffer, '\n');
|
|
296
|
+
|
|
297
|
+
/* Now we will display the actual error message. We will do this by
|
|
298
|
+
* first putting the prefix to the line, then a bunch of blank spaces
|
|
299
|
+
* depending on the column, then as many tildes as we need to display
|
|
300
|
+
* the width of the error, then the error message itself.
|
|
301
|
+
*
|
|
302
|
+
* Note that this doesn't take into account the width of the actual
|
|
303
|
+
* character when displayed in the terminal. For some east-asian
|
|
304
|
+
* languages or emoji, this means it can be thrown off pretty badly. We
|
|
305
|
+
* will need to solve this eventually. */
|
|
306
|
+
pm_buffer_append_string(buffer, " ", 2);
|
|
307
|
+
pm_buffer_append_string(buffer, format.blank_prefix, format.blank_prefix_length);
|
|
308
|
+
|
|
309
|
+
size_t column = 0;
|
|
310
|
+
if (last_column_start >= TRUNCATE) {
|
|
311
|
+
pm_buffer_append_string(buffer, " ", 4);
|
|
312
|
+
column = last_column_start;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
while (column < rich_error->column_start) {
|
|
316
|
+
pm_buffer_append_byte(buffer, ' ');
|
|
317
|
+
|
|
318
|
+
size_t char_width = pm_parser_encoding_char_width(parser, start + column, parser->end - (start + column));
|
|
319
|
+
column += (char_width == 0 ? 1 : char_width);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
switch (format_type) {
|
|
323
|
+
case PM_ERRORS_FORMAT_PLAIN:
|
|
324
|
+
pm_buffer_append_byte(buffer, '^');
|
|
325
|
+
break;
|
|
326
|
+
case PM_ERRORS_FORMAT_STYLE:
|
|
327
|
+
pm_buffer_append_format(buffer, "%s^", COLOR_BOLD);
|
|
328
|
+
break;
|
|
329
|
+
case PM_ERRORS_FORMAT_COLOR:
|
|
330
|
+
pm_buffer_append_format(buffer, "%s^", COLOR_RED);
|
|
331
|
+
break;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
size_t char_width = pm_parser_encoding_char_width(parser, start + column, parser->end - (start + column));
|
|
335
|
+
column += (char_width == 0 ? 1 : char_width);
|
|
336
|
+
|
|
337
|
+
while (column < rich_error->column_end) {
|
|
338
|
+
pm_buffer_append_byte(buffer, '~');
|
|
339
|
+
|
|
340
|
+
size_t char_width = pm_parser_encoding_char_width(parser, start + column, parser->end - (start + column));
|
|
341
|
+
column += (char_width == 0 ? 1 : char_width);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (format_type != PM_ERRORS_FORMAT_PLAIN) {
|
|
345
|
+
pm_buffer_append_format(buffer, "%s", COLOR_RESET);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (inline_messages) {
|
|
349
|
+
const char *message = pm_diagnostic_message(rich_error->diagnostic);
|
|
350
|
+
|
|
351
|
+
pm_buffer_append_byte(buffer, ' ');
|
|
352
|
+
pm_buffer_append_string(buffer, message, strlen(message));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
pm_buffer_append_byte(buffer, '\n');
|
|
356
|
+
|
|
357
|
+
/* Here we determine how many lines of padding to display after the
|
|
358
|
+
* diagnostic, depending on where the next diagnostic is in source. */
|
|
359
|
+
last_line = rich_error->line;
|
|
360
|
+
int32_t next_line;
|
|
361
|
+
|
|
362
|
+
if (idx == nerrors - 1) {
|
|
363
|
+
next_line = ((int32_t) parser->line_offsets.size) + parser->start_line;
|
|
364
|
+
|
|
365
|
+
/* If the file ends with a newline, subtract one from our
|
|
366
|
+
* "next_line" so that we do not output an extra line at the end of
|
|
367
|
+
* the file. */
|
|
368
|
+
if ((parser->start + parser->line_offsets.offsets[parser->line_offsets.size - 1]) == parser->end) {
|
|
369
|
+
next_line--;
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
next_line = rich_errors[idx + 1].line;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (next_line - last_line > 1) {
|
|
376
|
+
pm_buffer_append_string(buffer, " ", 2);
|
|
377
|
+
pm_error_format_line(parser, buffer, format.number_prefix, ++last_line, 0, 0);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
if (next_line - last_line > 1) {
|
|
381
|
+
pm_buffer_append_string(buffer, " ", 2);
|
|
382
|
+
pm_error_format_line(parser, buffer, format.number_prefix, ++last_line, 0, 0);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
static void
|
|
388
|
+
pm_rich_error_init(const pm_parser_t *parser, pm_rich_error_t *rich_error, pm_diagnostic_t *diagnostic, pm_location_t *location) {
|
|
389
|
+
const pm_line_offset_list_t *line_offsets = &parser->line_offsets;
|
|
390
|
+
pm_line_column_t start_line_column = pm_line_offset_list_line_column(line_offsets, location->start, parser->start_line);
|
|
391
|
+
pm_line_column_t end_line_column = pm_line_offset_list_line_column(line_offsets, location->start + location->length, parser->start_line);
|
|
392
|
+
|
|
393
|
+
uint32_t column_end;
|
|
394
|
+
if (start_line_column.line == end_line_column.line) {
|
|
395
|
+
column_end = end_line_column.column;
|
|
396
|
+
} else {
|
|
397
|
+
column_end = (uint32_t) (line_offsets->offsets[start_line_column.line - parser->start_line + 1] - line_offsets->offsets[start_line_column.line - parser->start_line] - 1);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* Ensure we have at least one column of error. */
|
|
401
|
+
if (start_line_column.column == column_end) column_end++;
|
|
402
|
+
|
|
403
|
+
*rich_error = (pm_rich_error_t) {
|
|
404
|
+
.diagnostic = diagnostic,
|
|
405
|
+
.line = start_line_column.line,
|
|
406
|
+
.column_start = start_line_column.column,
|
|
407
|
+
.column_end = column_end
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
pm_error_level_t
|
|
412
|
+
pm_errors_format(const pm_parser_t *parser, pm_buffer_t *buffer, pm_errors_format_type_t format_type) {
|
|
413
|
+
size_t nerrors = parser->error_list.size;
|
|
414
|
+
assert(nerrors > 0);
|
|
415
|
+
|
|
416
|
+
int filepath_length = (int) pm_string_length(&parser->filepath);
|
|
417
|
+
const char *filepath = (const char *) pm_string_source(&parser->filepath);
|
|
418
|
+
|
|
419
|
+
size_t rich_errors_size = nerrors * sizeof(pm_rich_error_t);
|
|
420
|
+
if (rich_errors_size / sizeof(pm_rich_error_t) != nerrors) abort();
|
|
421
|
+
|
|
422
|
+
pm_rich_error_t *rich_errors = xmalloc(rich_errors_size);
|
|
423
|
+
if (rich_errors == NULL) abort();
|
|
424
|
+
|
|
425
|
+
bool is_utf8 = true;
|
|
426
|
+
size_t rich_errors_idx = 0;
|
|
427
|
+
|
|
428
|
+
for (pm_diagnostic_t *diagnostic = (pm_diagnostic_t *) parser->error_list.head; diagnostic != NULL; diagnostic = (pm_diagnostic_t *) diagnostic->node.next) {
|
|
429
|
+
pm_location_t location = pm_diagnostic_location(diagnostic);
|
|
430
|
+
|
|
431
|
+
switch (pm_diagnostic_error_level(diagnostic)) {
|
|
432
|
+
case PM_ERROR_LEVEL_SYNTAX: {
|
|
433
|
+
if (is_utf8 && !location_is_utf8(parser, &location)) {
|
|
434
|
+
is_utf8 = false;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
pm_rich_error_init(parser, &rich_errors[rich_errors_idx], diagnostic, &location);
|
|
438
|
+
rich_errors[rich_errors_idx].idx = rich_errors_idx;
|
|
439
|
+
rich_errors_idx++;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
case PM_ERROR_LEVEL_ARGUMENT: {
|
|
443
|
+
/* If we get an argument error, we want to format it and return it
|
|
444
|
+
* immediately. They should include a snippet of the source if
|
|
445
|
+
* possible. */
|
|
446
|
+
pm_buffer_append_format(
|
|
447
|
+
buffer,
|
|
448
|
+
"%.*s:%" PRIi32 ": %s",
|
|
449
|
+
filepath_length,
|
|
450
|
+
filepath,
|
|
451
|
+
pm_line_offset_list_line(&parser->line_offsets, location.start, parser->start_line),
|
|
452
|
+
pm_diagnostic_message(diagnostic)
|
|
453
|
+
);
|
|
454
|
+
|
|
455
|
+
if (location_is_utf8(parser, &location)) {
|
|
456
|
+
pm_buffer_append_byte(buffer, '\n');
|
|
457
|
+
pm_rich_error_init(parser, rich_errors, diagnostic, &location);
|
|
458
|
+
pm_rich_errors_format(parser, buffer, format_type, 1, rich_errors, false);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
xfree_sized(rich_errors, rich_errors_size);
|
|
462
|
+
return PM_ERROR_LEVEL_ARGUMENT;
|
|
463
|
+
}
|
|
464
|
+
case PM_ERROR_LEVEL_LOAD: {
|
|
465
|
+
/* If we get a load error, we want to format it and return it
|
|
466
|
+
* immediately. It should only include the diagnostic message. */
|
|
467
|
+
const char *message = pm_diagnostic_message(diagnostic);
|
|
468
|
+
pm_buffer_append_string(buffer, message, strlen(message));
|
|
469
|
+
|
|
470
|
+
xfree_sized(rich_errors, rich_errors_size);
|
|
471
|
+
return PM_ERROR_LEVEL_LOAD;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
assert(rich_errors_idx == nerrors);
|
|
477
|
+
|
|
478
|
+
/* The header displays the line of the first error in parse order, which
|
|
479
|
+
* is the first entry in the array because it has not been sorted yet. */
|
|
480
|
+
pm_buffer_append_format(
|
|
481
|
+
buffer,
|
|
482
|
+
"%.*s:%" PRIi32 ": syntax error%s found\n",
|
|
483
|
+
filepath_length,
|
|
484
|
+
filepath,
|
|
485
|
+
rich_errors[0].line,
|
|
486
|
+
(nerrors > 1) ? "s" : ""
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
if (is_utf8) {
|
|
490
|
+
/* In here, we have all of the rich diagnostic information and we know
|
|
491
|
+
* the snippets are valid UTF-8. We will sort the errors so that they
|
|
492
|
+
* are displayed in the order that they appear in the source, and then
|
|
493
|
+
* format them all together with the source code snippets. */
|
|
494
|
+
qsort(rich_errors, nerrors, sizeof(pm_rich_error_t), pm_rich_error_compare);
|
|
495
|
+
pm_rich_errors_format(parser, buffer, format_type, nerrors, rich_errors, true);
|
|
496
|
+
} else {
|
|
497
|
+
/* In here, we have content in the source that is not valid UTF-8. In
|
|
498
|
+
* that case, we do not want to attempt to format the source code
|
|
499
|
+
* snippets because we do not know how the terminal will handle it. The
|
|
500
|
+
* diagnostics are displayed in the order that they were generated,
|
|
501
|
+
* which is the order of the array before it has been sorted. */
|
|
502
|
+
for (size_t idx = 0; idx < nerrors; idx++) {
|
|
503
|
+
pm_rich_error_t *rich_error = &rich_errors[idx];
|
|
504
|
+
|
|
505
|
+
if (idx > 0) pm_buffer_append_byte(buffer, '\n');
|
|
506
|
+
pm_buffer_append_format(
|
|
507
|
+
buffer,
|
|
508
|
+
"%.*s:%" PRIi32 ": %s",
|
|
509
|
+
filepath_length,
|
|
510
|
+
filepath,
|
|
511
|
+
rich_error->line,
|
|
512
|
+
pm_diagnostic_message(rich_error->diagnostic)
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
xfree_sized(rich_errors, rich_errors_size);
|
|
518
|
+
return PM_ERROR_LEVEL_SYNTAX;
|
|
519
|
+
}
|
|
@@ -1,4 +1,25 @@
|
|
|
1
|
-
#include "prism/
|
|
1
|
+
#include "prism/internal/integer.h"
|
|
2
|
+
|
|
3
|
+
#include "prism/internal/allocator.h"
|
|
4
|
+
#include "prism/internal/buffer.h"
|
|
5
|
+
|
|
6
|
+
#include <assert.h>
|
|
7
|
+
#include <inttypes.h>
|
|
8
|
+
#include <stdbool.h>
|
|
9
|
+
#include <stddef.h>
|
|
10
|
+
#include <stdlib.h>
|
|
11
|
+
#include <string.h>
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Free the internal memory of an integer. This memory will only be allocated if
|
|
15
|
+
* the integer exceeds the size of a single uint32_t.
|
|
16
|
+
*/
|
|
17
|
+
static void
|
|
18
|
+
pm_integer_free(pm_integer_t *integer) {
|
|
19
|
+
if (integer->values) {
|
|
20
|
+
xfree(integer->values);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
2
23
|
|
|
3
24
|
/**
|
|
4
25
|
* Pull out the length and values from the integer, regardless of the form in
|
|
@@ -374,7 +395,7 @@ pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, u
|
|
|
374
395
|
}
|
|
375
396
|
}
|
|
376
397
|
|
|
377
|
-
|
|
398
|
+
xfree_sized(bigints, bigints_length * sizeof(pm_integer_t));
|
|
378
399
|
bigints = next_bigints;
|
|
379
400
|
bigints_length = next_length;
|
|
380
401
|
}
|
|
@@ -383,7 +404,7 @@ pm_integer_convert_base(pm_integer_t *destination, const pm_integer_t *source, u
|
|
|
383
404
|
destination->negative = source->negative;
|
|
384
405
|
pm_integer_normalize(destination);
|
|
385
406
|
|
|
386
|
-
|
|
407
|
+
xfree_sized(bigints, bigints_length * sizeof(pm_integer_t));
|
|
387
408
|
pm_integer_free(&base);
|
|
388
409
|
}
|
|
389
410
|
|
|
@@ -422,7 +443,7 @@ pm_integer_parse_powof2(pm_integer_t *integer, uint32_t base, const uint8_t *dig
|
|
|
422
443
|
static void
|
|
423
444
|
pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t digits_length) {
|
|
424
445
|
const size_t batch = 9;
|
|
425
|
-
size_t length = (digits_length + batch - 1) / batch;
|
|
446
|
+
const size_t length = (digits_length + batch - 1) / batch;
|
|
426
447
|
|
|
427
448
|
uint32_t *values = (uint32_t *) xcalloc(length, sizeof(uint32_t));
|
|
428
449
|
uint32_t value = 0;
|
|
@@ -439,7 +460,7 @@ pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t di
|
|
|
439
460
|
|
|
440
461
|
// Convert base from 10**9 to 1<<32.
|
|
441
462
|
pm_integer_convert_base(integer, &((pm_integer_t) { .length = length, .values = values, .value = 0, .negative = false }), 1000000000, ((uint64_t) 1 << 32));
|
|
442
|
-
|
|
463
|
+
xfree_sized(values, length * sizeof(uint32_t));
|
|
443
464
|
}
|
|
444
465
|
|
|
445
466
|
/**
|
|
@@ -448,7 +469,8 @@ pm_integer_parse_decimal(pm_integer_t *integer, const uint8_t *digits, size_t di
|
|
|
448
469
|
static void
|
|
449
470
|
pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *start, const uint8_t *end) {
|
|
450
471
|
// Allocate an array to store digits.
|
|
451
|
-
|
|
472
|
+
const size_t digits_capa = sizeof(uint8_t) * (size_t) (end - start);
|
|
473
|
+
uint8_t *digits = xmalloc(digits_capa);
|
|
452
474
|
size_t digits_length = 0;
|
|
453
475
|
|
|
454
476
|
for (; start < end; start++) {
|
|
@@ -463,7 +485,7 @@ pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *
|
|
|
463
485
|
pm_integer_parse_powof2(integer, multiplier, digits, digits_length);
|
|
464
486
|
}
|
|
465
487
|
|
|
466
|
-
|
|
488
|
+
xfree_sized(digits, digits_capa);
|
|
467
489
|
}
|
|
468
490
|
|
|
469
491
|
/**
|
|
@@ -481,7 +503,7 @@ pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *s
|
|
|
481
503
|
uint32_t multiplier = 10;
|
|
482
504
|
switch (base) {
|
|
483
505
|
case PM_INTEGER_BASE_DEFAULT:
|
|
484
|
-
while (*start == '0') start++; // 01 -> 1
|
|
506
|
+
while (start < end && *start == '0') start++; // 01 -> 1
|
|
485
507
|
break;
|
|
486
508
|
case PM_INTEGER_BASE_BINARY:
|
|
487
509
|
start += 2; // 0b
|
|
@@ -603,7 +625,7 @@ void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator) {
|
|
|
603
625
|
/**
|
|
604
626
|
* Convert an integer to a decimal string.
|
|
605
627
|
*/
|
|
606
|
-
|
|
628
|
+
void
|
|
607
629
|
pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) {
|
|
608
630
|
if (integer->negative) {
|
|
609
631
|
pm_buffer_append_byte(buffer, '-');
|
|
@@ -635,7 +657,7 @@ pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) {
|
|
|
635
657
|
}
|
|
636
658
|
|
|
637
659
|
// Allocate a buffer that we'll copy the decimal digits into.
|
|
638
|
-
size_t digits_length = converted.length * 9;
|
|
660
|
+
const size_t digits_length = converted.length * 9;
|
|
639
661
|
char *digits = xcalloc(digits_length, sizeof(char));
|
|
640
662
|
if (digits == NULL) return;
|
|
641
663
|
|
|
@@ -654,17 +676,6 @@ pm_integer_string(pm_buffer_t *buffer, const pm_integer_t *integer) {
|
|
|
654
676
|
|
|
655
677
|
// Finally, append the string to the buffer and free the digits.
|
|
656
678
|
pm_buffer_append_string(buffer, digits + start_offset, digits_length - start_offset);
|
|
657
|
-
|
|
679
|
+
xfree_sized(digits, sizeof(char) * digits_length);
|
|
658
680
|
pm_integer_free(&converted);
|
|
659
681
|
}
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Free the internal memory of an integer. This memory will only be allocated if
|
|
663
|
-
* the integer exceeds the size of a single uint32_t.
|
|
664
|
-
*/
|
|
665
|
-
PRISM_EXPORTED_FUNCTION void
|
|
666
|
-
pm_integer_free(pm_integer_t *integer) {
|
|
667
|
-
if (integer->values) {
|
|
668
|
-
xfree(integer->values);
|
|
669
|
-
}
|
|
670
|
-
}
|