Skip to content

Commit

Permalink
src: expose macros that throw errors
Browse files Browse the repository at this point in the history
Macros `NAPI_THROW`, `NAPI_THROW_IF_FAILED`, and `NAPI_FATAL_IF_FAILED`
have so far been used only in the implementation of node-addon-api.
Nevertheless, they are useful in cases where direct N-API calls must be
interspersed between normal node-addon-api usage. The greatest value
they provide is that they convert non-`napi_ok` `napi_status` values
into errors that can be thrown, and that they throw the errors
respecting whether C++ exceptions are enabled or not.

PR-URL: nodejs/node-addon-api#448
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: Nicola Del Gobbo <nicoladelgobbo@NickNaso.local>
  • Loading branch information
kevindavies8 committed Mar 4, 2019
1 parent b7c7751 commit 2876e5e
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 62 deletions.
31 changes: 31 additions & 0 deletions doc/error_handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,34 @@ if (env.IsExceptionPending()) {

Since the exception was cleared here, it will not be propagated as a JavaScript
exception after the native callback returns.

## Calling N-API directly from a **node-addon-api** addon

**node-addon-api** provides macros for throwing errors in response to non-OK
`napi_status` results when calling [N-API](https://nodejs.org/docs/latest/api/n-api.html)
functions from within a native addon. These macros are defined differently
depending on whether C++ exceptions are enabled or not, but are available for
use in either case.

### `NAPI_THROW(e, ...)`

This macro accepts a `Napi::Error`, throws it, and returns the value given as
the last parameter. If C++ exceptions are enabled (by defining
`NAPI_CPP_EXCEPTIONS` during the build), the return value will be ignored.

### `NAPI_THROW_IF_FAILED(env, status, ...)`

This macro accepts a `Napi::Env` and a `napi_status`. It constructs an error
from the `napi_status`, throws it, and returns the value given as the last
parameter. If C++ exceptions are enabled (by defining `NAPI_CPP_EXCEPTIONS`
during the build), the return value will be ignored.

### `NAPI_THROW_IF_FAILED_VOID(env, status)`

This macro accepts a `Napi::Env` and a `napi_status`. It constructs an error
from the `napi_status`, throws it, and returns.

### `NAPI_FATAL_IF_FAILED(status, location, message)`

This macro accepts a `napi_status`, a C string indicating the location where the
error occurred, and a second C string for the message to display.
62 changes: 0 additions & 62 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,64 +17,6 @@ namespace Napi {
// Helpers to handle functions exposed from C++.
namespace details {

#ifdef NAPI_CPP_EXCEPTIONS

// When C++ exceptions are enabled, Errors are thrown directly. There is no need
// to return anything after the throw statements. The variadic parameter is an
// optional return value that is ignored.
// We need _VOID versions of the macros to avoid warnings resulting from
// leaving the NAPI_THROW_* `...` argument empty.

#define NAPI_THROW(e, ...) throw e
#define NAPI_THROW_VOID(e) throw e

#define NAPI_THROW_IF_FAILED(env, status, ...) \
if ((status) != napi_ok) throw Error::New(env);

#define NAPI_THROW_IF_FAILED_VOID(env, status) \
if ((status) != napi_ok) throw Error::New(env);

#else // NAPI_CPP_EXCEPTIONS

// When C++ exceptions are disabled, Errors are thrown as JavaScript exceptions,
// which are pending until the callback returns to JS. The variadic parameter
// is an optional return value; usually it is an empty result.
// We need _VOID versions of the macros to avoid warnings resulting from
// leaving the NAPI_THROW_* `...` argument empty.

#define NAPI_THROW(e, ...) \
do { \
(e).ThrowAsJavaScriptException(); \
return __VA_ARGS__; \
} while (0)

#define NAPI_THROW_VOID(e) \
do { \
(e).ThrowAsJavaScriptException(); \
return; \
} while (0)

#define NAPI_THROW_IF_FAILED(env, status, ...) \
if ((status) != napi_ok) { \
Error::New(env).ThrowAsJavaScriptException(); \
return __VA_ARGS__; \
}

#define NAPI_THROW_IF_FAILED_VOID(env, status) \
if ((status) != napi_ok) { \
Error::New(env).ThrowAsJavaScriptException(); \
return; \
}

#endif // NAPI_CPP_EXCEPTIONS

#define NAPI_FATAL_IF_FAILED(status, location, message) \
do { \
if ((status) != napi_ok) { \
Error::Fatal((location), (message)); \
} \
} while (0)

// Attach a data item to an object and delete it when the object gets
// garbage-collected.
// TODO: Replace this code with `napi_add_finalizer()` whenever it becomes
Expand Down Expand Up @@ -3705,10 +3647,6 @@ inline const napi_node_version* VersionManagement::GetNodeVersion(Env env) {
return result;
}

// These macros shouldn't be useful in user code.
#undef NAPI_THROW
#undef NAPI_THROW_IF_FAILED

} // namespace Napi

#endif // SRC_NAPI_INL_H_
58 changes: 58 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,64 @@ static_assert(sizeof(char16_t) == sizeof(wchar_t), "Size mismatch between char16
#define NAPI_NOEXCEPT noexcept
#endif

#ifdef NAPI_CPP_EXCEPTIONS

// When C++ exceptions are enabled, Errors are thrown directly. There is no need
// to return anything after the throw statements. The variadic parameter is an
// optional return value that is ignored.
// We need _VOID versions of the macros to avoid warnings resulting from
// leaving the NAPI_THROW_* `...` argument empty.

#define NAPI_THROW(e, ...) throw e
#define NAPI_THROW_VOID(e) throw e

#define NAPI_THROW_IF_FAILED(env, status, ...) \
if ((status) != napi_ok) throw Error::New(env);

#define NAPI_THROW_IF_FAILED_VOID(env, status) \
if ((status) != napi_ok) throw Error::New(env);

#else // NAPI_CPP_EXCEPTIONS

// When C++ exceptions are disabled, Errors are thrown as JavaScript exceptions,
// which are pending until the callback returns to JS. The variadic parameter
// is an optional return value; usually it is an empty result.
// We need _VOID versions of the macros to avoid warnings resulting from
// leaving the NAPI_THROW_* `...` argument empty.

#define NAPI_THROW(e, ...) \
do { \
(e).ThrowAsJavaScriptException(); \
return __VA_ARGS__; \
} while (0)

#define NAPI_THROW_VOID(e) \
do { \
(e).ThrowAsJavaScriptException(); \
return; \
} while (0)

#define NAPI_THROW_IF_FAILED(env, status, ...) \
if ((status) != napi_ok) { \
Error::New(env).ThrowAsJavaScriptException(); \
return __VA_ARGS__; \
}

#define NAPI_THROW_IF_FAILED_VOID(env, status) \
if ((status) != napi_ok) { \
Error::New(env).ThrowAsJavaScriptException(); \
return; \
}

#endif // NAPI_CPP_EXCEPTIONS

#define NAPI_FATAL_IF_FAILED(status, location, message) \
do { \
if ((status) != napi_ok) { \
Error::Fatal((location), (message)); \
} \
} while (0)

////////////////////////////////////////////////////////////////////////////////
/// N-API C++ Wrapper Classes
///
Expand Down

0 comments on commit 2876e5e

Please sign in to comment.