|
2 | 2 | #include "lib-ruby-parser.h" |
3 | 3 | #include "convert.h" |
4 | 4 | #include "custom_decoder.h" |
| 5 | +#include "bytes.h" |
| 6 | +#include "result.h" |
5 | 7 | #include <iostream> |
6 | 8 | #include <variant> |
7 | 9 | #include <tuple> |
8 | 10 |
|
9 | 11 | namespace lib_ruby_parser_node |
10 | 12 | { |
11 | | - Napi::Value JsThrow(Napi::Env env, std::string message) |
| 13 | + Napi::Value JsThrow(Napi::Env env, const std::string &message) |
12 | 14 | { |
13 | 15 | Napi::TypeError::New(env, message).ThrowAsJavaScriptException(); |
14 | 16 | return env.Null(); |
15 | 17 | } |
16 | 18 |
|
17 | | - using SharedDecodeError = std::shared_ptr<JsCustomDecoder::DecodeError>; |
18 | | - using BuildParserOptionsSuccess = std::tuple<lib_ruby_parser::ParserOptions, SharedDecodeError>; |
19 | | - using BuildParserOptionsResult = std::variant<BuildParserOptionsSuccess, std::string>; |
20 | | - |
21 | | - BuildParserOptionsResult BuildParserOptions(Napi::Object &object) |
| 19 | + class ParserOptions : public lib_ruby_parser::ParserOptions |
22 | 20 | { |
23 | | - lib_ruby_parser::ParserOptions options; |
24 | | - options.record_tokens = object.Get("record_tokens").ToBoolean().Value(); |
25 | | - options.debug = object.Get("debug").ToBoolean().Value(); |
26 | | - Napi::Value buffer_name = object.Get("buffer_name"); |
27 | | - if (buffer_name.IsString()) |
28 | | - { |
29 | | - options.buffer_name = buffer_name.As<Napi::String>().Utf8Value(); |
30 | | - } |
31 | | - else if (buffer_name.IsUndefined()) |
32 | | - { |
33 | | - // ok, default is used |
34 | | - } |
35 | | - else |
36 | | - { |
37 | | - return "buffer_name must be string/undefined"; |
38 | | - } |
39 | | - SharedDecodeError decode_error = std::make_shared<JsCustomDecoder::DecodeError>(); |
40 | | - Napi::Value custom_decoder = object.Get("custom_decoder"); |
41 | | - if (custom_decoder.IsFunction()) |
42 | | - { |
43 | | - options.custom_decoder = std::make_unique<JsCustomDecoder>(custom_decoder.As<Napi::Function>(), decode_error); |
44 | | - } |
45 | | - else if (custom_decoder.IsUndefined()) |
46 | | - { |
47 | | - // ok, default is used |
48 | | - } |
49 | | - else |
| 21 | + public: |
| 22 | + std::shared_ptr<std::string> decode_error; |
| 23 | + |
| 24 | + static Result<ParserOptions> FromV8(Napi::Value value) |
50 | 25 | { |
51 | | - return "custom_decoder must be function/undefined"; |
| 26 | + if (!value.IsObject()) |
| 27 | + { |
| 28 | + return "parser_options must be an object"; |
| 29 | + } |
| 30 | + Napi::Object object = value.As<Napi::Object>(); |
| 31 | + ParserOptions options; |
| 32 | + |
| 33 | + options.record_tokens = object.Get("record_tokens").ToBoolean().Value(); |
| 34 | + options.debug = object.Get("debug").ToBoolean().Value(); |
| 35 | + |
| 36 | + Napi::Value buffer_name = object.Get("buffer_name"); |
| 37 | + if (buffer_name.IsString()) |
| 38 | + { |
| 39 | + options.buffer_name = buffer_name.As<Napi::String>().Utf8Value(); |
| 40 | + } |
| 41 | + else if (buffer_name.IsUndefined()) |
| 42 | + { |
| 43 | + // ok, default is used |
| 44 | + } |
| 45 | + else |
| 46 | + { |
| 47 | + return "buffer_name must be string/undefined"; |
| 48 | + } |
| 49 | + |
| 50 | + Napi::Value custom_decoder = object.Get("custom_decoder"); |
| 51 | + if (custom_decoder.IsFunction()) |
| 52 | + { |
| 53 | + auto decoder = std::make_unique<JsCustomDecoder>(custom_decoder.As<Napi::Function>()); |
| 54 | + options.decode_error = decoder->error; |
| 55 | + options.custom_decoder = std::move(decoder); |
| 56 | + } |
| 57 | + else if (custom_decoder.IsUndefined()) |
| 58 | + { |
| 59 | + // ok, default is used |
| 60 | + } |
| 61 | + else |
| 62 | + { |
| 63 | + return "custom_decoder must be function/undefined"; |
| 64 | + } |
| 65 | + |
| 66 | + return std::move(options); |
52 | 67 | } |
| 68 | + }; |
53 | 69 |
|
54 | | - return std::make_tuple(std::move(options), decode_error); |
55 | | - } |
56 | | - |
57 | | - Napi::Value parse(const Napi::CallbackInfo &info) |
| 70 | + Result<std::unique_ptr<lib_ruby_parser::ParserResult>> parse(const Napi::CallbackInfo &info) |
58 | 71 | { |
59 | 72 | Napi::Env env = info.Env(); |
60 | 73 |
|
61 | 74 | if (info.Length() != 2) |
62 | | - return JsThrow(env, "Wrong number of arguments (expected 2)"); |
| 75 | + { |
| 76 | + return "Wrong number of arguments (expected 2)"; |
| 77 | + } |
| 78 | + |
| 79 | + UNWRAP_RESULT(bytes, Bytes::FromV8(info[0])); |
| 80 | + UNWRAP_RESULT(options, ParserOptions::FromV8(info[1])); |
63 | 81 |
|
64 | | - if (!info[0].IsString()) |
65 | | - return JsThrow(env, "The first argument must be a string"); |
66 | | - std::string source = info[0].As<Napi::String>().Utf8Value(); |
| 82 | + auto decode_error = options.decode_error; |
67 | 83 |
|
68 | | - if (!info[1].IsObject()) |
69 | | - return JsThrow(env, "The second argument must be an object"); |
70 | | - Napi::Object js_options = info[1].As<Napi::Object>(); |
| 84 | + auto result = lib_ruby_parser::ParserResult::from_source(std::move(bytes), std::move(options)); |
71 | 85 |
|
72 | | - auto build_result = BuildParserOptions(js_options); |
73 | | - if (auto error = std::get_if<std::string>(&build_result)) |
| 86 | + if (decode_error) |
74 | 87 | { |
75 | | - return JsThrow(env, *error); |
| 88 | + return std::string(*(decode_error.get())); |
76 | 89 | } |
77 | | - auto tuple = std::get<BuildParserOptionsSuccess>(std::move(build_result)); |
78 | | - auto decode_error = std::get<1>(tuple); |
79 | | - auto options = std::get<0>(std::move(tuple)); |
| 90 | + return std::move(result); |
| 91 | + } |
80 | 92 |
|
81 | | - auto result = lib_ruby_parser::ParserResult::from_source(source, std::move(options)); |
| 93 | + Napi::Value js_parse(const Napi::CallbackInfo &info) |
| 94 | + { |
| 95 | + Napi::Env env = info.Env(); |
82 | 96 |
|
83 | | - if (decode_error->has_error) |
| 97 | + auto result = parse(info); |
| 98 | + if (result.is_err()) |
84 | 99 | { |
85 | | - Napi::TypeError::New(env, decode_error->error) |
86 | | - .ThrowAsJavaScriptException(); |
87 | | - return env.Null(); |
| 100 | + return JsThrow(env, result.get_err()); |
88 | 101 | } |
89 | | - return convert(std::move(result), env); |
| 102 | + return convert(result.get(), env); |
90 | 103 | } |
91 | 104 |
|
92 | 105 | Napi::Object Init(Napi::Env env, Napi::Object exports) |
93 | 106 | { |
94 | 107 | exports.Set(Napi::String::New(env, "parse"), |
95 | | - Napi::Function::New(env, parse)); |
| 108 | + Napi::Function::New(env, js_parse)); |
96 | 109 |
|
97 | 110 | InitCustomTypes(env, exports); |
98 | 111 | InitNodeTypes(env, exports); |
|
0 commit comments