[ruby/prism] Prism.parse_success?(source)
A lot of tools use Ripper/RubyVM::AbstractSyntaxTree to determine if a source is valid. These tools both create an AST instead of providing an API that will return a boolean only. This new API only creates the C structs, but doesn't bother reifying them into Ruby/the serialization API. Instead it only returns true/false, which is significantly more efficient. https://github.com/ruby/prism/commit/7014740118
This commit is contained in:
parent
b77551adee
commit
492c82cb41
16
lib/prism.rb
16
lib/prism.rb
@ -64,6 +64,22 @@ module Prism
|
||||
def self.load(source, serialized)
|
||||
Serialize.load(source, serialized)
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# Prism::parse_failure?(source, **options) -> bool
|
||||
#
|
||||
# Returns true if the source is invalid Ruby code.
|
||||
def self.parse_failure?(source, **options)
|
||||
!parse_success?(source, **options)
|
||||
end
|
||||
|
||||
# :call-seq:
|
||||
# Prism::parse_file_failure?(filepath, **options) -> bool
|
||||
#
|
||||
# Returns true if the file at filepath is invalid Ruby code.
|
||||
def self.parse_file_failure?(filepath, **options)
|
||||
!parse_file_success?(filepath, **options)
|
||||
end
|
||||
end
|
||||
|
||||
require_relative "prism/node"
|
||||
|
@ -72,7 +72,8 @@ module Prism
|
||||
"pm_serialize_parse",
|
||||
"pm_serialize_parse_comments",
|
||||
"pm_serialize_lex",
|
||||
"pm_serialize_parse_lex"
|
||||
"pm_serialize_parse_lex",
|
||||
"pm_parse_success_p"
|
||||
)
|
||||
|
||||
load_exported_functions_from(
|
||||
@ -268,6 +269,18 @@ module Prism
|
||||
end
|
||||
end
|
||||
|
||||
# Mirror the Prism.parse_success? API by using the serialization API.
|
||||
def parse_success?(code, **options)
|
||||
LibRubyParser.pm_parse_success_p(code, code.bytesize, dump_options(options))
|
||||
end
|
||||
|
||||
# Mirror the Prism.parse_file_success? API by using the serialization API.
|
||||
def parse_file_success?(filepath, **options)
|
||||
LibRubyParser::PrismString.with(filepath) do |string|
|
||||
parse_success?(string.read, **options, filepath: filepath)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Convert the given options into a serialized options string.
|
||||
|
@ -798,6 +798,64 @@ parse_lex_file(int argc, VALUE *argv, VALUE self) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the given input and return true if it parses without errors or
|
||||
* warnings.
|
||||
*/
|
||||
static VALUE
|
||||
parse_input_success_p(pm_string_t *input, const pm_options_t *options) {
|
||||
pm_parser_t parser;
|
||||
pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
|
||||
|
||||
pm_node_t *node = pm_parse(&parser);
|
||||
pm_node_destroy(&parser, node);
|
||||
|
||||
VALUE result = parser.error_list.size == 0 && parser.warning_list.size == 0 ? Qtrue : Qfalse;
|
||||
pm_parser_free(&parser);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* call-seq:
|
||||
* Prism::parse_success?(source, **options) -> Array
|
||||
*
|
||||
* Parse the given string and return true if it parses without errors or
|
||||
* warnings. For supported options, see Prism::parse.
|
||||
*/
|
||||
static VALUE
|
||||
parse_success_p(int argc, VALUE *argv, VALUE self) {
|
||||
pm_string_t input;
|
||||
pm_options_t options = { 0 };
|
||||
string_options(argc, argv, &input, &options);
|
||||
|
||||
VALUE result = parse_input_success_p(&input, &options);
|
||||
pm_string_free(&input);
|
||||
pm_options_free(&options);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* call-seq:
|
||||
* Prism::parse_file_success?(filepath, **options) -> Array
|
||||
*
|
||||
* Parse the given file and return true if it parses without errors or warnings.
|
||||
* For supported options, see Prism::parse.
|
||||
*/
|
||||
static VALUE
|
||||
parse_file_success_p(int argc, VALUE *argv, VALUE self) {
|
||||
pm_string_t input;
|
||||
pm_options_t options = { 0 };
|
||||
if (!file_options(argc, argv, &input, &options)) return Qnil;
|
||||
|
||||
VALUE result = parse_input_success_p(&input, &options);
|
||||
pm_string_free(&input);
|
||||
pm_options_free(&options);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* Utility functions exposed to make testing easier */
|
||||
/******************************************************************************/
|
||||
@ -981,6 +1039,8 @@ Init_prism(void) {
|
||||
rb_define_singleton_method(rb_cPrism, "parse_file_comments", parse_file_comments, -1);
|
||||
rb_define_singleton_method(rb_cPrism, "parse_lex", parse_lex, -1);
|
||||
rb_define_singleton_method(rb_cPrism, "parse_lex_file", parse_lex_file, -1);
|
||||
rb_define_singleton_method(rb_cPrism, "parse_success?", parse_success_p, -1);
|
||||
rb_define_singleton_method(rb_cPrism, "parse_file_success?", parse_file_success_p, -1);
|
||||
|
||||
// Next, the functions that will be called by the parser to perform various
|
||||
// internal tasks. We expose these to make them easier to test.
|
||||
|
@ -152,6 +152,16 @@ PRISM_EXPORTED_FUNCTION void pm_serialize_lex(pm_buffer_t *buffer, const uint8_t
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION void pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data);
|
||||
|
||||
/**
|
||||
* Parse the source and return true if it parses without errors or warnings.
|
||||
*
|
||||
* @param source The source to parse.
|
||||
* @param size The size of the source.
|
||||
* @param data The optional data to pass to the parser.
|
||||
* @return True if the source parses without errors or warnings.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION bool pm_parse_success_p(const uint8_t *source, size_t size, const char *data);
|
||||
|
||||
/**
|
||||
* Returns a string representation of the given token type.
|
||||
*
|
||||
|
@ -359,3 +359,24 @@ pm_serialize_parse_lex(pm_buffer_t *buffer, const uint8_t *source, size_t size,
|
||||
pm_parser_free(&parser);
|
||||
pm_options_free(&options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the source and return true if it parses without errors or warnings.
|
||||
*/
|
||||
PRISM_EXPORTED_FUNCTION bool
|
||||
pm_parse_success_p(const uint8_t *source, size_t size, const char *data) {
|
||||
pm_options_t options = { 0 };
|
||||
pm_options_read(&options, data);
|
||||
|
||||
pm_parser_t parser;
|
||||
pm_parser_init(&parser, source, size, &options);
|
||||
|
||||
pm_node_t *node = pm_parse(&parser);
|
||||
pm_node_destroy(&parser, node);
|
||||
|
||||
bool result = parser.error_list.size == 0 && parser.warning_list.size == 0;
|
||||
pm_parser_free(&parser);
|
||||
pm_options_free(&options);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -20,6 +20,18 @@ module Prism
|
||||
assert_equal_nodes ast2, ast3
|
||||
end
|
||||
|
||||
def test_parse_success?
|
||||
assert Prism.parse_success?("1")
|
||||
refute Prism.parse_success?("<>")
|
||||
|
||||
assert Prism.parse_success?("m //", verbose: false)
|
||||
refute Prism.parse_success?("m //", verbose: true)
|
||||
end
|
||||
|
||||
def test_parse_file_success?
|
||||
assert Prism.parse_file_success?(__FILE__)
|
||||
end
|
||||
|
||||
def test_options
|
||||
assert_equal "", Prism.parse("__FILE__").value.statements.body[0].filepath
|
||||
assert_equal "foo.rb", Prism.parse("__FILE__", filepath: "foo.rb").value.statements.body[0].filepath
|
||||
|
Loading…
x
Reference in New Issue
Block a user