diff options
-rw-r--r-- | lib/prism/ffi.rb | 9 | ||||
-rw-r--r-- | prism/extension.c | 53 | ||||
-rw-r--r-- | prism/util/pm_string.c | 7 | ||||
-rw-r--r-- | test/prism/parse_test.rb | 85 |
4 files changed, 133 insertions, 21 deletions
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb index 12177450f4..617c469df6 100644 --- a/lib/prism/ffi.rb +++ b/lib/prism/ffi.rb @@ -160,8 +160,13 @@ module Prism pointer = FFI::MemoryPointer.new(SIZEOF) begin - raise unless LibRubyParser.pm_string_mapped_init(pointer, filepath) - yield new(pointer) + raise TypeError unless filepath.is_a?(String) + + if LibRubyParser.pm_string_mapped_init(pointer, filepath) + yield new(pointer) + else + raise SystemCallError.new(filepath, FFI.errno) + end ensure LibRubyParser.pm_string_free(pointer) pointer.free diff --git a/prism/extension.c b/prism/extension.c index 7cad38404e..c20ce5b525 100644 --- a/prism/extension.c +++ b/prism/extension.c @@ -1,5 +1,9 @@ #include "prism/extension.h" +#ifdef _WIN32 +#include <ruby/win32.h> +#endif + // NOTE: this file should contain only bindings. All non-trivial logic should be // in libprism so it can be shared its the various callers. @@ -212,20 +216,29 @@ string_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options) /** * Read options for methods that look like (filepath, **options). */ -static bool +static void file_options(int argc, VALUE *argv, pm_string_t *input, pm_options_t *options) { VALUE filepath; VALUE keywords; rb_scan_args(argc, argv, "1:", &filepath, &keywords); + Check_Type(filepath, T_STRING); + extract_options(options, filepath, keywords); - if (!pm_string_mapped_init(input, (const char *) pm_string_source(&options->filepath))) { + const char * string_source = (const char *) pm_string_source(&options->filepath); + + if (!pm_string_mapped_init(input, string_source)) { pm_options_free(options); - return false; - } - return true; +#ifdef _WIN32 + int e = rb_w32_map_errno(GetLastError()); +#else + int e = errno; +#endif + + rb_syserr_fail(e, string_source); + } } /******************************************************************************/ @@ -299,7 +312,8 @@ static VALUE dump_file(int argc, VALUE *argv, VALUE self) { pm_string_t input; pm_options_t options = { 0 }; - if (!file_options(argc, argv, &input, &options)) return Qnil; + + file_options(argc, argv, &input, &options); VALUE value = dump_input(&input, &options); pm_string_free(&input); @@ -609,7 +623,8 @@ static VALUE lex_file(int argc, VALUE *argv, VALUE self) { pm_string_t input; pm_options_t options = { 0 }; - if (!file_options(argc, argv, &input, &options)) return Qnil; + + file_options(argc, argv, &input, &options); VALUE value = parse_lex_input(&input, &options, false); pm_string_free(&input); @@ -710,7 +725,8 @@ static VALUE parse_file(int argc, VALUE *argv, VALUE self) { pm_string_t input; pm_options_t options = { 0 }; - if (!file_options(argc, argv, &input, &options)) return Qnil; + + file_options(argc, argv, &input, &options); VALUE value = parse_input(&input, &options); pm_string_free(&input); @@ -770,7 +786,8 @@ static VALUE parse_file_comments(int argc, VALUE *argv, VALUE self) { pm_string_t input; pm_options_t options = { 0 }; - if (!file_options(argc, argv, &input, &options)) return Qnil; + + file_options(argc, argv, &input, &options); VALUE value = parse_input_comments(&input, &options); pm_string_free(&input); @@ -824,7 +841,8 @@ static VALUE parse_lex_file(int argc, VALUE *argv, VALUE self) { pm_string_t input; pm_options_t options = { 0 }; - if (!file_options(argc, argv, &input, &options)) return Qnil; + + file_options(argc, argv, &input, &options); VALUE value = parse_lex_input(&input, &options, true); pm_string_free(&input); @@ -881,7 +899,8 @@ 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; + + file_options(argc, argv, &input, &options); VALUE result = parse_input_success_p(&input, &options); pm_string_free(&input); @@ -959,7 +978,17 @@ profile_file(VALUE self, VALUE filepath) { pm_string_t input; const char *checked = check_string(filepath); - if (!pm_string_mapped_init(&input, checked)) return Qnil; + Check_Type(filepath, T_STRING); + + if (!pm_string_mapped_init(&input, checked)) { +#ifdef _WIN32 + int e = rb_w32_map_errno(GetLastError()); +#else + int e = errno; +#endif + + rb_syserr_fail(e, checked); + } pm_options_t options = { 0 }; pm_options_filepath_set(&options, checked); diff --git a/prism/util/pm_string.c b/prism/util/pm_string.c index f4d3033a1b..e67fcee0ec 100644 --- a/prism/util/pm_string.c +++ b/prism/util/pm_string.c @@ -65,7 +65,6 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { HANDLE file = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (file == INVALID_HANDLE_VALUE) { - perror("CreateFile failed"); return false; } @@ -73,7 +72,6 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { DWORD file_size = GetFileSize(file, NULL); if (file_size == INVALID_FILE_SIZE) { CloseHandle(file); - perror("GetFileSize failed"); return false; } @@ -90,7 +88,6 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { HANDLE mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); if (mapping == NULL) { CloseHandle(file); - perror("CreateFileMapping failed"); return false; } @@ -100,7 +97,6 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { CloseHandle(file); if (source == NULL) { - perror("MapViewOfFile failed"); return false; } @@ -110,7 +106,6 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { // Open the file for reading int fd = open(filepath, O_RDONLY); if (fd == -1) { - perror("open"); return false; } @@ -118,7 +113,6 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { struct stat sb; if (fstat(fd, &sb) == -1) { close(fd); - perror("fstat"); return false; } @@ -135,7 +129,6 @@ pm_string_mapped_init(pm_string_t *string, const char *filepath) { source = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); if (source == MAP_FAILED) { - perror("Map failed"); return false; } diff --git a/test/prism/parse_test.rb b/test/prism/parse_test.rb index 2624315008..3a2bc3716f 100644 --- a/test/prism/parse_test.rb +++ b/test/prism/parse_test.rb @@ -69,11 +69,96 @@ module Prism assert_equal 5, tokens.length end + def test_dump_file + assert_nothing_raised do + Prism.dump_file(__FILE__) + end + + error = assert_raise Errno::ENOENT do + Prism.dump_file("idontexist.rb") + end + + assert_equal "No such file or directory - idontexist.rb", error.message + + assert_raise TypeError do + Prism.dump_file(nil) + end + end + + def test_lex_file + assert_nothing_raised do + Prism.lex_file(__FILE__) + end + + error = assert_raise Errno::ENOENT do + Prism.lex_file("idontexist.rb") + end + + assert_equal "No such file or directory - idontexist.rb", error.message + + assert_raise TypeError do + Prism.lex_file(nil) + end + end + def test_parse_lex_file node, tokens = Prism.parse_lex_file(__FILE__).value assert_kind_of ProgramNode, node refute_empty tokens + + error = assert_raise Errno::ENOENT do + Prism.parse_lex_file("idontexist.rb") + end + + assert_equal "No such file or directory - idontexist.rb", error.message + + assert_raise TypeError do + Prism.parse_lex_file(nil) + end + end + + def test_parse_file + node = Prism.parse_file(__FILE__).value + assert_kind_of ProgramNode, node + + error = assert_raise Errno::ENOENT do + Prism.parse_file("idontexist.rb") + end + + assert_equal "No such file or directory - idontexist.rb", error.message + + assert_raise TypeError do + Prism.parse_file(nil) + end + end + + def test_parse_file_success + assert_predicate Prism.parse_file_comments(__FILE__), :any? + + error = assert_raise Errno::ENOENT do + Prism.parse_file_comments("idontexist.rb") + end + + assert_equal "No such file or directory - idontexist.rb", error.message + + assert_raise TypeError do + Prism.parse_file_comments(nil) + end + end + + def test_parse_file_comments + assert_predicate Prism.parse_file_comments(__FILE__), :any? + + error = assert_raise Errno::ENOENT do + Prism.parse_file_comments("idontexist.rb") + end + + assert_equal "No such file or directory - idontexist.rb", error.message + + assert_raise TypeError do + Prism.parse_file_comments(nil) + end end # To accurately compare against Ripper, we need to make sure that we're |