prism 0.17.1 → 0.19.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +60 -1
- data/Makefile +5 -5
- data/README.md +4 -3
- data/config.yml +214 -68
- data/docs/build_system.md +6 -6
- data/docs/building.md +10 -3
- data/docs/configuration.md +11 -9
- data/docs/encoding.md +92 -88
- data/docs/heredocs.md +1 -1
- data/docs/javascript.md +29 -1
- data/docs/local_variable_depth.md +229 -0
- data/docs/ruby_api.md +16 -0
- data/docs/serialization.md +18 -13
- data/ext/prism/api_node.c +411 -240
- data/ext/prism/extconf.rb +97 -127
- data/ext/prism/extension.c +97 -33
- data/ext/prism/extension.h +1 -1
- data/include/prism/ast.h +377 -159
- data/include/prism/defines.h +17 -0
- data/include/prism/diagnostic.h +38 -6
- data/include/prism/{enc/pm_encoding.h → encoding.h} +126 -64
- data/include/prism/options.h +2 -2
- data/include/prism/parser.h +62 -36
- data/include/prism/regexp.h +2 -2
- data/include/prism/util/pm_buffer.h +9 -1
- data/include/prism/util/pm_memchr.h +2 -2
- data/include/prism/util/pm_strpbrk.h +3 -3
- data/include/prism/version.h +3 -3
- data/include/prism.h +13 -15
- data/lib/prism/compiler.rb +15 -3
- data/lib/prism/debug.rb +13 -4
- data/lib/prism/desugar_compiler.rb +4 -3
- data/lib/prism/dispatcher.rb +70 -14
- data/lib/prism/dot_visitor.rb +4612 -0
- data/lib/prism/dsl.rb +77 -57
- data/lib/prism/ffi.rb +19 -6
- data/lib/prism/lex_compat.rb +19 -9
- data/lib/prism/mutation_compiler.rb +26 -6
- data/lib/prism/node.rb +1314 -522
- data/lib/prism/node_ext.rb +102 -19
- data/lib/prism/parse_result.rb +58 -27
- data/lib/prism/ripper_compat.rb +49 -34
- data/lib/prism/serialize.rb +251 -227
- data/lib/prism/visitor.rb +15 -3
- data/lib/prism.rb +21 -4
- data/prism.gemspec +7 -9
- data/rbi/prism.rbi +688 -284
- data/rbi/prism_static.rbi +3 -0
- data/sig/prism.rbs +426 -156
- data/sig/prism_static.rbs +1 -0
- data/src/diagnostic.c +280 -216
- data/src/encoding.c +5137 -0
- data/src/node.c +99 -21
- data/src/options.c +21 -2
- data/src/prettyprint.c +1743 -1241
- data/src/prism.c +1774 -831
- data/src/regexp.c +15 -15
- data/src/serialize.c +261 -164
- data/src/util/pm_buffer.c +10 -1
- data/src/util/pm_memchr.c +1 -1
- data/src/util/pm_strpbrk.c +4 -4
- metadata +8 -10
- data/src/enc/pm_big5.c +0 -53
- data/src/enc/pm_euc_jp.c +0 -59
- data/src/enc/pm_gbk.c +0 -62
- data/src/enc/pm_shift_jis.c +0 -57
- data/src/enc/pm_tables.c +0 -743
- data/src/enc/pm_unicode.c +0 -2369
- data/src/enc/pm_windows_31j.c +0 -57
data/ext/prism/extconf.rb
CHANGED
@@ -1,136 +1,106 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
if ARGV.delete("--help")
|
4
|
+
print(<<~TEXT)
|
5
|
+
USAGE: ruby #{$PROGRAM_NAME} [options]
|
6
|
+
|
7
|
+
Flags that are always valid:
|
8
|
+
|
9
|
+
--enable-debug-mode-build
|
10
|
+
Enable debug mode build.
|
11
|
+
You may also use set PRISM_DEBUG_MODE_BUILD environment variable.
|
12
|
+
|
13
|
+
--help
|
14
|
+
Display this message.
|
15
|
+
|
16
|
+
Environment variables used:
|
17
|
+
|
18
|
+
PRISM_DEBUG_MODE_BUILD
|
19
|
+
Equivalent to `--enable-debug-mode-build` when set, even if nil or blank.
|
4
20
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
require "mkmf"
|
19
|
-
configure_c_extension
|
20
|
-
configure_rubyparser
|
21
|
-
|
22
|
-
create_makefile("prism/prism")
|
23
|
-
|
24
|
-
if static_link?
|
25
|
-
File.open('Makefile', 'a') do |mf|
|
26
|
-
mf.puts
|
27
|
-
mf.puts '# Automatically rebuild the extension if librubyparser.a changed'
|
28
|
-
mf.puts '$(TARGET_SO): $(LOCAL_LIBS)'
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def configure_c_extension
|
34
|
-
append_cflags("-DPRISM_DEBUG_MODE_BUILD") if debug_mode_build?
|
35
|
-
append_cflags("-fvisibility=hidden")
|
36
|
-
end
|
37
|
-
|
38
|
-
def configure_rubyparser
|
39
|
-
if static_link?
|
40
|
-
static_archive_path = File.join(build_dir, "librubyparser.a")
|
41
|
-
unless File.exist?(static_archive_path)
|
42
|
-
build_static_rubyparser
|
43
|
-
end
|
44
|
-
$LOCAL_LIBS << " #{static_archive_path}"
|
45
|
-
else
|
46
|
-
shared_library_path = File.join(build_dir, "librubyparser.#{RbConfig::CONFIG["SOEXT"]}")
|
47
|
-
unless File.exist?(shared_library_path)
|
48
|
-
build_shared_rubyparser
|
49
|
-
end
|
50
|
-
unless find_library("rubyparser", "pm_parser_init", build_dir)
|
51
|
-
raise "could not link against #{File.basename(shared_library_path)}"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
find_header("prism.h", include_dir) or raise "prism.h is required"
|
56
|
-
|
57
|
-
# Explicitly look for the extension header in the parent directory
|
58
|
-
# because we want to consistently look for prism/extension.h in our
|
59
|
-
# source files to line up with our mirroring in CRuby.
|
60
|
-
find_header("prism/extension.h", File.join(__dir__, "..")) or raise "prism/extension.h is required"
|
61
|
-
end
|
62
|
-
|
63
|
-
def build_shared_rubyparser
|
64
|
-
build_target_rubyparser "build/librubyparser.#{RbConfig::CONFIG["SOEXT"]}"
|
65
|
-
end
|
66
|
-
|
67
|
-
def build_static_rubyparser
|
68
|
-
build_target_rubyparser "build/librubyparser.a"
|
69
|
-
end
|
70
|
-
|
71
|
-
def build_target_rubyparser(target)
|
72
|
-
Dir.chdir(root_dir) do
|
73
|
-
if !File.exist?("include/prism/ast.h") && Dir.exist?(".git")
|
74
|
-
# this block only exists to support building the gem from a "git" source,
|
75
|
-
# normally we package up the configure and other files in the gem itself
|
76
|
-
system("templates/template.rb", exception: true)
|
77
|
-
end
|
78
|
-
system("make", target, exception: true)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def root_dir
|
83
|
-
File.expand_path("../..", __dir__)
|
84
|
-
end
|
85
|
-
|
86
|
-
def include_dir
|
87
|
-
File.join(root_dir, "include")
|
88
|
-
end
|
89
|
-
|
90
|
-
def build_dir
|
91
|
-
File.join(root_dir, "build")
|
92
|
-
end
|
93
|
-
|
94
|
-
def print_help
|
95
|
-
print(<<~TEXT)
|
96
|
-
USAGE: ruby #{$PROGRAM_NAME} [options]
|
97
|
-
|
98
|
-
Flags that are always valid:
|
99
|
-
|
100
|
-
--enable-static
|
101
|
-
--disable-static
|
102
|
-
Enable or disable static linking against librubyparser.
|
103
|
-
The default is to statically link.
|
104
|
-
|
105
|
-
--enable-debug-mode-build
|
106
|
-
Enable debug mode build.
|
107
|
-
You may also use set PRISM_DEBUG_MODE_BUILD environment variable.
|
108
|
-
|
109
|
-
--help
|
110
|
-
Display this message.
|
111
|
-
|
112
|
-
Environment variables used:
|
113
|
-
|
114
|
-
PRISM_DEBUG_MODE_BUILD
|
115
|
-
Equivalent to `--enable-debug-mode-build` when set, even if nil or blank.
|
116
|
-
|
117
|
-
TEXT
|
118
|
-
end
|
119
|
-
|
120
|
-
def static_link?
|
121
|
-
enable_config("static", true)
|
122
|
-
end
|
123
|
-
|
124
|
-
def debug_mode_build?
|
125
|
-
enable_config("debug-mode-build", ENV["PRISM_DEBUG_MODE_BUILD"] || false)
|
126
|
-
end
|
21
|
+
TEXT
|
22
|
+
exit!(0)
|
23
|
+
end
|
24
|
+
|
25
|
+
# If this gem is being build from a git source, then we need to run
|
26
|
+
# templating if it hasn't been run yet. In normal packaging, we would have
|
27
|
+
# shipped the templated files with the gem, so this wouldn't be necessary.
|
28
|
+
def generate_templates
|
29
|
+
Dir.chdir(File.expand_path("../..", __dir__)) do
|
30
|
+
if !File.exist?("include/prism/ast.h") && Dir.exist?(".git")
|
31
|
+
system("templates/template.rb", exception: true)
|
127
32
|
end
|
128
33
|
end
|
129
34
|
end
|
130
35
|
|
131
|
-
|
132
|
-
|
133
|
-
|
36
|
+
# Runs `make` in the root directory of the project. Note that this is the
|
37
|
+
# `Makefile` for the overall project, not the `Makefile` that is being generated
|
38
|
+
# by this script.`
|
39
|
+
def make(target)
|
40
|
+
Dir.chdir(File.expand_path("../..", __dir__)) do
|
41
|
+
system("make", target, exception: true)
|
42
|
+
end
|
134
43
|
end
|
135
44
|
|
136
|
-
|
45
|
+
require "rbconfig"
|
46
|
+
|
47
|
+
# On non-CRuby we only need the shared library since we'll interface with it
|
48
|
+
# through FFI, so we'll build only that and not the C extension. We also avoid
|
49
|
+
# `require "mkmf"` as that prepends the LLVM toolchain to PATH on TruffleRuby,
|
50
|
+
# but we want to use the native toolchain here since libprism is run natively.
|
51
|
+
if RUBY_ENGINE != "ruby"
|
52
|
+
generate_templates
|
53
|
+
make("build/libprism.#{RbConfig::CONFIG["SOEXT"]}")
|
54
|
+
File.write("Makefile", "all install clean:\n\t@#{RbConfig::CONFIG["NULLCMD"]}\n")
|
55
|
+
return
|
56
|
+
end
|
57
|
+
|
58
|
+
require "mkmf"
|
59
|
+
|
60
|
+
# First, ensure that we can find the header for the prism library.
|
61
|
+
generate_templates # Templates should be generated before find_header.
|
62
|
+
unless find_header("prism.h", File.expand_path("../../include", __dir__))
|
63
|
+
raise "prism.h is required"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Next, ensure we can find the header for the C extension. Explicitly look for
|
67
|
+
# the extension header in the parent directory because we want to consistently
|
68
|
+
# look for `prism/extension.h` in our source files to line up with our mirroring
|
69
|
+
# in CRuby.
|
70
|
+
unless find_header("prism/extension.h", File.expand_path("..", __dir__))
|
71
|
+
raise "prism/extension.h is required"
|
72
|
+
end
|
73
|
+
|
74
|
+
# If `--enable-debug-mode-build` is passed to this script or the
|
75
|
+
# `PRISM_DEBUG_MODE_BUILD` environment variable is defined, we'll build with the
|
76
|
+
# `PRISM_DEBUG_MODE_BUILD` macro defined. This causes parse functions to
|
77
|
+
# duplicate their input so that they have clearly set bounds, which is useful
|
78
|
+
# for finding bugs that cause the parser to read off the end of the input.
|
79
|
+
if enable_config("debug-mode-build", ENV["PRISM_DEBUG_MODE_BUILD"] || false)
|
80
|
+
append_cflags("-DPRISM_DEBUG_MODE_BUILD")
|
81
|
+
end
|
82
|
+
|
83
|
+
# By default, all symbols are hidden in the shared library.
|
84
|
+
append_cflags("-fvisibility=hidden")
|
85
|
+
|
86
|
+
# We need to link against the libprism.a archive, which is built by the
|
87
|
+
# project's `Makefile`. We'll build it if it doesn't exist yet, and then add it
|
88
|
+
# to `mkmf`'s list of local libraries.
|
89
|
+
archive_target = "build/libprism.a"
|
90
|
+
archive_path = File.expand_path("../../#{archive_target}", __dir__)
|
91
|
+
|
92
|
+
make(archive_target) unless File.exist?(archive_path)
|
93
|
+
$LOCAL_LIBS << " #{archive_path}"
|
94
|
+
|
95
|
+
# Finally, we'll create the `Makefile` that is going to be used to configure and
|
96
|
+
# build the C extension.
|
97
|
+
create_makefile("prism/prism")
|
98
|
+
|
99
|
+
# Now that the `Makefile` for the C extension is built, we'll append on an extra
|
100
|
+
# rule that dictates that the extension should be rebuilt if the archive is
|
101
|
+
# updated.
|
102
|
+
File.open("Makefile", "a") do |mf|
|
103
|
+
mf.puts
|
104
|
+
mf.puts("# Automatically rebuild the extension if libprism.a changed")
|
105
|
+
mf.puts("$(TARGET_SO): $(LOCAL_LIBS)")
|
106
|
+
end
|
data/ext/prism/extension.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#include "prism/extension.h"
|
2
2
|
|
3
3
|
// NOTE: this file should contain only bindings. All non-trivial logic should be
|
4
|
-
// in
|
4
|
+
// in libprism so it can be shared its the various callers.
|
5
5
|
|
6
6
|
VALUE rb_cPrism;
|
7
7
|
VALUE rb_cPrismNode;
|
@@ -12,7 +12,6 @@ VALUE rb_cPrismLocation;
|
|
12
12
|
VALUE rb_cPrismComment;
|
13
13
|
VALUE rb_cPrismInlineComment;
|
14
14
|
VALUE rb_cPrismEmbDocComment;
|
15
|
-
VALUE rb_cPrismDATAComment;
|
16
15
|
VALUE rb_cPrismMagicComment;
|
17
16
|
VALUE rb_cPrismParseError;
|
18
17
|
VALUE rb_cPrismParseWarning;
|
@@ -127,7 +126,7 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
|
|
127
126
|
} else if (key_id == rb_option_id_encoding) {
|
128
127
|
if (!NIL_P(value)) pm_options_encoding_set(options, rb_enc_name(rb_to_encoding(value)));
|
129
128
|
} else if (key_id == rb_option_id_line) {
|
130
|
-
if (!NIL_P(value)) pm_options_line_set(options,
|
129
|
+
if (!NIL_P(value)) pm_options_line_set(options, NUM2INT(value));
|
131
130
|
} else if (key_id == rb_option_id_frozen_string_literal) {
|
132
131
|
if (!NIL_P(value)) pm_options_frozen_string_literal_set(options, value == Qtrue);
|
133
132
|
} else if (key_id == rb_option_id_verbose) {
|
@@ -167,6 +166,7 @@ build_options(VALUE argument) {
|
|
167
166
|
*/
|
168
167
|
static void
|
169
168
|
extract_options(pm_options_t *options, VALUE filepath, VALUE keywords) {
|
169
|
+
options->line = 1; // default
|
170
170
|
if (!NIL_P(keywords)) {
|
171
171
|
struct build_options_data data = { .options = options, .keywords = keywords };
|
172
172
|
struct build_options_data *argument = &data;
|
@@ -316,26 +316,11 @@ parser_comments(pm_parser_t *parser, VALUE source) {
|
|
316
316
|
for (pm_comment_t *comment = (pm_comment_t *) parser->comment_list.head; comment != NULL; comment = (pm_comment_t *) comment->node.next) {
|
317
317
|
VALUE location_argv[] = {
|
318
318
|
source,
|
319
|
-
LONG2FIX(comment->start - parser->start),
|
320
|
-
LONG2FIX(comment->end - comment->start)
|
319
|
+
LONG2FIX(comment->location.start - parser->start),
|
320
|
+
LONG2FIX(comment->location.end - comment->location.start)
|
321
321
|
};
|
322
322
|
|
323
|
-
VALUE type;
|
324
|
-
switch (comment->type) {
|
325
|
-
case PM_COMMENT_INLINE:
|
326
|
-
type = rb_cPrismInlineComment;
|
327
|
-
break;
|
328
|
-
case PM_COMMENT_EMBDOC:
|
329
|
-
type = rb_cPrismEmbDocComment;
|
330
|
-
break;
|
331
|
-
case PM_COMMENT___END__:
|
332
|
-
type = rb_cPrismDATAComment;
|
333
|
-
break;
|
334
|
-
default:
|
335
|
-
type = rb_cPrismInlineComment;
|
336
|
-
break;
|
337
|
-
}
|
338
|
-
|
323
|
+
VALUE type = (comment->type == PM_COMMENT_EMBDOC) ? rb_cPrismEmbDocComment : rb_cPrismInlineComment;
|
339
324
|
VALUE comment_argv[] = { rb_class_new_instance(3, location_argv, rb_cPrismLocation) };
|
340
325
|
rb_ary_push(comments, rb_class_new_instance(1, comment_argv, type));
|
341
326
|
}
|
@@ -374,6 +359,25 @@ parser_magic_comments(pm_parser_t *parser, VALUE source) {
|
|
374
359
|
return magic_comments;
|
375
360
|
}
|
376
361
|
|
362
|
+
/**
|
363
|
+
* Extract out the data location from the parser into a Location instance if one
|
364
|
+
* exists.
|
365
|
+
*/
|
366
|
+
static VALUE
|
367
|
+
parser_data_loc(const pm_parser_t *parser, VALUE source) {
|
368
|
+
if (parser->data_loc.end == NULL) {
|
369
|
+
return Qnil;
|
370
|
+
} else {
|
371
|
+
VALUE argv[] = {
|
372
|
+
source,
|
373
|
+
LONG2FIX(parser->data_loc.start - parser->start),
|
374
|
+
LONG2FIX(parser->data_loc.end - parser->data_loc.start)
|
375
|
+
};
|
376
|
+
|
377
|
+
return rb_class_new_instance(3, argv, rb_cPrismLocation);
|
378
|
+
}
|
379
|
+
}
|
380
|
+
|
377
381
|
/**
|
378
382
|
* Extract the errors out of the parser into an array.
|
379
383
|
*/
|
@@ -385,8 +389,8 @@ parser_errors(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
|
385
389
|
for (error = (pm_diagnostic_t *) parser->error_list.head; error != NULL; error = (pm_diagnostic_t *) error->node.next) {
|
386
390
|
VALUE location_argv[] = {
|
387
391
|
source,
|
388
|
-
LONG2FIX(error->start - parser->start),
|
389
|
-
LONG2FIX(error->end - error->start)
|
392
|
+
LONG2FIX(error->location.start - parser->start),
|
393
|
+
LONG2FIX(error->location.end - error->location.start)
|
390
394
|
};
|
391
395
|
|
392
396
|
VALUE error_argv[] = {
|
@@ -411,8 +415,8 @@ parser_warnings(pm_parser_t *parser, rb_encoding *encoding, VALUE source) {
|
|
411
415
|
for (warning = (pm_diagnostic_t *) parser->warning_list.head; warning != NULL; warning = (pm_diagnostic_t *) warning->node.next) {
|
412
416
|
VALUE location_argv[] = {
|
413
417
|
source,
|
414
|
-
LONG2FIX(warning->start - parser->start),
|
415
|
-
LONG2FIX(warning->end - warning->start)
|
418
|
+
LONG2FIX(warning->location.start - parser->start),
|
419
|
+
LONG2FIX(warning->location.end - warning->location.start)
|
416
420
|
};
|
417
421
|
|
418
422
|
VALUE warning_argv[] = {
|
@@ -465,7 +469,7 @@ parse_lex_token(void *data, pm_parser_t *parser, pm_token_t *token) {
|
|
465
469
|
static void
|
466
470
|
parse_lex_encoding_changed_callback(pm_parser_t *parser) {
|
467
471
|
parse_lex_data_t *parse_lex_data = (parse_lex_data_t *) parser->lex_callback->data;
|
468
|
-
parse_lex_data->encoding = rb_enc_find(parser->encoding
|
472
|
+
parse_lex_data->encoding = rb_enc_find(parser->encoding->name);
|
469
473
|
|
470
474
|
// Since the encoding changed, we need to go back and change the encoding of
|
471
475
|
// the tokens that were already lexed. This is only going to end up being
|
@@ -531,6 +535,7 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
|
|
531
535
|
value,
|
532
536
|
parser_comments(&parser, source),
|
533
537
|
parser_magic_comments(&parser, source),
|
538
|
+
parser_data_loc(&parser, source),
|
534
539
|
parser_errors(&parser, parse_lex_data.encoding, source),
|
535
540
|
parser_warnings(&parser, parse_lex_data.encoding, source),
|
536
541
|
source
|
@@ -538,7 +543,7 @@ parse_lex_input(pm_string_t *input, const pm_options_t *options, bool return_nod
|
|
538
543
|
|
539
544
|
pm_node_destroy(&parser, node);
|
540
545
|
pm_parser_free(&parser);
|
541
|
-
return rb_class_new_instance(
|
546
|
+
return rb_class_new_instance(7, result_argv, rb_cPrismParseResult);
|
542
547
|
}
|
543
548
|
|
544
549
|
/**
|
@@ -594,19 +599,20 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
|
|
594
599
|
pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
|
595
600
|
|
596
601
|
pm_node_t *node = pm_parse(&parser);
|
597
|
-
rb_encoding *encoding = rb_enc_find(parser.encoding
|
602
|
+
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
598
603
|
|
599
604
|
VALUE source = pm_source_new(&parser, encoding);
|
600
605
|
VALUE result_argv[] = {
|
601
606
|
pm_ast_new(&parser, node, encoding),
|
602
607
|
parser_comments(&parser, source),
|
603
608
|
parser_magic_comments(&parser, source),
|
609
|
+
parser_data_loc(&parser, source),
|
604
610
|
parser_errors(&parser, encoding, source),
|
605
611
|
parser_warnings(&parser, encoding, source),
|
606
612
|
source
|
607
613
|
};
|
608
614
|
|
609
|
-
VALUE result = rb_class_new_instance(
|
615
|
+
VALUE result = rb_class_new_instance(7, result_argv, rb_cPrismParseResult);
|
610
616
|
|
611
617
|
pm_node_destroy(&parser, node);
|
612
618
|
pm_parser_free(&parser);
|
@@ -687,7 +693,7 @@ parse_input_comments(pm_string_t *input, const pm_options_t *options) {
|
|
687
693
|
pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
|
688
694
|
|
689
695
|
pm_node_t *node = pm_parse(&parser);
|
690
|
-
rb_encoding *encoding = rb_enc_find(parser.encoding
|
696
|
+
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
691
697
|
|
692
698
|
VALUE source = pm_source_new(&parser, encoding);
|
693
699
|
VALUE comments = parser_comments(&parser, source);
|
@@ -792,6 +798,63 @@ parse_lex_file(int argc, VALUE *argv, VALUE self) {
|
|
792
798
|
return value;
|
793
799
|
}
|
794
800
|
|
801
|
+
/**
|
802
|
+
* Parse the given input and return true if it parses without errors.
|
803
|
+
*/
|
804
|
+
static VALUE
|
805
|
+
parse_input_success_p(pm_string_t *input, const pm_options_t *options) {
|
806
|
+
pm_parser_t parser;
|
807
|
+
pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
|
808
|
+
|
809
|
+
pm_node_t *node = pm_parse(&parser);
|
810
|
+
pm_node_destroy(&parser, node);
|
811
|
+
|
812
|
+
VALUE result = parser.error_list.size == 0 ? Qtrue : Qfalse;
|
813
|
+
pm_parser_free(&parser);
|
814
|
+
|
815
|
+
return result;
|
816
|
+
}
|
817
|
+
|
818
|
+
/**
|
819
|
+
* call-seq:
|
820
|
+
* Prism::parse_success?(source, **options) -> Array
|
821
|
+
*
|
822
|
+
* Parse the given string and return true if it parses without errors. For
|
823
|
+
* supported options, see Prism::parse.
|
824
|
+
*/
|
825
|
+
static VALUE
|
826
|
+
parse_success_p(int argc, VALUE *argv, VALUE self) {
|
827
|
+
pm_string_t input;
|
828
|
+
pm_options_t options = { 0 };
|
829
|
+
string_options(argc, argv, &input, &options);
|
830
|
+
|
831
|
+
VALUE result = parse_input_success_p(&input, &options);
|
832
|
+
pm_string_free(&input);
|
833
|
+
pm_options_free(&options);
|
834
|
+
|
835
|
+
return result;
|
836
|
+
}
|
837
|
+
|
838
|
+
/**
|
839
|
+
* call-seq:
|
840
|
+
* Prism::parse_file_success?(filepath, **options) -> Array
|
841
|
+
*
|
842
|
+
* Parse the given file and return true if it parses without errors. For
|
843
|
+
* supported options, see Prism::parse.
|
844
|
+
*/
|
845
|
+
static VALUE
|
846
|
+
parse_file_success_p(int argc, VALUE *argv, VALUE self) {
|
847
|
+
pm_string_t input;
|
848
|
+
pm_options_t options = { 0 };
|
849
|
+
if (!file_options(argc, argv, &input, &options)) return Qnil;
|
850
|
+
|
851
|
+
VALUE result = parse_input_success_p(&input, &options);
|
852
|
+
pm_string_free(&input);
|
853
|
+
pm_options_free(&options);
|
854
|
+
|
855
|
+
return result;
|
856
|
+
}
|
857
|
+
|
795
858
|
/******************************************************************************/
|
796
859
|
/* Utility functions exposed to make testing easier */
|
797
860
|
/******************************************************************************/
|
@@ -808,7 +871,7 @@ static VALUE
|
|
808
871
|
named_captures(VALUE self, VALUE source) {
|
809
872
|
pm_string_list_t string_list = { 0 };
|
810
873
|
|
811
|
-
if (!pm_regexp_named_capture_group_names((const uint8_t *) RSTRING_PTR(source), RSTRING_LEN(source), &string_list, false,
|
874
|
+
if (!pm_regexp_named_capture_group_names((const uint8_t *) RSTRING_PTR(source), RSTRING_LEN(source), &string_list, false, PM_ENCODING_UTF_8_ENTRY)) {
|
812
875
|
pm_string_list_free(&string_list);
|
813
876
|
return Qnil;
|
814
877
|
}
|
@@ -898,7 +961,7 @@ inspect_node(VALUE self, VALUE source) {
|
|
898
961
|
|
899
962
|
pm_prettyprint(&buffer, &parser, node);
|
900
963
|
|
901
|
-
rb_encoding *encoding = rb_enc_find(parser.encoding
|
964
|
+
rb_encoding *encoding = rb_enc_find(parser.encoding->name);
|
902
965
|
VALUE string = rb_enc_str_new(pm_buffer_value(&buffer), pm_buffer_length(&buffer), encoding);
|
903
966
|
|
904
967
|
pm_buffer_free(&buffer);
|
@@ -938,7 +1001,6 @@ Init_prism(void) {
|
|
938
1001
|
rb_cPrismComment = rb_define_class_under(rb_cPrism, "Comment", rb_cObject);
|
939
1002
|
rb_cPrismInlineComment = rb_define_class_under(rb_cPrism, "InlineComment", rb_cPrismComment);
|
940
1003
|
rb_cPrismEmbDocComment = rb_define_class_under(rb_cPrism, "EmbDocComment", rb_cPrismComment);
|
941
|
-
rb_cPrismDATAComment = rb_define_class_under(rb_cPrism, "DATAComment", rb_cPrismComment);
|
942
1004
|
rb_cPrismMagicComment = rb_define_class_under(rb_cPrism, "MagicComment", rb_cObject);
|
943
1005
|
rb_cPrismParseError = rb_define_class_under(rb_cPrism, "ParseError", rb_cObject);
|
944
1006
|
rb_cPrismParseWarning = rb_define_class_under(rb_cPrism, "ParseWarning", rb_cObject);
|
@@ -976,6 +1038,8 @@ Init_prism(void) {
|
|
976
1038
|
rb_define_singleton_method(rb_cPrism, "parse_file_comments", parse_file_comments, -1);
|
977
1039
|
rb_define_singleton_method(rb_cPrism, "parse_lex", parse_lex, -1);
|
978
1040
|
rb_define_singleton_method(rb_cPrism, "parse_lex_file", parse_lex_file, -1);
|
1041
|
+
rb_define_singleton_method(rb_cPrism, "parse_success?", parse_success_p, -1);
|
1042
|
+
rb_define_singleton_method(rb_cPrism, "parse_file_success?", parse_file_success_p, -1);
|
979
1043
|
|
980
1044
|
// Next, the functions that will be called by the parser to perform various
|
981
1045
|
// internal tasks. We expose these to make them easier to test.
|