Javascript Node-API support added

Closes #2545
This commit is contained in:
Momtchil Momtchev 2023-06-28 07:21:10 +01:00 committed by William S Fulton
parent 4e20b7d71e
commit ceed54758a
63 changed files with 3839 additions and 107 deletions

View File

@ -98,6 +98,14 @@ jobs:
ENGINE: node
VER: '18'
CPPSTD: c++14
- SWIGLANG: javascript
ENGINE: napi
VER: '14'
CPPSTD: c++11
- SWIGLANG: javascript
ENGINE: napi
VER: '18'
CPPSTD: c++14
- SWIGLANG: javascript
ENGINE: jsc
VER: '4.0'

1
.gitignore vendored
View File

@ -157,6 +157,7 @@ Examples/java/doxygen/javadocs
# Javascript
Examples/test-suite/javascript/*/
*.gyp
!Examples/test-suite/javascript/node_template
# Lua
Examples/lua/dual/dual

View File

@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.2.0 (in progress)
===========================
2023-06-27: mmomtchev
[Javascript] #2545 New Javascript generator targeting the Node.js
binary stable ABI Node-API.
2023-06-27: olly
[Java] Completely remove pragmas which were deprecated in 2002 and
have triggered an error since SWIG 2.0:

View File

@ -79,7 +79,7 @@ With <a href="https://github.com/rogerwang/node-webkit">node-webkit</a> there is
int gcd(int x, int y);
extern double Foo;</pre>
</div>
<p>To build a Javascript module, run SWIG using the <code>-javascript</code> option and a desired target engine <code>-jsc</code>, <code>-v8</code>, or <code>-node</code>. The generator for <code>node</code> is essentially delegating to the <code>v8</code> generator and adds some necessary preprocessor definitions.</p>
<p>To build a Javascript module, run SWIG using the <code>-javascript</code> option and a desired target engine <code>-jsc</code>, <code>-v8</code>, <code>-node</code> or <code>-napi</code>. <code>-v8</code> allows for interfacing with a raw embedded version of V8. In this case, it is up to the user to implement a binary module loading protocol. There are two generators supporting Node.js. The older generator for <code>node</code> is essentially delegating to the <code>v8</code> generator and adds some necessary preprocessor definitions. The more recent <code>-napi</code> generator produces <code>node-addon-api</code> that interfaces to Node.js through Node-API. The V8 generator is more mature, while the Node-API generator offers a number of advantages such as binary stable ABI allowing for publishing of universal binary modules on npm, Electron support and automatic multi-threading.</p>
<div class="shell">
<pre>
$ swig -javascript -jsc example.i</pre>
@ -92,6 +92,10 @@ $ swig -c++ -javascript -jsc example.i</pre>
<p>The V8 code that SWIG generates requires at least V8 5.0. Keep in mind
that this is theV8 version, not Node.js. To give some perspective, Node.js v6.0
uses V8 5.0, v12.0 - 7.4, v14.0 - 8.1...</p>
<p>The Node-API code that SWIG generates requires Node-API version 6.
This Node-API is available starting from Node.js v10.20 on the v10.x branch,
Node.js v12.17 on the v12.x branch and all versions starting from v14.0.</p>
</p>
<p>To generate code for V8, you would run swig like so:</p>
<div class="shell">
<pre>
@ -127,12 +131,17 @@ $ sudo apt-get install libjavascriptcoregtk-1.0-dev</pre>
<pre>
$ sudo apt-get install libv8-dev</pre>
</div>
<p>Running with Node-API requires <code>node-addon-api</code>:</p>
<div class="shell">
<pre>
$ sudo npm install -g node-addon-api</pre>
</div>
<p>Examples can be run using</p>
<div class="shell">
<pre>
$ make check-javascript-examples ENGINE=jsc</pre>
</div>
<p><code>ENGINE</code> can be <code>node</code>, <code>jsc</code>, or <code>v8</code>.</p>
<p><code>ENGINE</code> can be <code>node</code>, <code>jsc</code>, <code>v8</code>, or <code>napi</code>.</p>
<p>The test-suite can be run using</p>
<div class="shell">
<pre>
@ -150,15 +159,15 @@ $ make check-javascript-examples V8_VERSION=0x032530 ENGINE=v8</pre>
<p>At the moment, the Javascript generators pass all tests syntactically, i.e., the generated source code compiles. However, there are still remaining runtime issues.</p>
<ul>
<li><p>Default optional arguments do not work for all targeted interpreters</p></li>
<li><p>Default optional arguments do not work for all targeted interpreters except Node-API</p></li>
<li><p>Multiple output arguments do not work for JSC</p></li>
<li><p>C89 incompatibility: the JSC generator might still generate C89 violating code</p></li>
<li><p><code>long long</code> is not supported</p></li>
<li><p><code>long long</code> is not supported except with Node-API</p></li>
<li><p>Javascript callbacks are not supported</p></li>
<li><p><code>instanceOf</code> does not work under JSC</p></li>
</ul>
<p>The primary development environment has been Linux (Ubuntu 12.04). Windows and Mac OS X have been tested sporadically. Therefore, the generators might have more issues on those platforms. Please report back any problem you observe to help us improving this module quickly.</p>
<p>The primary development environment has been Linux (Ubuntu 22.04). Windows and Mac OS X have been tested sporadically. Therefore, the generators might have more issues on those platforms. Please report back any problem you observe to help us improving this module quickly.</p>
<H2><a name="Javascript_integration">28.3 Integration</a></H2>
@ -211,7 +220,25 @@ require("./build/Release/example")</pre>
</div>
<p>A more detailed explanation is given in the <a href="#Javascript_examples">Examples</a> section.</p>
<H4><a name="Javascript_troubleshooting">28.3.1.1 Troubleshooting</a></H4>
<H4><a name="Using_yeoman">28.3.1.1 Using <code>yeoman</code> to generate a Node-API skeleton</a></H4>
<p>If targeting Node-API, the easiest way to bootstrap a project is by using the <code>yeoman</code> generator: </p>
<div class="shell">
<pre>
$ sudo npm install -g yo
$ sudo npm install -g generator-napi-module
$ mkdir example
$ cd example
$ yo napi-module # the choice of template is irrelevant, SWIG will replace the C++ code
$ npm install node-addon-api@latest # the yeoman version is outdated
$ swig -javascript -napi -c++ -o src/example.cc example.i
$ node-gyp configure
$ node-gyp build
</pre>
</div>
<p>There is also the <a href="https://github.com/mmomtchev/node-magickwand"><code>node-magickwand</code></a> project that can be used as a tutorial for building and publishing a complex C++ library to
npm as a ready-to-use real-world binary module.</p>
<H4><a name="Javascript_troubleshooting">28.3.1.2 Troubleshooting</a></H4>
<ul>
@ -605,7 +632,7 @@ at emitKey (readline.js:1095:12)</pre>
<H3><a name="Javascript_source_code">28.5.1 Source Code</a></H3>
<p>The Javascript module is implemented in <code>Source/Modules/javascript.cxx</code>. It dispatches the code generation to a <code>JSEmitter</code> instance, <code>V8Emitter</code> or <code>JSCEmitter</code>. Additionally there are some helpers: <code>Template</code>, for templated code generation, and <code>JSEmitterState</code>, which is used to manage state information during AST traversal. This rough map shall make it easier to find a way through this huge source file:</p>
<p>The Javascript module is implemented in <code>Source/Modules/javascript.cxx</code>. It dispatches the code generation to a <code>JSEmitter</code> instance, <code>V8Emitter</code>, <code>JSCEmitter</code> or <code>NAPIEmitter</code>. Additionally there are some helpers: <code>Template</code>, for templated code generation, and <code>JSEmitterState</code>, which is used to manage state information during AST traversal. This rough map shall make it easier to find a way through this huge source file:</p>
<div class="code">
<pre>
// module wide defines
@ -629,6 +656,7 @@ class JSEmitter { ... };
JSEmitter *swig_javascript_create_JSCEmitter();
JSEmitter *swig_javascript_create_V8Emitter();
JSEmitter *swig_javascript_create_NAPIEmitter();
// ###############################
// # Javascript module
@ -706,7 +734,7 @@ Template::Template(const String *code_) { ... }
<H3><a name="Javascript_code_templates">28.5.2 Code Templates</a></H3>
<p>All generated code is created on the basis of code templates. The templates for <em>JavascriptCore</em> can be found in <code>Lib/javascript/jsc/javascriptcode.swg</code>, for <em>v8</em> in <code>Lib/javascript/v8/javascriptcode.swg</code>.</p>
<p>All generated code is created on the basis of code templates. The templates for <em>JavascriptCore</em> can be found in <code>Lib/javascript/jsc/javascriptcode.swg</code>, for <em>v8</em> in <code>Lib/javascript/v8/javascriptcode.swg</code> and for <em>Node-API</em> in <code>Lib/javascript/napi.javascriptcode.swg</code>.</p>
<p>To track the originating code template for generated code you can run</p>
<div class="shell">
<pre>
@ -985,5 +1013,28 @@ if(js_exception)
}</pre>
</div>
<H3><a name="Javascript_napi_exceptions">28.5.6 Handling Exceptions in Node-API</a></H3>
<p>Node-API is the only generator that provides fully automatic conversion of C++ exceptions to JavaScript exceptions when building with C++ exceptions enabled in `binding.gyp`:</p>
<div class="code">
<pre>
'conditions': [
['OS=="mac"',
{
'xcode_settings': {
'GCC_ENABLE_CPP_RTTI': 'YES',
'GCC_ENABLE_CPP_EXCEPTIONS' : 'YES'
}
}
],
['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"',
{
'cflags!': [ '-fno-exceptions' ],
'cflags_cc!': [ '-fno-exceptions', '-fno-rtti' ]
}
]
]
</pre>
</div>
<p>In this case, nothing else is needed for the C++ exceptions to be passed to JavaScript.</p>
</body>
</html>

View File

@ -132,6 +132,7 @@ SWIGJAVA Defined when using Java
SWIGJAVASCRIPT Defined when using Javascript
SWIG_JAVASCRIPT_JSC Defined when using Javascript with -jsc
SWIG_JAVASCRIPT_V8 Defined when using Javascript with -v8 or -node
SWIG_JAVASCRIPT_NAPI Defined when using Javascript with -napi
SWIGLUA Defined when using Lua
SWIGMZSCHEME Defined when using Mzscheme
SWIGOCAML Defined when using OCaml

View File

@ -688,8 +688,10 @@ endif
# Creating and building Javascript wrappers
# ----------------------------------------------------------------
NAPI_DIR = @NODENAPI_DIR@
javascript_wrapper:
ifeq (node,$(JSENGINE))
ifeq ($(JSENGINE), $(filter $(JSENGINE), node napi))
$(SWIG) -javascript $(SWIGOPT) -$(JSENGINE) -o $(INTERFACEDIR)$(TARGET)_wrap.cxx $(INTERFACEPATH)
else
$(SWIG) -javascript $(SWIGOPT) -$(JSENGINE) -o $(INTERFACEDIR)$(TARGET)_wrap.c $(INTERFACEPATH)
@ -702,15 +704,18 @@ javascript_build: $(SRCDIR_SRCS)
ifeq (node,$(JSENGINE))
sed -e 's|$$srcdir|./$(SRCDIR)|g' $(SRCDIR)binding.gyp.in > binding.gyp
MAKEFLAGS= $(NODEGYP) --loglevel=silent configure build 1>>/dev/null
else ifeq (napi,$(JSENGINE))
sed -e 's|$$srcdir|./$(SRCDIR)|g' $(SRCDIR)binding.gyp.in > binding.gyp
MAKEFLAGS= CXXFLAGS="$(CXXFLAGS) -I$(NAPI_DIR)" $(NODEGYP) --loglevel=silent configure build 1>>/dev/null
else
$(CC) -c $(CCSHARED) $(CPPFLAGS) $(CFLAGS) $(ISRCS) $(SRCDIR_SRCS) $(INCLUDES) $(JSINCLUDES)
$(LDSHARED) $(CCSHARED) $(CFLAGS) $(LDFLAGS) $(OBJS) $(IOBJS) $(JSDYNAMICLINKING) $(LIBS) -o $(LIBPREFIX)$(TARGET)$(SO)
endif
javascript_build_cpp: $(SRCDIR_SRCS)
ifeq (node,$(JSENGINE))
ifeq ($(JSENGINE), $(filter $(JSENGINE), node napi))
sed -e 's|$$srcdir|./$(SRCDIR)|g' $(SRCDIR)binding.gyp.in > binding.gyp
MAKEFLAGS= $(NODEGYP) --loglevel=silent configure build 1>>/dev/null
MAKEFLAGS= CXXFLAGS="$(CXXFLAGS) -I$(NAPI_DIR)" $(NODEGYP) --loglevel=silent configure build 1>>/dev/null
else
$(CXX) -c $(CCSHARED) $(CPPFLAGS) $(CXXFLAGS) $(ICXXSRCS) $(SRCDIR_SRCS) $(SRCDIR_CXXSRCS) $(INCLUDES) $(JSINCLUDES)
$(CXXSHARED) $(CXXFLAGS) $(LDFLAGS) $(OBJS) $(IOBJS) $(JSDYNAMICLINKING) $(LIBS) $(CPP_DLLIBS) -o $(LIBPREFIX)$(TARGET)$(SO)
@ -740,7 +745,7 @@ javascript_cpp: $(SRCDIR_SRCS) javascript_custom_interpreter
javascript_custom_interpreter:
(cd $(ROOT_DIR)/Tools/javascript && $(MAKE) JSENGINE='$(JSENGINE)')
ifeq (node,$(JSENGINE))
ifeq ($(JSENGINE), $(filter $(JSENGINE), node napi))
javascript_run:
env NODE_PATH=$$PWD:$(SRCDIR) $(RUNTOOL) $(NODEJS) $(SRCDIR)$(RUNME).js $(RUNPIPE)
else
@ -761,7 +766,7 @@ ifeq (, $(ENGINE))
echo "Version depends on the interpreter"; \
fi
endif
ifeq (node, $(ENGINE))
ifeq ($(ENGINE), $(filter $(ENGINE), node napi))
echo "Node.js: `($(NODEJS) --version)`"
echo "node-gyp: `($(NODEGYP) --version)`"
endif

View File

@ -7,6 +7,12 @@ c = new example.Circle(10);
console.log("Created circle " + c);
s = new example.Square(10);
console.log("Created square " + s);
try {
new example.Shape();
console.error("Should have thrown");
} catch {
console.log("Instantiating abstract class Shape failed");
}
// ----- Access a static member -----
console.log("\nA total of " + example.Shape.nshapes + " shapes were created"); // access static member as properties of the class object
@ -21,6 +27,15 @@ c.y = 30;
s.x = -10;
s.y = 5;
// ----- Check inheritance -----
console.log("Square instanceof Shape: ", s instanceof example.Shape);
console.log("Square instanceof Circle: ", s instanceof example.Circle);
console.log("Square instanceof Square: ", s instanceof example.Square);
// ----- Use an inherited method -----
s.move(1, 1);
c.move(-1, -1);
console.log("\nHere is their new position:");
console.log("Circle = (" + c.x + "," + c.y + ")");
console.log("Square = (" + s.x + "," + s.y + ")");

View File

@ -1,15 +1,19 @@
var example = require("example");
a = new example.intSum(0);
a = new example.intSum(1);
b = new example.doubleSum(100.0);
c = new example.intSum();
// Use the objects. They should be callable just like a normal
// javascript function.
for (i=1;i<=100;i++)
for (i=1;i<=100;i++) {
a.call(i); // Note: function call
b.call(Math.sqrt(i)); // Note: function call
c.call(i);
}
console.log(a.result());
console.log(b.result());
console.log(c.result());

View File

@ -10,7 +10,7 @@ int placeholder() { return 0; }
// actual demo code
%wrapper
%{
#ifdef SWIG_V8_VERSION /* Engine: Node || V8 */
#if defined(SWIG_V8_VERSION) /* Engine: Node || V8 */
static SwigV8ReturnValue JavaScript_do_work(const SwigV8Arguments &args) {
SWIGV8_HANDLESCOPE();
@ -24,6 +24,21 @@ int placeholder() { return 0; }
SWIGV8_RETURN(SWIGV8_UNDEFINED());
}
#elif defined(NAPI_VERSION) /* Engine: NAPI */
static Napi::Value JavaScript_do_work(const Napi::CallbackInfo &args) {
Napi::Env env = args.Env();
Napi::EscapableHandleScope scope(env);
const int MY_MAGIC_NUMBER = 5;
Napi::Value jsresult =
SWIG_From_int(env, static_cast< int >(MY_MAGIC_NUMBER));
if (args.Length() != 0)
SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments.");
return scope.Escape(jsresult);
fail:
return Napi::Value();
}
#else /* Engine: JavaScriptCore */
static JSValueRef JavaScript_do_work(JSContextRef context,

View File

@ -4,7 +4,8 @@
%warnfilter(SWIGWARN_PARSE_KEYWORD) delete;
#if !defined(SWIGOCTAVE) && !defined(SWIG_JAVASCRIPT_V8) /* Octave and Javascript/v8 compiles wrappers as C++ */
/* Octave and Javascript/v8 compiles wrappers as C++ */
#if !defined(SWIGOCTAVE) && !defined(SWIG_JAVASCRIPT_V8) && !defined(SWIG_JAVASCRIPT_NAPI)
%inline %{
struct delete {

View File

@ -4,7 +4,8 @@
%warnfilter(SWIGWARN_PARSE_KEYWORD) delete;
#if !defined(SWIGOCTAVE) && !defined(SWIG_JAVASCRIPT_V8) /* Octave and Javascript/v8 compiles wrappers as C++ */
/* Octave and Javascript/v8 compiles wrappers as C++ */
#if !defined(SWIGOCTAVE) && !defined(SWIG_JAVASCRIPT_V8) && !defined(SWIG_JAVASCRIPT_NAPI)
%inline %{
double delete(double d) { return d; }

View File

@ -412,7 +412,6 @@ CPP_TEST_CASES += \
smart_pointer_protected \
smart_pointer_rename \
smart_pointer_simple \
smart_pointer_static \
smart_pointer_template_const_overload \
smart_pointer_template_defaults_overload \
smart_pointer_templatemethods \

View File

@ -1,7 +1,7 @@
%module enum_forward
/* This contains C code that is not valid C++03 and Octave, and Javascript(v8) wrappers are always compiled as C++ */
#if !defined(SWIGOCTAVE) && !defined(SWIG_JAVASCRIPT_V8)
#if !defined(SWIGOCTAVE) && !defined(SWIG_JAVASCRIPT_V8) && !defined(SWIG_JAVASCRIPT_NAPI)
%{
enum ForwardEnum1 { AAA, BBB };
enum ForwardEnum2 { CCC, DDD };

View File

@ -8,7 +8,7 @@ NODEJS = @NODEJS@
SCRIPTSUFFIX = _runme.js
OBJEXT = @OBJEXT@
SO = @SO@
GYP_CXXFLAGS = @BOOST_CPPFLAGS@ @PLATCXXFLAGS@
GYP_CXXFLAGS = @BOOST_CPPFLAGS@ @PLATCXXFLAGS@ -I$(shell npm config get prefix)/lib/node_modules/node-addon-api
HAVE_CXX11 = @HAVE_CXX11@
HAVE_CXX14 = @HAVE_CXX14@
@ -27,6 +27,9 @@ CPP_TEST_CASES += \
li_std_containers_int \
li_std_map_member
CPP_TEST_BROKEN += \
smart_pointer_static \
SWIGEXE = $(top_builddir)/swig
SWIG_LIB_DIR = $(top_srcdir)/Lib
@ -68,7 +71,8 @@ _setup = \
SWIGOPT += -$(JSENGINE)
ifeq (node,$(JSENGINE))
ifeq ($(JSENGINE), $(filter $(JSENGINE), node napi))
SWIGOPT += -DBUILDING_NODE_EXTENSION=1
# shut up some warnings
@ -81,11 +85,24 @@ ifeq (node,$(JSENGINE))
member_funcptr_galore.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
director_unwrap_result.cpptest: GYP_CFLAGS = \"-Wno-ignored-qualifiers\"
# Run with asan:
# ASAN=1 ENGINE=napi make <test_name>.cpptest
#
ifneq (, $(ASAN))
GYP_CFLAGS += \"-fsanitize=address\"
GYP_OPTS = --debug
ASAN_PRELOAD = $(shell $(CC) -print-file-name=libasan.so)
LSAN_OPTIONS = suppressions=$(srcdir)/node_template/napi-leaks-suppression.txt
BUILD = Debug
else
BUILD = Release
endif
setup_node = \
test -d $* || mkdir $* && \
sed -e 's|$$testcase|$*|g; s|$$cflags|$(GYP_CFLAGS)|g; s|$$cxxflags|"$(GYP_CXXFLAGS)"|g; s|$$srcdir|$(srcdir)|g' \
$(srcdir)/node_template/binding.gyp.in > $*/binding.gyp && \
sed -e 's|$$testcase|$*|g;' \
sed -e 's|$$testcase|$*|g; s|$$build|$(BUILD)|g;' \
$(srcdir)/node_template/index.js.in > $*/index.js
# Note: we need to use swig in C parse mode, but make node-gyp believe it is c++ (via file extension)
@ -94,18 +111,19 @@ ifeq (node,$(JSENGINE))
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile SRCDIR='$(SRCDIR)' \
SWIG_LIB_DIR='$(SWIG_LIB_DIR)' SWIGEXE='$(SWIGEXE)' \
SWIGOPT='-javascript $(SWIGOPT) -o $*_wrap.cxx $(srcdir)/../$*.i' swiginvoke && \
MAKEFLAGS= $(COMPILETOOL) $(NODEGYP) --loglevel=silent --directory $* configure build 1>>/dev/null
MAKEFLAGS= $(COMPILETOOL) $(NODEGYP) --loglevel=silent --directory $* configure $(GYP_OPTS) build 1>>/dev/null
swig_and_compile_cpp = \
$(setup_node) && \
$(MAKE) -f $(top_builddir)/$(EXAMPLES)/Makefile SRCDIR='$(SRCDIR)' \
SWIG_LIB_DIR='$(SWIG_LIB_DIR)' SWIGEXE='$(SWIGEXE)' \
SWIGOPT='-c++ -javascript $(SWIGOPT) $(srcdir)/../$*.i' swiginvoke && \
MAKEFLAGS= $(COMPILETOOL) $(NODEGYP) --loglevel=silent --directory $* configure build 1>>/dev/null
MAKEFLAGS= $(COMPILETOOL) $(NODEGYP) --loglevel=silent --directory $* configure $(GYP_OPTS) build 1>>/dev/null
run_testcase = \
if [ -f $(srcdir)/$*$(SCRIPTSUFFIX) ]; then \
env NODE_PATH=$$PWD:$(srcdir) $(RUNTOOL) $(NODEJS) $(srcdir)/$*$(SCRIPTSUFFIX); \
env NODE_PATH=$$PWD:$(srcdir) LD_PRELOAD=$(ASAN_PRELOAD) LSAN_OPTIONS=$(LSAN_OPTIONS) \
$(RUNTOOL) $(NODEJS) $(srcdir)/$*$(SCRIPTSUFFIX); \
fi

View File

@ -4,7 +4,7 @@ exception_thrown = false;
try {
catches_strings.StringsThrower.charstring();
} catch (e) {
if (!e.message.includes("charstring message"))
if (!(e.message || e).includes("charstring message"))
throw new Error("incorrect exception message " + e.message);
exception_thrown = true;
}
@ -15,7 +15,7 @@ exception_thrown = false;
try {
catches_strings.StringsThrower.stdstring();
} catch (e) {
if (!e.message.includes("stdstring message"))
if (!(e.message || e).includes("stdstring message"))
throw new Error("incorrect exception message " + e.message);
exception_thrown = true;
}

View File

@ -96,11 +96,11 @@ checkCount(0);
// overloaded parameters
if (li_std_auto_ptr.overloadTest() != 0)
throw new RuntimeException("overloadTest failed");
throw new Error("overloadTest failed");
if (li_std_auto_ptr.overloadTest(null) != 1)
throw new RuntimeException("overloadTest failed");
throw new Error("overloadTest failed");
if (li_std_auto_ptr.overloadTest(new li_std_auto_ptr.Klass("over")) != 1)
throw new RuntimeException("overloadTest failed");
throw new Error("overloadTest failed");
checkCount(0);

View File

@ -8,7 +8,14 @@ function check(flag) {
intPair = li_std_pair.makeIntPair(7, 6);
check(typeof intPair === 'object');
check(Object.keys(intPair).length == 2);
if (Object.keys(intPair).length) {
// When using raw V8, intPair will be an object with two properties
check(Object.keys(intPair).length == 2);
} else {
// When using NAPI, intPair will be an object of class intPair whose
// prototype will have two properties
check(Object.keys(Object.getPrototypeOf(intPair)).length == 2);
}
check(intPair.first === 7);
check(intPair.second === 6);

View File

@ -1 +1 @@
module.exports = require('./build/Release/$testcase');
module.exports = require('./build/$build/$testcase');

View File

@ -0,0 +1,2 @@
leak:Init
leak:napi_module_register

View File

@ -48,8 +48,35 @@ extern "C" JNIEXPORT jint JNICALL Java_native_1directive_native_1directiveJNI_Co
#ifdef SWIGJAVASCRIPT
%native(CountAlphaCharacters) void JavaScript_alpha_count();
#if defined(SWIG_JAVASCRIPT_NAPI) /* engine = napi */
%{
static Napi::Value JavaScript_alpha_count(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::EscapableHandleScope scope(env);
Napi::Value jsresult;
char *arg1 = (char *)0;
int res1;
char *buf1 = 0;
int alloc1 = 0;
int result;
if (info.Length() != 1) SWIG_exception_fail(SWIG_ERROR, "Illegal number of arguments for _wrap_alpha_count.");
res1 = SWIG_AsCharPtrAndSize(info[0], &buf1, NULL, &alloc1);
if (!SWIG_IsOK(res1))
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "alpha_count" "', argument " "1"" of type '" "char const *""'");
arg1 = reinterpret_cast< char * >(buf1);
result = (int)alpha_count((char const *)arg1);
jsresult = SWIG_From_int(env, static_cast< int >(result));
if (alloc1 == SWIG_NEWOBJ) delete[] buf1;
return scope.Escape(jsresult);
fail:
return Napi::Value();
}
%}
#elif defined(SWIG_JAVASCRIPT_V8) /* engine = node || v8 */
%{
#ifdef SWIG_V8_VERSION /* engine = node || v8 */
static SwigV8ReturnValue JavaScript_alpha_count(const SwigV8Arguments &args) {
SWIGV8_HANDLESCOPE();
@ -72,7 +99,9 @@ fail:
SWIGV8_RETURN(SWIGV8_UNDEFINED());
}
#else /* engine = jsc */
%}
#elif defined(SWIG_JAVASCRIPT_JSC) /* engine = jsc */
%{
static JSValueRef JavaScript_alpha_count(JSContextRef context, JSObjectRef function,
JSObjectRef thisObject, size_t argc, const JSValueRef argv[], JSValueRef* exception)
@ -96,7 +125,11 @@ fail:
return JSValueMakeUndefined(context);
}
#endif /* engine */
%}
#else
%{
#error No valid JS engine configured
%}
#endif /* engine */
#endif /* SWIGJAVASCRIPT */

View File

@ -13,7 +13,7 @@ Also tests reported error when a #define placed in a deeply embedded struct/unio
%rename(InUnNamed) OuterStructNamed::Inner_union_named;
#endif
#if defined(SWIG_JAVASCRIPT_V8)
#if defined(SWIG_JAVASCRIPT_V8) || defined(SWIG_JAVASCRIPT_NAPI)
%inline %{
#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)

View File

@ -1,6 +1,6 @@
%module nested_extend_c
#if defined(SWIG_JAVASCRIPT_V8)
#if defined(SWIG_JAVASCRIPT_V8) || defined(SWIG_JAVASCRIPT_NAPI)
%inline %{
#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
@ -16,7 +16,7 @@
#include "stdlib.h"
%}
#if !defined(SWIGOCTAVE) && !defined(SWIG_JAVASCRIPT_V8)
#if !defined(SWIGOCTAVE) && !defined(SWIG_JAVASCRIPT_V8) && !defined(SWIG_JAVASCRIPT_NAPI)
%extend hiA {
hiA() {
union hiA *self = (union hiA *)malloc(sizeof(union hiA));

View File

@ -1,6 +1,6 @@
%module nested_structs
#if defined(SWIG_JAVASCRIPT_V8)
#if defined(SWIG_JAVASCRIPT_V8) || defined(SWIG_JAVASCRIPT_NAPI)
%inline %{
#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)

View File

@ -18,6 +18,10 @@
%header %{
#define OUT_NULL_VALUE SWIGV8_NULL()
%}
#elif defined(SWIG_JAVASCRIPT_NAPI)
%header %{
#define OUT_NULL_VALUE env.Null()
%}
#else
%header %{
#define OUT_NULL_VALUE 0

View File

@ -0,0 +1,66 @@
/* ------------------------------------------------------------
* SWIG library containing argc and argv multi-argument typemaps
* ------------------------------------------------------------ */
%{
SWIGINTERN int SWIG_AsVal_string (Napi::Value valRef, Napi::String *str)
{
if (!valRef.IsString()) {
return SWIG_TypeError;
}
if(str != SWIG_NULLPTR) {
*str = valRef.ToString();
}
return SWIG_OK;
}
%}
%typemap(in) (int ARGC, char **ARGV) {
$1_ltype i, len;
size_t arraysize;
Napi::Array array;
if (!$input.IsArray()) {
SWIG_exception_fail(SWIG_ERROR, "not array");
}
array = $input.As<Napi::Array>();
len = array.Length();
arraysize = (len+1)*sizeof($*2_ltype);
$1 = len;
$2 = ($2_ltype) malloc(arraysize);
if ($2 == SWIG_NULLPTR) {
SWIG_exception_fail(SWIG_ERROR, "memory allocation of array failed");
}
memset($2, 0, arraysize);
for (i = 0; i < len; i++) {
int res, slen;
$*2_ltype pstr;
Napi::String napi_str;
Napi::Value jsvalue = array.Get(i);
res = SWIG_AsVal_string(jsvalue, &napi_str);
if (!SWIG_IsOK(res)) {
SWIG_exception_fail(SWIG_ERROR, "failed to convert to string");
}
std::string str = napi_str.Utf8Value();
slen = str.size();
pstr = ($*2_ltype) malloc(slen + 1);
if (pstr == SWIG_NULLPTR) {
SWIG_exception_fail(SWIG_ERROR, "memory allocation of a string failed");
}
if (slen) {
memcpy(pstr, str.c_str(), slen);
}
pstr[slen] = 0;
$2[i] = pstr;
}
$2[i] = SWIG_NULLPTR;
}
%typemap(freearg) (int ARGC, char **ARGV) {
if ($2 != SWIG_NULLPTR) {
$1_ltype i;
for (i = 0; i < $1; i++) {
free((void *)$2[i]);
}
free((void *)$2);
}
}

View File

@ -0,0 +1,88 @@
/* -----------------------------------------------------------------------------
* arrays_javascript.i
*
* These typemaps give more natural support for arrays. The typemaps are not efficient
* as there is a lot of copying of the array values whenever the array is passed to C/C++
* from JavaScript and vice versa. The JavaScript array is expected to be the same size as the C array.
* An exception is thrown if they are not.
*
* Example usage:
* Wrapping:
*
* %include <arrays_javascript.i>
* %inline %{
* extern int FiddleSticks[3];
* %}
*
* Use from JavaScript like this:
*
* var fs = [10, 11, 12];
* example.FiddleSticks = fs;
* fs = example.FiddleSticks;
* ----------------------------------------------------------------------------- */
%fragment("SWIG_NAPI_GetIntProperty", "header", fragment=SWIG_AsVal_frag(int)) {}
%fragment("SWIG_NAPI_GetNumberProperty", "header", fragment=SWIG_AsVal_frag(double)) {}
%fragment("SWIG_NAPI_OutInt", "header", fragment=SWIG_From_frag(int)) {}
%fragment("SWIG_NAPI_OutNumber", "header", fragment=SWIG_From_frag(double)) {}
%define JAVASCRIPT_ARRAYS_IN_DECL(NAME, CTYPE, ANY, ANYLENGTH)
%typemap(in, fragment=NAME) CTYPE[ANY] {
if ($input.IsArray()) {
Napi::Env env = $input.Env();
// Convert into Array
Napi::Array array = $input.As<Napi::Array>();
int length = ANYLENGTH;
$1 = ($*1_ltype *)malloc(sizeof($*1_ltype) * length);
// Get each element from array
for (int i = 0; i < length; i++) {
Napi::Value jsvalue = array.Get(i);
$*1_ltype temp;
// Get primitive value from JSObject
int res = SWIG_AsVal(CTYPE)(jsvalue, &temp);
if (!SWIG_IsOK(res)) {
SWIG_Error(SWIG_ERROR, "Failed to convert $input to double");
}
arg$argnum[i] = temp;
}
} else {
Napi::Env env = $input.Env();
SWIG_Error(SWIG_ERROR, "$input is not an array");
}
}
%typemap(freearg) CTYPE[ANY] {
free($1);
}
%enddef
%define JAVASCRIPT_ARRAYS_OUT_DECL(NAME, CTYPE)
%typemap(out, fragment=NAME) CTYPE[ANY] {
int length = $1_dim0;
Napi::Array array = Napi::Array::New(env, length);
for (int i = 0; i < length; i++) {
array.Set(i, SWIG_From(CTYPE)($1[i]));
}
$result = array;
}
%enddef
JAVASCRIPT_ARRAYS_IN_DECL("SWIG_NAPI_GetIntProperty", int, , array.Length())
JAVASCRIPT_ARRAYS_IN_DECL("SWIG_NAPI_GetIntProperty", int, ANY, $1_dim0)
JAVASCRIPT_ARRAYS_IN_DECL("SWIG_NAPI_GetNumberProperty", double, , array.Length())
JAVASCRIPT_ARRAYS_IN_DECL("SWIG_NAPI_GetNumberProperty", double, ANY, $1_dim0)
JAVASCRIPT_ARRAYS_OUT_DECL("SWIG_NAPI_OutInt", int)
JAVASCRIPT_ARRAYS_OUT_DECL("SWIG_NAPI_OutNumber", double)

View File

@ -0,0 +1,27 @@
/* -----------------------------------------------------------------------------
* ccomplex.i
*
* C complex typemaps
* ISO C99: 7.3 Complex arithmetic <complex.h>
* ----------------------------------------------------------------------------- */
%include <javascriptcomplex.swg>
%{
#include <complex.h>
%}
#define complex _Complex
/* C complex constructor */
#define CCplxConst(r, i) ((r) + I*(i))
%swig_cplxflt_convn(float _Complex, CCplxConst, creal, cimag);
%swig_cplxdbl_convn(double _Complex, CCplxConst, creal, cimag);
%swig_cplxdbl_convn(_Complex, CCplxConst, creal, cimag);
/* declaring the typemaps */
%typemaps_primitive(SWIG_TYPECHECK_CPLXFLT, float _Complex);
%typemaps_primitive(SWIG_TYPECHECK_CPLXDBL, double _Complex);
%typemaps_primitive(SWIG_TYPECHECK_CPLXDBL, _Complex);

View File

@ -0,0 +1 @@
%include <typemaps/cdata.swg>

View File

@ -0,0 +1 @@
%include <typemaps/cmalloc.swg>

View File

@ -0,0 +1,6 @@
#ifdef __cplusplus
%include <std_complex.i>
#else
%include <ccomplex.i>
#endif

View File

@ -0,0 +1 @@
%include <typemaps/exception.swg>

View File

@ -0,0 +1 @@
%include <typemaps/factory.swg>

View File

@ -0,0 +1,17 @@
/* -----------------------------------------------------------------------------
* javascript.swg
*
* Javascript typemaps
* ----------------------------------------------------------------------------- */
%include <typemaps/swigmacros.swg>
%include <javascripttypemaps.swg>
%include <javascriptruntime.swg>
%include <javascriptkw.swg>
%include <javascriptcode.swg>
%include <javascriptinit.swg>

View File

@ -0,0 +1,880 @@
/* -----------------------------------------------------------------------------
* js_ctor: template for wrapping a ctor.
* - $jswrapper: wrapper of called ctor
* - $jsparent: mangled name of parent (or SWIG_NAPI_ObjectWrap if none)
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* - $jsargcount: number of arguments
* - $jsargrequired: minimum number of arguments
* - $jsmangledname: mangled name of class
* - $jsmangledtype: mangled type of class
* ----------------------------------------------------------------------------- */
%fragment("js_ctor", "templates") %{
template <typename SWIG_OBJ_WRAP>
// js_ctor
// This is the main constructor
$jsmangledname_templ<SWIG_OBJ_WRAP>::$jsmangledname_templ(const Napi::CallbackInfo &info)
: $jsparent_templ<SWIG_OBJ_WRAP>(true, info) {
Napi::Env env = info.Env();
this->info = SWIGTYPE_$jsmangledtype;
if (info.Length() == 1 && info[0].IsExternal()) {
// This constructor has been called internally from C++/SWIG
// to wrap an already existing C++ object in JS
this->self = info[0].As<Napi::External<void>>().Data();
this->owned = false;
return;
}
this->owned = true;
$jslocals
if(static_cast<int>(info.Length()) < $jsargrequired || static_cast<int>(info.Length()) > $jsargcount) {
SWIG_Error(SWIG_ERROR, "Illegal number of arguments for $jswrapper.");
}
$jscode
this->self = result;
return;
goto fail;
fail:
return;
}
// This is the bypass constructor to be used from child classes
template <typename SWIG_OBJ_WRAP>
$jsmangledname_templ<SWIG_OBJ_WRAP>::$jsmangledname_templ(bool, const Napi::CallbackInfo &info)
: $jsparent_templ<SWIG_OBJ_WRAP>(true, info) {}
%}
/* -----------------------------------------------------------------------------
* js_veto_ctor: a vetoing ctor for abstract classes
* - $jsmangledname: mangled name of class
* - $jsparent: mangled name of parent (or SWIG_NAPI_ObjectWrap if none)
* ----------------------------------------------------------------------------- */
%fragment ("js_veto_ctor", "templates")
%{
// js_veto_ctor
template <typename SWIG_OBJ_WRAP>
$jsmangledname_templ<SWIG_OBJ_WRAP>::$jsmangledname_templ(const Napi::CallbackInfo &info)
: $jsparent_templ<SWIG_OBJ_WRAP>(true, info) {
Napi::Env env = info.Env();
if (info.Length() == 1 && info[0].IsExternal()) {
// This constructor has been called internally from C++/SWIG
// to wrap an already existing C++ object in JS as its
// base abstract class
this->self = info[0].As<Napi::External<void>>().Data();
this->owned = false;
return;
}
SWIG_Error(SWIG_ERROR, "Class $jsname can not be instantiated");
return;
goto fail;
fail:
return;
}
// This is the extendable constructor to be used from child classes
template <typename SWIG_OBJ_WRAP>
$jsmangledname_templ<SWIG_OBJ_WRAP>::$jsmangledname_templ(bool, const Napi::CallbackInfo &info)
: $jsparent_templ<SWIG_OBJ_WRAP>(true, info) {
}
%}
/* -----------------------------------------------------------------------------
* js_ctor_dispatcher: dispatcher for overloaded constructors
* - $jsmangledname: mangled name of class
* - $jsparent: mangled name of parent (or SWIG_NAPI_ObjectWrap if none)
* - $jsdispatchcases: part containing code for dispatching
* - $jsmangledtype: mangled type of class
* ----------------------------------------------------------------------------- */
%fragment ("js_ctor_dispatcher", "templates")
%{
// js_ctor_dispatcher
template <typename SWIG_OBJ_WRAP>
$jsmangledname_templ<SWIG_OBJ_WRAP>::$jsmangledname_templ(const Napi::CallbackInfo &info)
: $jsparent_templ<SWIG_OBJ_WRAP>(true, info) {
Napi::Env env = info.Env();
Napi::Object self;
NAPI_CHECK_RESULT(info.This().ToObject(), self);
this->info = SWIGTYPE_$jsmangledtype;
if (info.Length() == 1 && info[0].IsExternal()) {
// This constructor has been called internally from C++/SWIG
// to wrap an already existing C++ object in JS
this->self = info[0].As<Napi::External<void>>().Data();
this->owned = false;
return;
}
// switch all cases by means of series of if-returns.
$jsdispatchcases
// default:
SWIG_Error(SWIG_ERROR, "Illegal arguments for construction of $jsmangledname");
goto fail;
fail:
return;
}
// This is the extendable constructor to be used from child classes
template <typename SWIG_OBJ_WRAP>
$jsmangledname_templ<SWIG_OBJ_WRAP>::$jsmangledname_templ(bool, const Napi::CallbackInfo &info)
: $jsparent_templ<SWIG_OBJ_WRAP>(true, info) {
}
%}
/* -----------------------------------------------------------------------------
* js_overloaded_ctor: template for wrapping a ctor.
* - $jswrapper: wrapper of called ctor
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* - $jsargcount: number of arguments
* - $jsargrequired: minimum number of arguments
* - $jsmangledtype: mangled type of class
* ----------------------------------------------------------------------------- */
%fragment("js_overloaded_ctor", "templates") %{
// js_overloaded_ctor
template <typename SWIG_OBJ_WRAP>
Napi::Value $jsmangledname_templ<SWIG_OBJ_WRAP>::$jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Object self;
$jslocals
NAPI_CHECK_RESULT(info.This().ToObject(), self);
this->owned = true;
if(static_cast<int>(info.Length()) < $jsargrequired || static_cast<int>(info.Length()) > $jsargcount) {
SWIG_Error(SWIG_ERROR, "Illegal number of arguments for $jswrapper.");
}
$jscode
this->self = result;
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* js_ctor_dispatch_case: template for a dispatch case for calling an overloaded ctor.
* - $jsargcount: number of arguments of called ctor
* - $jsargrequired: minimum number of arguments
* - $jswrapper: wrapper of called ctor
*
* Note: a try-catch-like mechanism is used to switch cases
* ----------------------------------------------------------------------------- */
%fragment ("js_ctor_dispatch_case", "templates")
%{
// js_ctor_dispatch_case
if(static_cast<int>(info.Length()) >= $jsargrequired && static_cast<int>(info.Length()) <= $jsargcount) {
#ifdef NAPI_CPP_EXCEPTIONS
bool tryNext = false;
try {
$jswrapper(info);
} catch (const Napi::TypeError &) {
tryNext = true;
} catch (const Napi::Error &e) {
throw e;
}
if (!tryNext)
return;
#else
$jswrapper(info);
if (env.IsExceptionPending()) {
Napi::Error e = env.GetAndClearPendingException();
Napi::Value typeErrorValue;
bool isTypeError;
Napi::Function typeErrorCons;
// Yes, this is ugly
// TODO: Fix this in Node.js when the core team grows up
NAPI_CHECK_RESULT(env.Global().Get("TypeError"), typeErrorValue);
typeErrorCons = typeErrorValue.As<Napi::Function>();
NAPI_CHECK_RESULT(e.Value().InstanceOf(typeErrorCons), isTypeError);
if (!isTypeError) {
// This is not the error you are looking for
e.ThrowAsJavaScriptException();
SWIG_fail;
}
} else {
return;
}
#endif
}
%}
/* -----------------------------------------------------------------------------
* js_check_arg: template for checking if an argument exists
* - $jsarg: number of argument
* ----------------------------------------------------------------------------- */
%fragment ("js_check_arg", "templates")
%{if(info.Length() > $jsarg)%}
/* -----------------------------------------------------------------------------
* js_dtor: template for a destructor wrapper
* - $jsmangledname: mangled class name
* - $jstype: class type
* ----------------------------------------------------------------------------- */
%fragment ("js_dtor", "templates")
%{
// js_dtor
template <typename SWIG_OBJ_WRAP>
$jsmangledname_templ<SWIG_OBJ_WRAP>::~$jsmangledname_templ() {
}
%}
/* -----------------------------------------------------------------------------
* js_dtoroverride: template for a destructor wrapper
* - ${classname_mangled}: mangled class name
* - $jstype: class type
* - ${destructor_action}: The custom destructor action to invoke.
* ----------------------------------------------------------------------------- */
%fragment ("js_dtoroverride", "templates")
%{
// js_dtoroverride
template <typename SWIG_OBJ_WRAP>
${classname_mangled}_templ<SWIG_OBJ_WRAP>::~${classname_mangled}_templ() {
auto arg1 = reinterpret_cast<$jstype>(this->self);
if (this->owned && arg1) {
${destructor_action}
this->self = nullptr;
}
}
%}
/* -----------------------------------------------------------------------------
* js_global_getter: template for global getter function wrappers
* - $jswrapper: wrapper function name
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment("js_global_getter", "templates")
%{
// js_global_getter
Napi::Value $jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jslocals
$jscode
return jsresult;
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* js_global_setter: template for global setter function wrappers
* - $jswrapper: wrapper function name
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment("js_global_setter", "templates")
%{
// js_global_setter
void $jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value value = info.Length() > 0 ? info[0] : Napi::Value();
Napi::Value jsresult;
$jslocals
$jscode
return;
goto fail;
fail:
return;
}
%}
/* -----------------------------------------------------------------------------
* jsnapi_register_global_variable: template for a statement that registers a global variable
* - $jsname: variable name
* - $jsparent: parent namespace
* - $jsgetter: wrapper of the getter function
* - $jssetter: wrapper of the setter function
*
* Note: this template is also used for global variables.
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_register_global_variable", "templates")
%{
// jsnapi_register_global_variable
do {
Napi::PropertyDescriptor pd = Napi::PropertyDescriptor::Accessor<$jsgetter, $jssetter>("$jsname");
NAPI_CHECK_MAYBE($jsparent.DefineProperties({pd}));
} while (0);
%}
/* -----------------------------------------------------------------------------
* js_global_function: template for function wrappers
* - $jswrapper: wrapper function name
* - $jslocals: locals part of wrapper
* - $jsargcount: number of arguments
* - $jsargrequired: minimum number of arguments
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment("js_global_function", "templates")
%{
// js_global_function
Napi::Value $jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jslocals
if(static_cast<int>(info.Length()) < $jsargrequired || static_cast<int>(info.Length()) > $jsargcount) {
SWIG_Error(SWIG_ERROR, "Illegal number of arguments for $jswrapper.");
}
$jscode
return jsresult;
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* js_global_function_dispatcher: template for a global function dispatcher for
* global overloaded functions
* - $jswrapper: wrapper function name
* - $jsname: name of the wrapped function
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment("js_global_function_dispatcher", "templates")
%{
// js_global_function_dispatcher
Napi::Value $jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jscode
SWIG_Error(SWIG_ERROR, "Illegal arguments for function $jsname.");
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* jsnapi_register_global_function: template for a statement that registers a global function
* - $jsname: function name
* - $jsparent: parent namespace
* - $jswrapper: name of the JS wrapper
*
* Note: this template is also used for global variables.
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_register_global_function", "templates")
%{
// jsnapi_register_global_function
do {
Napi::PropertyDescriptor pd = Napi::PropertyDescriptor::Function("$jsname", $jswrapper);
NAPI_CHECK_MAYBE($jsparent.DefineProperties({pd}));
} while (0);
%}
/* -----------------------------------------------------------------------------
* js_getter: template for getter function wrappers
* - $jsmangledname: mangled class name
* - $jswrapper: wrapper function name
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment("js_getter", "templates")
%{
// js_getter
template <typename SWIG_OBJ_WRAP>
Napi::Value $jsmangledname_templ<SWIG_OBJ_WRAP>::$jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jslocals
$jscode
return jsresult;
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* js_setter: template for setter function wrappers
* - $jsmangledname: mangled class name
* - $jswrapper: wrapper function name
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment("js_setter", "templates")
%{
// js_setter
template <typename SWIG_OBJ_WRAP>
void $jsmangledname_templ<SWIG_OBJ_WRAP>::$jswrapper(const Napi::CallbackInfo &info, const Napi::Value &value) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jslocals
$jscode
return;
goto fail;
fail:
return;
}
%}
/* -----------------------------------------------------------------------------
* js_function: template for function wrappers
* - $jsmangledname: mangled class name
* - $jswrapper: wrapper function name
* - $jsargcount: minimum number of arguments
* - $jsargrequired: minimum number of arguments
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment("js_function", "templates")
%{
// js_function
template <typename SWIG_OBJ_WRAP>
Napi::Value $jsmangledname_templ<SWIG_OBJ_WRAP>::$jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jslocals
if(static_cast<int>(info.Length()) < $jsargrequired || static_cast<int>(info.Length()) > $jsargcount) {
SWIG_Error(SWIG_ERROR, "Illegal number of arguments for $jswrapper.");
}
$jscode
return jsresult;
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* js_function_dispatcher: template for a function dispatcher for overloaded functions
* - $jsmangledname: mangled class name
* - $jswrapper: wrapper function name
* - $jsname: name of the wrapped function
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment("js_function_dispatcher", "templates")
%{
// js_function_dispatcher
template <typename SWIG_OBJ_WRAP>
Napi::Value $jsmangledname_templ<SWIG_OBJ_WRAP>::$jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jscode
SWIG_Error(SWIG_ERROR, "Illegal arguments for function $jsname.");
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* js_overloaded_function: template for a overloaded function
* - $jswrapper: wrapper function name
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment ("js_overloaded_function", "templates")
%{
// js_overloaded_function
template <typename SWIG_OBJ_WRAP>
Napi::Value $jsmangledname_templ<SWIG_OBJ_WRAP>::$jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jslocals
$jscode
return jsresult;
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* js_global_overloaded_function: template for a global overloaded function
* - $jswrapper: wrapper function name
* - $jslocals: locals part of wrapper
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment ("js_global_overloaded_function", "templates")
%{
// js_global_overloaded_function
Napi::Value $jswrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
$jslocals
$jscode
return jsresult;
goto fail;
fail:
return Napi::Value();
}
%}
/* -----------------------------------------------------------------------------
* js_function_dispatch_case: template for a case used in the function dispatcher
* - $jswrapper: wrapper function name
* - $jsargcount: number of arguments of overloaded function
* - $jsargrequired: minimum number of arguments
* - $jscode: code part of wrapper
* ----------------------------------------------------------------------------- */
%fragment ("js_function_dispatch_case", "templates")
%{
// js_function_dispatch_case
if(static_cast<int>(info.Length()) >= $jsargrequired && static_cast<int>(info.Length()) <= $jsargcount) {
#ifdef NAPI_CPP_EXCEPTIONS
bool tryNext = false;
try {
jsresult = $jswrapper(info);
} catch (const Napi::TypeError &) {
tryNext = true;
} catch (const Napi::Error &e) {
throw e;
}
if (!tryNext)
return jsresult;
#else
$jswrapper(info);
if (env.IsExceptionPending()) {
Napi::Error e = env.GetAndClearPendingException();
Napi::Value typeErrorValue;
bool isTypeError;
Napi::Function typeErrorCons;
// Yes, this is ugly
// TODO: Fix this in Node.js when the core team grows up
NAPI_CHECK_RESULT(env.Global().Get("TypeError"), typeErrorValue);
typeErrorCons = typeErrorValue.As<Napi::Function>();
NAPI_CHECK_RESULT(e.Value().InstanceOf(typeErrorCons), isTypeError);
if (!isTypeError) {
// This is not the error you are looking for
e.ThrowAsJavaScriptException();
SWIG_fail;
}
} else {
return jsresult;
}
#endif
}
%}
/* -----------------------------------------------------------------------------
* jsnapi_class_prologue_template: template for a class prologue
* - $jsmangledname: mangled class name
* - $jsparent: mangled name of parent (or SWIG_NAPI_ObjectWrap if none)
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_class_prologue_template", "templates")
%{
// jsnapi_class_prologue_template
template <typename SWIG_OBJ_WRAP>
class $jsmangledname_templ : public $jsparent_templ<SWIG_OBJ_WRAP> {
public:
$jsmangledname_templ(const Napi::CallbackInfo &);
$jsmangledname_templ(bool, const Napi::CallbackInfo &);
%}
/* -----------------------------------------------------------------------------
* jsnapi_class_dtor_declaration: template for a class destructor declaration
* - $jsmangledname: mangled class name
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_class_dtor_declaration", "templates")
%{
virtual ~$jsmangledname_templ();
%}
/* -----------------------------------------------------------------------------
* jsnapi_class_method_declaration: template for a class method declaration
* - $jsmangledname: mangled class name
* - $jswrapper: method name
* - $jsstatic: static modifier
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_class_method_declaration", "templates")
%{
// jsnapi_class_method_declaration
$jsstatic Napi::Value $jswrapper(const Napi::CallbackInfo &);
%}
/* -----------------------------------------------------------------------------
* jsnapi_class_setter_declaration: template for a class method declaration
* - $jsmangledname: mangled class name
* - $jswrapper: method name
* - $jsstatic: static modifier
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_class_setter_declaration", "templates")
%{
// jsnapi_class_setter_declaration
$jsstatic void $jswrapper(const Napi::CallbackInfo &, const Napi::Value &);
%}
/* -----------------------------------------------------------------------------
* jsnapi_class_epilogue_template: template for a class epilogue
* - $jsmangledname: mangled class name
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_class_epilogue_template", "templates")
%{
// jsnapi_class_epilogue_template
static void JS_veto_set_static_variable(const Napi::CallbackInfo &, const Napi::Value &);
void JS_veto_set_variable(const Napi::CallbackInfo &, const Napi::Value &);
};
template <typename SWIG_OBJ_WRAP>
void $jsmangledname_templ<SWIG_OBJ_WRAP>::JS_veto_set_static_variable(const Napi::CallbackInfo &info, const Napi::Value &value) {
SWIG_NAPI_Raise(info.Env(), "Tried to write read-only variable.");
}
template <typename SWIG_OBJ_WRAP>
void $jsmangledname_templ<SWIG_OBJ_WRAP>::JS_veto_set_variable(const Napi::CallbackInfo &info, const Napi::Value &value) {
SWIG_NAPI_Raise(info.Env(), "Tried to write read-only variable.");
}
%}
/* -----------------------------------------------------------------------------
* jsnapi_class_instance: template for a class declaration instance
* - $jsmangledname: mangled class name
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_declare_class_instance", "templates")
%{
// jsnapi_class_instance
class $jsmangledname_inst : public $jsmangledname_templ<$jsmangledname_inst> {
public:
using $jsmangledname_templ::$jsmangledname_templ;
virtual ~$jsmangledname_inst() {};
static void GetMembers(
Napi::Env,
std::map<std::string, $jsmangledname_templ::PropertyDescriptor> &,
std::map<std::string, $jsmangledname_templ::PropertyDescriptor> &
);
static Napi::Function GetClass(Napi::Env);
};
%}
/*
* Inheritance is still not officially supported in NAPI
* Refer to this for my workaround:
* https://mmomtchev.medium.com/c-class-inheritance-with-node-api-and-node-addon-api-c180334d9902
*/
/* -----------------------------------------------------------------------------
* jsnapi_inherited_class_prologue_template: template for a class prologue
* - $jsmangledname: mangled class name
* - $jsparent: mangled name of parent class
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_inherited_class_prologue_template", "templates")
%{
// jsnapi_inherited_class_prologue_template
SWIG_NAPI_ClientData $jsmangledname_clientData;
template <typename SWIG_OBJ_WRAP>
class $jsmangledname_templ : public $jsparent_templ<SWIG_OBJ_WRAP> {
public:
$jsmangledname_templ(const Napi::CallbackInfo& info);
%}
/* -----------------------------------------------------------------------------
* jsnapi_getclass: template for creating a class object
* - $jsname: class name
* - $jsmangledname: mangled class name
* - $jsfunctions: member functions
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_getclass", "templates")
%{
/* Class: $jsname ($jsmangledname) */
// jsnapi_getclass
Napi::Function $jsmangledname_inst::GetClass(Napi::Env env) {
std::map<std::string, $jsmangledname_templ::PropertyDescriptor> members, staticMembers;
GetMembers(env, members, staticMembers);
std::vector<$jsmangledname_inst::PropertyDescriptor> symbolTable;
for (auto it = members.begin(); it != members.end(); it++)
symbolTable.push_back(it->second);
for (auto it = staticMembers.begin(); it != staticMembers.end(); it++)
symbolTable.push_back(it->second);
return Napi::ObjectWrap<$jsmangledname_inst>::DefineClass(env, "$jsname", symbolTable);
}
void $jsmangledname_inst::GetMembers(
Napi::Env env,
std::map<std::string, $jsmangledname_templ::PropertyDescriptor> &members,
std::map<std::string, $jsmangledname_templ::PropertyDescriptor> &staticMembers
) {
std::map<std::string, $jsparent_templ<$jsparent_inst>::PropertyDescriptor> baseMembers, baseStaticMembers;
$jsparent_inst::GetMembers(env, baseMembers, baseStaticMembers);
members.insert(baseMembers.begin(), baseMembers.end());
staticMembers.insert(staticMembers.begin(), staticMembers.end());
/* register wrapper functions */
$jsnapiwrappers
/* add static class functions and variables */
$jsnapistaticwrappers
}
%}
/* -----------------------------------------------------------------------------
* jsnapi_registerclass: template for regsitering a class object
* - $jsname: class name
* - $jsmangledname: mangled class name
* - $jsparent: parent namespace
* - $jsmangledtype: mangled class type
* - $jsclassidx: class index in the class table
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_registerclass", "templates")
%{
/* Class: $jsname ($jsmangledname) */
// jsnapi_registerclass
Napi::Function $jsmangledname_ctor = $jsmangledname_inst::GetClass(env);
$jsparent.Set("$jsname", $jsmangledname_ctor);
if (SWIGTYPE_$jsmangledtype->clientdata == nullptr) {
SWIGTYPE_$jsmangledtype->clientdata = new size_t($jsclassidx);
}
Napi::FunctionReference *$jsmangledname_ctor_ref = new Napi::FunctionReference();
*$jsmangledname_ctor_ref = Napi::Persistent($jsmangledname_ctor);
env.GetInstanceData<EnvInstanceData>()->ctor[$jsclassidx] = $jsmangledname_ctor_ref;
%}
/* -----------------------------------------------------------------------------
* jsnapi_setup_inheritance: setup inheritance between two classes
* - $jsname: class name
* - $jsmangledname: mangled class name
* - $jsparent: mangled name of parent class
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_setup_inheritance", "templates")
%{
// Inheritance for $jsmangledname ($jsname) <- $jsparent
// jsnapi_setup_inheritance
do {
Napi::Value protoBase, protoSub;
NAPI_CHECK_RESULT($jsmangledname_ctor.Get("prototype"), protoSub);
NAPI_CHECK_RESULT($jsparent_ctor.Get("prototype"), protoBase);
NAPI_CHECK_MAYBE(setProto.Call({$jsmangledname_ctor, $jsparent_ctor}));
NAPI_CHECK_MAYBE(setProto.Call({protoSub, protoBase}));
} while (0);
%}
/* -----------------------------------------------------------------------------
* jsnapi_create_namespace: template for a statement that creates a namespace object.
* - $jsmangledname: mangled namespace name
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_create_namespace", "templates")
%{
// jsnapi_create_namespace
Napi::Object $jsmangledname = Napi::Object::New(env);
%}
/* -----------------------------------------------------------------------------
* jsnapi_register_namespace: template for a statement that registers a namespace in a parent namespace.
* - $jsname: name of namespace
* - $jsmangledname: mangled name of namespace
* - $jsparent: mangled name of parent namespace
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_register_namespace", "templates")
%{
// jsnapi_register_namespace
NAPI_CHECK_MAYBE($jsparent.Set("$jsname", $jsmangledname));
%}
/* -----------------------------------------------------------------------------
* jsnapi_member_function_descriptor: template for a statement that registers a member function.
* - $jsmangledname: mangled class name
* - $jsname: name of the function
* - $jswrapper: wrapper of the member function
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_register_member_function", "templates")
%{
// jsnapi_member_function_descriptor
members.erase("$jsname");
members.insert({"$jsname",
$jsmangledname_templ::InstanceMethod("$jsname",
&$jsmangledname_templ::$jswrapper,
static_cast<napi_property_attributes>(napi_writable | napi_configurable))
});
%}
/* -----------------------------------------------------------------------------
* jsnapi_register_member_variable: template for a statement that registers a member variable.
* - $jsname: name of the function
* - $jsmangledname: mangled class name
* - $jsgetter: wrapper of the getter function
* - $jssetter: wrapper of the setter function
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_register_member_variable", "templates")
%{
// jsnapi_register_member_variable
members.erase("$jsname");
members.insert({"$jsname",
$jsmangledname_templ::InstanceAccessor("$jsname",
&$jsmangledname_templ::$jsgetter,
&$jsmangledname_templ::$jssetter,
static_cast<napi_property_attributes>(napi_writable | napi_enumerable | napi_configurable))
});
%}
/* -----------------------------------------------------------------------------
* jsnapi_register_static_function: template for a statement that registers a static class function.
* - $jsname: function name
* - $jsmangledname: mangled class name
* - $jswrapper: wrapper of the function
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_register_static_function", "templates")
%{
// jsnapi_register_static_function
staticMembers.erase("$jsname");
staticMembers.insert({"$jsname",
StaticMethod("$jsname",
&$jsmangledname_templ::$jswrapper,
static_cast<napi_property_attributes>(napi_writable | napi_configurable))
});
%}
/* -----------------------------------------------------------------------------
* jsnapi_register_static_variable: template for a statement that registers a static variable.
* - $jsname: variable name
* - $jsmangledname: mangled class name
* - $jsgetter: wrapper of the getter function
* - $jssetter: wrapper of the setter function
* ----------------------------------------------------------------------------- */
%fragment("jsnapi_register_static_variable", "templates")
%{
// jsnapi_register_static_variable
staticMembers.erase("$jsname");
staticMembers.insert({"$jsname",
StaticAccessor("$jsname",
&$jsmangledname_templ::$jsgetter,
&$jsmangledname_templ::$jssetter,
static_cast<napi_property_attributes>(napi_writable | napi_enumerable | napi_configurable))
});
%}

View File

@ -0,0 +1,116 @@
/*
Defines the As/From converters for double/float complex, you need to
provide complex Type, the Name you want to use in the converters,
the complex Constructor method, and the Real and Imag complex
accessor methods.
See the std_complex.i and ccomplex.i for concrete examples.
*/
/* the common from converter */
%define %swig_fromcplx_conv(Type, Real, Imag)
%fragment(SWIG_From_frag(Type),"header",
fragment=SWIG_From_frag(double))
{
SWIGINTERNINLINE Napi::Value
SWIG_From_dec(Type)(%ifcplusplus(const Type&, Type) c)
{
Napi::Array vals = Napi::Array::New(0);
vals.Set(0, SWIG_From(double)(Real(c)));
vals.Set(1, SWIG_From(double)(Imag(c)));
return vals;
}
}
%enddef
/* the double case */
%define %swig_cplxdbl_conv(Type, Constructor, Real, Imag)
%fragment(SWIG_AsVal_frag(Type),"header",
fragment=SWIG_AsVal_frag(double))
{
SWIGINTERN int
SWIG_AsVal_dec(Type) (Napi::Value o, Type* val)
{
if (o.IsArray()) {
Napi::Array array = Napi::Array::Cast(o);
if (array->Length() != 2) SWIG_Error(SWIG_TypeError, "Illegal argument for complex: must be array[2].");
double re, im;
Napi::Value r;
r = array.Get(0);
if (!r.IsNumber()) {
return SWIG_TypeError;
}
re = r.ToNumber().DoubleValue();
r = array.Get(1);
if (!r.IsNumber()) {
return SWIG_TypeError;
}
im = r.ToNumber().DoubleValue();
if (val) *val = Constructor(re, im);
return SWIG_OK;
} else if (o.IsNumber()) {
double d = o.ToNumber().DoubleValue();
if (val) *val = Constructor(d, 0.0);
return SWIG_OK;
}
return SWIG_TypeError;
}
}
%swig_fromcplx_conv(Type, Real, Imag);
%enddef
/* the float case */
%define %swig_cplxflt_conv(Type, Constructor, Real, Imag)
%fragment(SWIG_AsVal_frag(Type),"header",
fragment=SWIG_AsVal_frag(float)) {
SWIGINTERN int
SWIG_AsVal_dec(Type) (Napi::Value o, Type* val)
{
if (o.IsArray()) {
Napi::Array array = o.As<Napi::Array>();
if (array.Length() != 2) SWIG_Error(SWIG_TypeError, "Illegal argument for complex: must be array[2].");
double re, im;
Napi::Value r;
r = array.Get(0);
if (!r.IsNumber()) {
return SWIG_TypeError;
}
re = r.ToNumber().DoubleValue();
r = array.Get(1);
if (!r.IsNumber()) {
return SWIG_TypeError;
}
im = r.ToNumber().DoubleValue();
if ((-FLT_MAX <= re && re <= FLT_MAX) && (-FLT_MAX <= im && im <= FLT_MAX)) {
if (val) *val = Constructor(%numeric_cast(re, float),
%numeric_cast(im, float));
return SWIG_OK;
} else {
return SWIG_OverflowError;
}
} else if (o.IsNumber()) {
float f = static_cast<float>(o.ToNumber().DoubleValue());
if (val) *val = Constructor(f, 0.0);
return SWIG_OK;
}
return SWIG_TypeError;
}
}
%swig_fromcplx_conv(Type, Real, Imag);
%enddef
#define %swig_cplxflt_convn(Type, Constructor, Real, Imag) \
%swig_cplxflt_conv(Type, Constructor, Real, Imag)
#define %swig_cplxdbl_convn(Type, Constructor, Real, Imag) \
%swig_cplxdbl_conv(Type, Constructor, Real, Imag)

View File

@ -0,0 +1,23 @@
/*
Create a file with this name, 'javascriptfragments.swg', in your working
directory and add all the %fragments you want to take precedence
over the default ones defined by swig.
For example, if you add:
%fragment(SWIG_AsVal_frag(int),"header") {
SWIGINTERNINLINE int
SWIG_AsVal(int)(PyObject *obj, int *val)
{
<your code here>;
}
}
this will replace the code used to retrieve an integer value for all
the typemaps that need it, including:
int, std::vector<int>, std::list<std::pair<int,int> >, etc.
*/

View File

@ -0,0 +1,111 @@
%insert(header) %{
#include <assert.h>
%}
%insert(init) %{
EnvInstanceData::EnvInstanceData(Napi::Env env, swig_module_info *swig_module) :
env(env), SWIG_NAPI_ObjectWrapCtor(nullptr), ctor(nullptr), swig_module(swig_module) {
ctor = new Napi::FunctionReference*[swig_module->size + 1];
for (size_t i = 0; i <= swig_module->size; i++) {
ctor[i] = nullptr;
}
}
EnvInstanceData::~EnvInstanceData() {
for (size_t i = 0; i <= swig_module->size; i++) {
if (ctor[i] != nullptr)
delete ctor[i];
ctor[i] = nullptr;
}
delete [] ctor;
delete SWIG_NAPI_ObjectWrapCtor;
}
SWIGRUNTIME void
SWIG_NAPI_SetModule(Napi::Env env, swig_module_info *swig_module) {
auto data = new EnvInstanceData(env, swig_module);
env.SetInstanceData(data);
}
SWIGRUNTIME swig_module_info *
SWIG_NAPI_GetModule(Napi::Env env) {
auto data = env.GetInstanceData<EnvInstanceData>();
if (data == nullptr) return nullptr;
return data->swig_module;
}
#define SWIG_GetModule(clientdata) SWIG_NAPI_GetModule(clientdata)
#define SWIG_SetModule(clientdata, pointer) SWIG_NAPI_SetModule(clientdata, pointer)
#define SWIG_INIT_CLIENT_DATA_TYPE Napi::Env
%}
%insert(init) "swiginit.swg"
// Open the initializer function definition here
%fragment ("js_initializer_define", "templates") %{
#define SWIG_NAPI_INIT $jsname_initialize
%}
%insert(init) %{
Napi::Object Init(Napi::Env env, Napi::Object exports) {
SWIG_InitializeModule(env);
%}
/* -----------------------------------------------------------------------------
* js_init_inheritance: template for enabling the inheritance
* ----------------------------------------------------------------------------- */
%fragment("js_init_inheritance", "templates")
%{
Napi::Value jsObjectValue, jsSetProtoValue;
Napi::Object jsObject;
Napi::Function setProto;
NAPI_CHECK_RESULT(env.Global().Get("Object"), jsObjectValue);
NAPI_CHECK_RESULT(jsObjectValue.ToObject(), jsObject);
NAPI_CHECK_RESULT(jsObject.Get("setPrototypeOf"), jsSetProtoValue);
setProto = jsSetProtoValue.As<Napi::Function>();
%}
/* -----------------------------------------------------------------------------
* js_initializer: template for the module initializer function
* - $jsname: module name
* - $jsnapipreinheritance: the previous template
* - $jsnapinspaces: part with code creating namespace objects
* - $jsnapiwrappers: part with code that registers wrapper functions
* - $jsnapiinitinheritance: part with inherit statements
* - $jsnapistaticwrappers: part with code adding static functions to class objects
* - $jsnapiregisterclasses: part with code that registers class objects in namespaces
* - $jsnapiregisternspaces: part with code that registers namespaces in parent namespaces
* ----------------------------------------------------------------------------- */
%fragment("js_initializer", "templates")
%{
Napi::Function SWIG_NAPI_ObjectWrap_ctor = SWIG_NAPI_ObjectWrap_inst::GetClass(env);
Napi::FunctionReference *SWIG_NAPI_ObjectWrap_ctor_ref = new Napi::FunctionReference();
*SWIG_NAPI_ObjectWrap_ctor_ref = Napi::Persistent(SWIG_NAPI_ObjectWrap_ctor);
env.GetInstanceData<EnvInstanceData>()->SWIG_NAPI_ObjectWrapCtor = SWIG_NAPI_ObjectWrap_ctor_ref;
/* create objects for namespaces */
$jsnapinspaces
/* register classes */
$jsnapiregisterclasses
/* enable inheritance */
$jsnapipreinheritance
/* setup inheritances */
$jsnapiinitinheritance
/* create and register namespace objects */
$jsnapiregisternspaces
return exports;
goto fail;
fail:
return Napi::Object();
}
NODE_API_MODULE($jsname, Init)
%}

View File

@ -0,0 +1,387 @@
/* ------------------------------------------------------------
* Primitive Types
* ------------------------------------------------------------ */
/* boolean */
%fragment(SWIG_From_frag(bool),"header", "header") {
SWIGINTERN
Napi::Value SWIG_From_bool(Napi::Env env, bool val)
{
return Napi::Boolean::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(bool),"header",
fragment=SWIG_AsVal_frag(long)) {
SWIGINTERN
int SWIG_AsVal_dec(bool)(Napi::Value obj, bool *val)
{
if(!obj.IsBoolean()) {
return SWIG_TypeError;
}
Napi::Boolean b;
NAPI_CHECK_RESULT(obj.ToBoolean(), b);
if (val) *val = b.Value();
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}
/* char */
%fragment(SWIG_From_frag(unsigned char), "header") {
SWIGINTERNINLINE Napi::Value
SWIG_From_unsigned_SS_char(Napi::Env env, unsigned char c)
{
return Napi::Number::New(env, static_cast<double>(c));
}
}
%fragment(SWIG_From_frag(signed char), "header") {
SWIGINTERNINLINE Napi::Value
SWIG_From_signed_SS_char(Napi::Env env, signed char c)
{
return Napi::Number::New(env, static_cast<double>(c));
}
}
/* int */
%fragment(SWIG_From_frag(int), "header") {
SWIGINTERN
Napi::Value SWIG_From_int(Napi::Env env, int val)
{
return Napi::Number::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(int),"header") {
SWIGINTERN
int SWIG_AsVal_dec(int)(Napi::Value valRef, int* val)
{
if (!valRef.IsNumber()) {
return SWIG_TypeError;
}
if (val) {
Napi::Number num;
NAPI_CHECK_RESULT(valRef.ToNumber(), num);
*val = static_cast<int>(num.Int32Value());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}
/* unsigned int */
%fragment(SWIG_From_frag(unsigned int), "header") {
SWIGINTERN
Napi::Value SWIG_From_unsigned_SS_int(Napi::Env env, unsigned int val)
{
return Napi::Number::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(unsigned int),"header") {
SWIGINTERN
int SWIG_AsVal_dec(unsigned int)(Napi::Value valRef, unsigned int* val)
{
if (!valRef.IsNumber()) {
return SWIG_TypeError;
}
if (val) {
Napi::Number num;
NAPI_CHECK_RESULT(valRef.ToNumber(), num);
if (num.Int64Value() < 0) {
return SWIG_TypeError;
}
*val = static_cast<unsigned int>(num.Uint32Value());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}
/* short */
%fragment("SWIG_Env_FromShort", "header") {
SWIGINTERN
Napi::Value SWIG_From_short(Napi::Env env, short val)
{
return Napi::Number::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(short),"header") {
SWIGINTERN
int SWIG_AsVal_dec(short)(Napi::Value valRef, short* val)
{
if (!valRef.IsNumber()) {
return SWIG_TypeError;
}
if (val) {
Napi::Number num;
NAPI_CHECK_RESULT(valRef.ToNumber(), num);
*val = static_cast<short>(num.Int32Value());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}
/* unsigned short */
%fragment(SWIG_From_frag(unsigned short), "header") {
SWIGINTERN
Napi::Value SWIG_From_unsigned_SS_short(Napi::Env env, unsigned short val)
{
return Napi::Number::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(unsigned short),"header") {
SWIGINTERN
int SWIG_AsVal_dec(unsigned short)(Napi::Value valRef, unsigned short* val)
{
if (!valRef.IsNumber()) {
return SWIG_TypeError;
}
if (val) {
Napi::Number num;
NAPI_CHECK_RESULT(valRef.ToNumber(), num);
if (num.Int64Value() < 0) {
return SWIG_TypeError;
}
*val = static_cast<unsigned short>(num.Uint32Value());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}
/* long */
%fragment(SWIG_From_frag(long), "header") {
SWIGINTERN
Napi::Value SWIG_From_long(Napi::Env env, long val)
{
return Napi::Number::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(long),"header",
fragment="SWIG_CanCastAsInteger") {
SWIGINTERN
int SWIG_AsVal_dec(long)(Napi::Value obj, long* val)
{
if (!obj.IsNumber()) {
return SWIG_TypeError;
}
if (val) {
Napi::Number num;
NAPI_CHECK_RESULT(obj.ToNumber(), num);
*val = static_cast<long>(num.Int64Value());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}
/* unsigned long */
%fragment(SWIG_From_frag(unsigned long), "header") {
SWIGINTERN
Napi::Value SWIG_From_unsigned_SS_long(Napi::Env env, unsigned long val)
{
return Napi::Number::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(unsigned long),"header",
fragment="SWIG_CanCastAsInteger") {
SWIGINTERN
int SWIG_AsVal_dec(unsigned long)(Napi::Value obj, unsigned long *val)
{
if(!obj.IsNumber()) {
return SWIG_TypeError;
}
if (val) {
Napi::Number num;
NAPI_CHECK_RESULT(obj.ToNumber(), num);
if (num.Int64Value() < 0) {
return SWIG_TypeError;
}
*val = static_cast<unsigned long>(num.Int64Value());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}
/* long long */
%fragment(SWIG_From_frag(long long), "header", fragment="SWIG_LongLongAvailable") {
%#ifdef SWIG_LONG_LONG_AVAILABLE
SWIGINTERN
Napi::Value SWIG_From_long_SS_long(Napi::Env env, long long val)
{
return Napi::Number::New(env, val);
}
%#endif
}
%fragment(SWIG_AsVal_frag(long long),"header",
fragment=SWIG_AsVal_frag(long),
fragment="SWIG_CanCastAsInteger",
fragment="SWIG_LongLongAvailable") {
%#ifdef SWIG_LONG_LONG_AVAILABLE
SWIGINTERN
int SWIG_AsVal_dec(long long)(Napi::Value obj, long long* val)
{
if(!obj.IsNumber()) {
return SWIG_TypeError;
}
if (val) {
Napi::Number num;
NAPI_CHECK_RESULT(obj.ToNumber(), num);
*val = static_cast<long long>(num.Int64Value());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
%#endif
}
/* unsigned long long */
%fragment(SWIG_From_frag(unsigned long long), "header", fragment="SWIG_LongLongAvailable") {
%#ifdef SWIG_LONG_LONG_AVAILABLE
SWIGINTERN
Napi::Value SWIG_From_unsigned_SS_long_SS_long(Napi::Env env, unsigned long long val)
{
return Napi::Number::New(env, val);
}
%#endif
}
%fragment(SWIG_AsVal_frag(unsigned long long),"header",
fragment=SWIG_AsVal_frag(unsigned long),
fragment="SWIG_CanCastAsInteger",
fragment="SWIG_LongLongAvailable") {
%#ifdef SWIG_LONG_LONG_AVAILABLE
SWIGINTERN
int SWIG_AsVal_dec(unsigned long long)(Napi::Value obj, unsigned long long *val)
{
if(!obj.IsNumber()) {
return SWIG_TypeError;
}
if (obj.ToNumber().Int64Value() < 0) {
return SWIG_TypeError;
}
if (val) {
Napi::Number num;
NAPI_CHECK_RESULT(obj.ToNumber(), num);
*val = static_cast<unsigned long long>(num.Int64Value());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
%#endif
}
/* float */
%fragment(SWIG_From_frag(float), "header") {
SWIGINTERN
Napi::Value SWIG_From_float(Napi::Env env, float val)
{
return Napi::Number::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(float),"header") {
SWIGINTERN
int SWIG_AsVal_dec(float)(Napi::Value obj, float *val)
{
if(!obj.IsNumber()) {
return SWIG_TypeError;
}
if(val) {
Napi::Number num;
NAPI_CHECK_RESULT(obj.ToNumber(), num);
*val = static_cast<float>(num.DoubleValue());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}
/* double */
%fragment(SWIG_From_frag(double), "header") {
SWIGINTERN
Napi::Value SWIG_From_double(Napi::Env env, double val)
{
return Napi::Number::New(env, val);
}
}
%fragment(SWIG_AsVal_frag(double),"header") {
SWIGINTERN
int SWIG_AsVal_dec(double)(Napi::Value obj, double *val)
{
if(!obj.IsNumber()) {
return SWIG_TypeError;
}
if(val) {
Napi::Number num;
NAPI_CHECK_RESULT(obj.ToNumber(), num);
*val = static_cast<double>(num.DoubleValue());
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
}

View File

@ -0,0 +1,446 @@
/* ---------------------------------------------------------------------------
* Error handling
*
* ---------------------------------------------------------------------------*/
/*
* We support several forms:
*
* SWIG_Raise("Error message")
* which creates an Error object with the error message
*
* SWIG_Raise(SWIG_TypeError, "Type error")
* which creates the specified error type with the message
*
* SWIG_Raise(obj)
* which throws the object itself
*
* SWIG_Raise(obj, "Exception const &", SWIGType_p_Exception)
* which also throws the object itself and discards the unneeded extra type info
*
* These must be functions instead of macros to use the C++ overloading to
* resolve the arguments
*/
#define SWIG_exception(code, msg) SWIG_Error(code, msg)
#define SWIG_fail goto fail
#ifdef NAPI_CPP_EXCEPTIONS
#define SWIG_Error(code, msg) SWIG_NAPI_Raise(env, code, msg)
#define NAPI_CHECK_MAYBE(maybe) (maybe)
#define NAPI_CHECK_RESULT(maybe, result) (result = maybe)
SWIGINTERN void SWIG_NAPI_Raise(Napi::Env env, const char *msg) {
throw Napi::Error::New(env, msg);
}
SWIGINTERN void SWIG_NAPI_Raise(Napi::Env env, int type, const char *msg) {
switch(type) {
default:
case SWIG_IOError:
case SWIG_MemoryError:
case SWIG_SystemError:
case SWIG_RuntimeError:
case SWIG_DivisionByZero:
case SWIG_SyntaxError:
throw Napi::Error::New(env, msg);
case SWIG_OverflowError:
case SWIG_IndexError:
throw Napi::RangeError::New(env, msg);
case SWIG_ValueError:
case SWIG_TypeError:
throw Napi::TypeError::New(env, msg);
}
}
SWIGINTERN void SWIG_NAPI_Raise(Napi::Env env, Napi::Value obj,
const char *msg = nullptr, swig_type_info *info = nullptr) {
throw Napi::Error(env, obj);
}
#else
#define SWIG_Error(code, msg) do { SWIG_NAPI_Raise(env, code, msg); SWIG_fail; } while (0)
#define NAPI_CHECK_MAYBE(maybe) do { if (maybe.IsNothing()) SWIG_fail; } while (0)
#define NAPI_CHECK_RESULT(maybe, result) \
do { \
auto r = maybe; \
if (r.IsNothing()) SWIG_fail; \
result = r.Unwrap(); \
} while (0)
SWIGINTERN void SWIG_NAPI_Raise(Napi::Env env, const char *msg) {
Napi::Error::New(env, msg).ThrowAsJavaScriptException();
}
SWIGINTERN void SWIG_NAPI_Raise(Napi::Env env, int type, const char *msg) {
switch(type) {
default:
case SWIG_IOError:
case SWIG_MemoryError:
case SWIG_SystemError:
case SWIG_RuntimeError:
case SWIG_DivisionByZero:
case SWIG_SyntaxError:
Napi::Error::New(env, msg).ThrowAsJavaScriptException();
return;
case SWIG_OverflowError:
case SWIG_IndexError:
Napi::RangeError::New(env, msg).ThrowAsJavaScriptException();
return;
case SWIG_ValueError:
case SWIG_TypeError:
Napi::TypeError::New(env, msg).ThrowAsJavaScriptException();
return;
}
}
SWIGINTERN void SWIG_NAPI_Raise(Napi::Env env, Napi::Value obj,
const char *msg = nullptr, swig_type_info *info = nullptr) {
Napi::Error(env, obj).ThrowAsJavaScriptException();
}
#endif
void JS_veto_set_variable(const Napi::CallbackInfo &info) {
SWIG_NAPI_Raise(info.Env(), "Tried to write read-only variable.");
}
struct EnvInstanceData {
Napi::Env env;
// Base class per-environment constructor, used to check
// if a JS object is a SWIG wrapper
Napi::FunctionReference *SWIG_NAPI_ObjectWrapCtor;
// Per-environment wrapper constructors, indexed by the number in
// swig_type->clientdata
Napi::FunctionReference **ctor;
swig_module_info *swig_module;
EnvInstanceData(Napi::Env, swig_module_info *);
~EnvInstanceData();
};
typedef size_t SWIG_NAPI_ClientData;
// Base class for all wrapped objects,
// used mostly when unwrapping unknown objects
template <typename SWIG_OBJ_WRAP>
class SWIG_NAPI_ObjectWrap_templ : public Napi::ObjectWrap<SWIG_OBJ_WRAP> {
public:
void *self;
bool owned;
size_t size;
swig_type_info *info;
SWIG_NAPI_ObjectWrap_templ(const Napi::CallbackInfo &info);
SWIG_NAPI_ObjectWrap_templ(bool, const Napi::CallbackInfo &info) :
Napi::ObjectWrap<SWIG_OBJ_WRAP>(info),
self(nullptr),
owned(true),
size(0),
info(nullptr)
{}
virtual ~SWIG_NAPI_ObjectWrap_templ() {};
Napi::Value ToString(const Napi::CallbackInfo &info);
};
template <typename SWIG_OBJ_WRAP>
SWIG_NAPI_ObjectWrap_templ<SWIG_OBJ_WRAP>::SWIG_NAPI_ObjectWrap_templ(const Napi::CallbackInfo &info) :
Napi::ObjectWrap<SWIG_OBJ_WRAP>(info), size(0), info(nullptr) {
Napi::Env env = info.Env();
if (info.Length() == 1 && info[0].IsExternal()) {
// This constructor has been called internally from C++/SWIG
// to wrap an already existing C++ object of unknown type in JS
this->self = info[0].As<Napi::External<void>>().Data();
this->owned = false;
} else {
SWIG_Error(SWIG_ERROR, "This constructor is not accessible from JS");
}
return;
goto fail;
fail:
return;
}
template <typename SWIG_OBJ_WRAP>
Napi::Value SWIG_NAPI_ObjectWrap_templ<SWIG_OBJ_WRAP>::ToString(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
static char repr[128];
const char *name = SWIG_TypePrettyName(this->info);
snprintf(repr, sizeof(repr), "{SwigObject %s (%s) at %p %s}",
this->info ? this->info->name : "unknown",
name ? name : "unknown",
this->self,
this->owned ? "[owned]" : "[copy]");
return Napi::String::New(env, repr);
}
class SWIG_NAPI_ObjectWrap_inst : public SWIG_NAPI_ObjectWrap_templ<SWIG_NAPI_ObjectWrap_inst> {
public:
using SWIG_NAPI_ObjectWrap_templ::SWIG_NAPI_ObjectWrap_templ;
static Napi::Function GetClass(Napi::Env);
static void GetMembers(
Napi::Env,
std::map<std::string, SWIG_NAPI_ObjectWrap_templ::PropertyDescriptor> &,
std::map<std::string, SWIG_NAPI_ObjectWrap_templ::PropertyDescriptor> &
);
};
void SWIG_NAPI_ObjectWrap_inst::GetMembers(
Napi::Env env,
std::map<std::string, SWIG_NAPI_ObjectWrap_templ::PropertyDescriptor> &members,
std::map<std::string, SWIG_NAPI_ObjectWrap_templ::PropertyDescriptor> &
) {
members.erase("toString");
members.insert({"toString", SWIG_NAPI_ObjectWrap_templ::InstanceMethod("toString", &SWIG_NAPI_ObjectWrap_templ::ToString)});
}
Napi::Function SWIG_NAPI_ObjectWrap_inst::GetClass(Napi::Env env) {
return Napi::ObjectWrap<SWIG_NAPI_ObjectWrap_inst>::DefineClass(env, "SwigObject", {});
}
SWIGRUNTIME int SWIG_NAPI_ConvertInstancePtr(Napi::Object objRef, void **ptr, swig_type_info *info, int flags) {
SWIG_NAPI_ObjectWrap_inst *ow;
Napi::Env env = objRef.Env();
if(!objRef.IsObject()) return SWIG_ERROR;
// Check if this is a SWIG wrapper
Napi::FunctionReference *ctor = env.GetInstanceData<EnvInstanceData>()->SWIG_NAPI_ObjectWrapCtor;
bool instanceOf;
NAPI_CHECK_RESULT(objRef.InstanceOf(ctor->Value()), instanceOf);
if (!instanceOf) {
return SWIG_TypeError;
}
ow = Napi::ObjectWrap<SWIG_NAPI_ObjectWrap_inst>::Unwrap(objRef);
// Now check if the SWIG type is compatible unless the types match exactly or the type is unknown
if(info && ow->info != info && ow->info != nullptr) {
swig_cast_info *tc = SWIG_TypeCheckStruct(ow->info, info);
if (!tc && ow->info->name) {
tc = SWIG_TypeCheck(ow->info->name, info);
}
bool type_valid = tc != 0;
if(!type_valid) {
return SWIG_TypeError;
}
int newmemory = 0;
*ptr = SWIG_TypeCast(tc, ow->self, &newmemory);
assert(!newmemory); /* newmemory handling not yet implemented */
} else {
*ptr = ow->self;
}
if (((flags & SWIG_POINTER_RELEASE) == SWIG_POINTER_RELEASE) && !ow->owned) {
return SWIG_ERROR_RELEASE_NOT_OWNED;
} else {
if (flags & SWIG_POINTER_DISOWN) {
ow->owned = false;
}
if (flags & SWIG_POINTER_CLEAR) {
ow->self = nullptr;
}
}
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
SWIGRUNTIME int SWIG_NAPI_GetInstancePtr(Napi::Value valRef, void **ptr) {
SWIG_NAPI_ObjectWrap_inst *ow;
if(!valRef.IsObject()) {
return SWIG_TypeError;
}
Napi::Object objRef;
NAPI_CHECK_RESULT(valRef.ToObject(), objRef);
ow = Napi::ObjectWrap<SWIG_NAPI_ObjectWrap_inst>::Unwrap(objRef);
if(ow->self == nullptr) {
return SWIG_ERROR;
}
*ptr = ow->self;
return SWIG_OK;
goto fail;
fail:
return SWIG_ERROR;
}
SWIGRUNTIME int SWIG_NAPI_ConvertPtr(Napi::Value valRef, void **ptr, swig_type_info *info, int flags) {
// special case: JavaScript null => C NULL pointer
if (valRef.IsNull()) {
*ptr=0;
return (flags & SWIG_POINTER_NO_NULL) ? SWIG_NullReferenceError : SWIG_OK;
}
if (!valRef.IsObject()) {
return SWIG_TypeError;
}
Napi::Object objRef;
NAPI_CHECK_RESULT(valRef.ToObject(), objRef);
return SWIG_NAPI_ConvertInstancePtr(objRef, ptr, info, flags);
goto fail;
fail:
return SWIG_ERROR;
}
SWIGRUNTIME Napi::Value SWIG_NAPI_NewPointerObj(Napi::Env env, void *ptr, swig_type_info *info, int flags) {
Napi::External<void> native;
Napi::FunctionReference *ctor;
if (ptr == nullptr) {
return env.Null();
}
native = Napi::External<void>::New(env, ptr);
size_t *idx = info != nullptr ?
reinterpret_cast<SWIG_NAPI_ClientData *>(info->clientdata) :
nullptr;
if (idx == nullptr) {
// This type does not have a dedicated wrapper
ctor = env.GetInstanceData<EnvInstanceData>()->SWIG_NAPI_ObjectWrapCtor;
} else {
ctor = env.GetInstanceData<EnvInstanceData>()->ctor[*idx];
}
Napi::Value wrapped;
NAPI_CHECK_RESULT(ctor->New({native}), wrapped);
// Preserve the type even if using the generic wrapper
if (idx == nullptr && info != nullptr) {
Napi::Object obj;
NAPI_CHECK_RESULT(wrapped.ToObject(), obj);
Napi::ObjectWrap<SWIG_NAPI_ObjectWrap_inst>::Unwrap(obj)->info = info;
}
if ((flags & SWIG_POINTER_OWN) == SWIG_POINTER_OWN) {
Napi::Object obj;
NAPI_CHECK_RESULT(wrapped.ToObject(), obj);
Napi::ObjectWrap<SWIG_NAPI_ObjectWrap_inst>::Unwrap(obj)->owned = true;
}
return wrapped;
goto fail;
fail:
return Napi::Value();
}
#define SWIG_ConvertPtr(obj, ptr, info, flags) SWIG_NAPI_ConvertPtr(obj, ptr, info, flags)
#define SWIG_NewPointerObj(ptr, info, flags) SWIG_NAPI_NewPointerObj(env, ptr, info, flags)
#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_NAPI_ConvertInstancePtr(obj, pptr, type, flags)
#define SWIG_NewInstanceObj(thisvalue, type, flags) SWIG_NAPI_NewPointerObj(env, thisvalue, type, flags)
#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_NAPI_ConvertPtr(obj, pptr, type, 0)
#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_NAPI_NewPointerObj(env, ptr, type, 0)
#define SWIG_GetInstancePtr(obj, ptr) SWIG_NAPI_GetInstancePtr(obj, ptr)
SWIGRUNTIME Napi::Value _SWIG_NAPI_wrap_equals(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
void *arg1 = (void *) 0 ;
void *arg2 = (void *) 0 ;
bool result;
int res1;
int res2;
if(info.Length() != 1) SWIG_Error(SWIG_ERROR, "Illegal number of arguments for equals.");
res1 = SWIG_GetInstancePtr(info.This(), &arg1);
if (!SWIG_IsOK(res1)) {
SWIG_Error(SWIG_ERROR, "Could not get pointer from 'this' object for equals.");
}
res2 = SWIG_GetInstancePtr(info[0], &arg2);
if (!SWIG_IsOK(res2)) {
SWIG_Error(SWIG_ArgError(res2), " in method '" "equals" "', argument " "1"" of type '" "void *""'");
}
result = (bool)(arg1 == arg2);
jsresult = Napi::Boolean::New(env, result);
return jsresult;
goto fail;
fail:
return Napi::Value();
}
SWIGRUNTIME Napi::Value _wrap_getCPtr(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
Napi::Value jsresult;
void *arg1 = (void *) 0 ;
long result;
int res1;
res1 = SWIG_GetInstancePtr(info.This(), &arg1);
if (!SWIG_IsOK(res1)) {
SWIG_Error(SWIG_ArgError(res1), " in method '" "getCPtr" "', argument " "1"" of type '" "void *""'");
}
result = (long)arg1;
jsresult = Napi::Number::New(env, result);
return jsresult;
goto fail;
fail:
return Napi::Value();
}
/* ---------------------------------------------------------------------------
* PackedData object
* (objects visible to JS that do not have a dedicated wrapper but must preserve type)
* ---------------------------------------------------------------------------*/
SWIGRUNTIME
Napi::Value SWIG_NAPI_NewPackedObj(Napi::Env env, void *data, size_t size, swig_type_info *type) {
void *data_copy = new uint8_t[size];
memcpy(data_copy, data, size);
Napi::Value val = SWIG_NAPI_NewPointerObj(env, data_copy, type, SWIG_POINTER_OWN);
Napi::Object obj;
if (val.IsEmpty()) goto fail;
NAPI_CHECK_RESULT(val.ToObject(), obj);
Napi::ObjectWrap<SWIG_NAPI_ObjectWrap_inst>::Unwrap(obj)->size = size;
fail:
return val;
}
SWIGRUNTIME
int SWIG_NAPI_ConvertPacked(Napi::Value valRef, void *ptr, size_t size, swig_type_info *type) {
void *tmp;
if (!SWIG_IsOK(SWIG_NAPI_ConvertPtr(valRef, &tmp, type, 0))) {
return SWIG_ERROR;
}
memcpy(ptr, tmp, size);
return SWIG_OK;
}
#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_NAPI_ConvertPacked(obj, ptr, sz, ty)
#define SWIG_NewMemberObj(ptr, sz, type) SWIG_NAPI_NewPackedObj(env, ptr, sz, type)
/* ---------------------------------------------------------------------------
* Support for IN/OUTPUT typemaps (see Lib/typemaps/inoutlist.swg)
*
* ---------------------------------------------------------------------------*/
SWIGRUNTIME
Napi::Value SWIG_NAPI_AppendOutput(Napi::Env env, Napi::Value result, Napi::Value obj) {
if (result.IsUndefined()) {
result = Napi::Array::New(env);
} else if (!result.IsArray()) {
Napi::Array tmparr = Napi::Array::New(env);
tmparr.Set(static_cast<uint32_t>(0), result);
result = tmparr;
}
Napi::Array arr = result.As<Napi::Array>();
arr.Set(arr.Length(), obj);
return arr;
}

View File

@ -0,0 +1,40 @@
/* -----------------------------------------------------------------------------
* javascriptruntime.swg
*
* ----------------------------------------------------------------------------- */
// NAPI
// ----------
%insert(runtime) %{
#if defined(_CPPUNWIND) || defined(__EXCEPTIONS)
#define NAPI_CPP_EXCEPTIONS
#else
#define NAPI_DISABLE_CPP_EXCEPTIONS
#define NODE_ADDON_API_ENABLE_MAYBE
#endif
// This gives us
// Branch Node.js v10.x - from v10.20.0
// Branch Node.js v12.x - from v12.17.0
// Everything from Node.js v14.0.0 on
// Our limiting feature is napi_set_instance_data
#ifndef NAPI_VERSION
#define NAPI_VERSION 6
#elif NAPI_VERSION < 6
#error NAPI_VERSION 6 is the minimum supported target (Node.js >=14, >=12.17, >=10.20)
#endif
#include <napi.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <assert.h>
#include <map>
%}
%insert(runtime) "swigrun.swg"; /* SWIG API */
%insert(runtime) "swigerrors.swg"; /* SWIG errors */
%insert(runtime) "javascriptrun.swg"

View File

@ -0,0 +1,77 @@
/* ------------------------------------------------------------
* utility methods for char strings
* ------------------------------------------------------------ */
%fragment("SWIG_AsCharPtrAndSize", "header", fragment="SWIG_pchar_descriptor") {
SWIGINTERN int
SWIG_AsCharPtrAndSize(Napi::Value valRef, char** cptr, size_t* psize, int *alloc)
{
if(valRef.IsString()) {
Napi::String js_str;
NAPI_CHECK_RESULT(valRef.ToString(), js_str);
std::string str = js_str.Utf8Value();
size_t len = str.size() + 1;
char* cstr = (char*) %new_array(len, char);
memcpy(cstr, str.data(), len);
if(alloc) *alloc = SWIG_NEWOBJ;
if(psize) *psize = len;
if(cptr) *cptr = cstr;
return SWIG_OK;
} else {
if(valRef.IsObject()) {
swig_type_info* pchar_descriptor = SWIG_pchar_descriptor();
Napi::Object obj;
NAPI_CHECK_RESULT(valRef.ToObject(), obj);
// try if the object is a wrapped char[]
if (pchar_descriptor) {
void* vptr = 0;
if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) {
if (cptr) *cptr = (char *) vptr;
if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0;
if (alloc) *alloc = SWIG_OLDOBJ;
return SWIG_OK;
}
}
}
}
goto fail;
fail:
return SWIG_TypeError;
}
}
%fragment(SWIG_From_frag(char), "header") {
SWIGINTERNINLINE Napi::Value
SWIG_From_char(Napi::Env env, char c)
{
Napi::String js_str = Napi::String::New(env, &c, 1);
return js_str;
}
}
%fragment("SWIG_FromCharPtr", "header", fragment = "SWIG_FromCharPtrAndSize") {
// Override the default one with an empty one
}
%fragment("SWIG_FromCharPtrAndSize", "header") {
SWIGINTERNINLINE Napi::Value
SWIG_Env_FromCharPtrAndSize(Napi::Env env, const char* carray, size_t size)
{
if (carray) {
Napi::String js_str = Napi::String::New(env, carray, size);
return js_str;
} else {
return env.Undefined();
}
}
}
%insert(runtime) %{
#define SWIG_FromCharPtrAndSize(cptr, size) SWIG_Env_FromCharPtrAndSize(env, cptr, size)
#define SWIG_FromCharPtr(cptr) SWIG_Env_FromCharPtrAndSize(env, cptr, strlen(cptr))
%}

View File

@ -0,0 +1,56 @@
/* ------------------------------------------------------------
* Typemap specializations for Javascript
* ------------------------------------------------------------ */
/* ------------------------------------------------------------
* Fragment section
* ------------------------------------------------------------ */
/* These macros are necessary to provide an extra parameter
to SWIG_AsVal_dec functions (Napi::Env environment).
They must be defined before including `typemaps/fragments.swg`
*/
#define SWIG_FROM_DECL_ARGS SWIG_NAPI_FROM_DECL_ARGS
#define SWIG_FROM_CALL_ARGS SWIG_NAPI_FROM_CALL_ARGS
/* Include fundamental fragemt definitions */
%include <typemaps/fragments.swg>
/* Look for user fragments file. */
%include <javascriptfragments.swg>
/* Javascript fragments for fundamental types */
%include <javascriptprimtypes.swg>
/* Javascript fragments for char* strings */
%include <javascriptstrings.swg>
/* ------------------------------------------------------------
* Unified typemap section
* ------------------------------------------------------------ */
/* Javascript types */
#define SWIG_Object Napi::Value
#define VOID_Object env.Undefined()
/* Overload of the output/constant/exception/dirout handling */
/* append output */
#define SWIG_AppendOutput(result, obj) SWIG_NAPI_AppendOutput(env, result, obj)
/* set constant */
#define SWIG_SetConstant(name, obj)
/* raise */
#define SWIG_Raise(...) SWIG_NAPI_Raise(env, __VA_ARGS__)
%insert("runtime") %{
#define SWIG_NAPI_FROM_DECL_ARGS(arg1) (Napi::Env env, arg1)
#define SWIG_NAPI_FROM_CALL_ARGS(arg1) (env, arg1)
%}
/* Include the unified typemap library */
%include <typemaps/swigtypemaps.swg>

View File

@ -0,0 +1,47 @@
/*
* To include generic versions of the in typemaps, add:
*
* %typemap(in) (void *, size_t) = (const void* buffer_data, const size_t buffer_len);
* %typemap(typecheck) (void *, size_t) = (const void* buffer_data, const size_t buffer_len);
*
* or to discriminate by argument names:
* %typemap(in) (void *data, size_t length) = (const void* buffer_data, const size_t buffer_len);
* %typemap(typecheck) (void *data, size_t length) = (const void* buffer_data, const size_t buffer_len);
*/
%typemap(in) (const void* buffer_data, const size_t buffer_len) {
if ($input.IsBuffer()) {
Napi::Buffer<char> buf = $input.As<Napi::Buffer<char>>();
$1 = reinterpret_cast<void *>(buf.Data());
$2 = buf.ByteLength();
} else {
SWIG_exception_fail(SWIG_TypeError, "in method '$symname', argument is not a Buffer");
}
}
%typemap(typecheck, precedence=SWIG_TYPECHECK_VOIDPTR) (const void* buffer_data, const size_t buffer_len) {
$1 = $input.IsBuffer();
}
/*
* In order to use the argout typemap, the function must have the following signature:
*
* void buffer(void **buffer_data, size_t *buffer_len)
*
* In this case, this function will be wrapped by a JS function that takes
* no arguments (because of numinputs=0) and returns a Buffer
*/
%typemap(in, numinputs=0) (void **buffer_data, size_t *buffer_len) (void *temp_data, size_t temp_len) {
$1 = &temp_data;
$2 = &temp_len;
}
%typemap(argout) (void **buffer_data, size_t *buffer_len) {
if (*$1 != nullptr) {
Napi::Buffer<char> buf = Napi::Buffer<char>::Copy(env, reinterpret_cast<char *>(*$1), *$2);
NAPI_CHECK_RESULT(buf.As<Napi::Value>(), $result);
} else {
$result = env.Null();
}
}

View File

@ -0,0 +1,39 @@
/* -----------------------------------------------------------------------------
* std_auto_ptr.i
*
* SWIG library file for handling std::auto_ptr.
* Memory ownership is passed from the std::auto_ptr C++ layer to the proxy
* class when returning a std::auto_ptr from a function.
* Memory ownership is passed from the proxy class to the std::auto_ptr in the
* C++ layer when passed as a parameter to a wrapped function.
* ----------------------------------------------------------------------------- */
%define %auto_ptr(TYPE)
%typemap(in, noblock=1) std::auto_ptr< TYPE > (void *argp = 0, int res = 0) {
res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags);
if (!SWIG_IsOK(res)) {
if (res == SWIG_ERROR_RELEASE_NOT_OWNED) {
%releasenotowned_fail(res, "TYPE *", $symname, $argnum);
} else {
%argument_fail(res, "TYPE *", $symname, $argnum);
}
}
$1.reset((TYPE *)argp);
}
%typemap (out) std::auto_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::auto_ptr< TYPE > {
void *vptr = 0;
int res = SWIG_ConvertPtr($input, &vptr, $descriptor(TYPE *), 0);
$1 = SWIG_CheckState(res);
}
%template() std::auto_ptr< TYPE >;
%enddef
namespace std {
template <class T> class auto_ptr {};
}

View File

@ -0,0 +1,5 @@
%include <std_except.i>
%apply size_t { std::size_t };
%apply const size_t& { const std::size_t& };

View File

@ -0,0 +1,26 @@
/*
* STD C++ complex typemaps
*/
%include <javascriptcomplex.swg>
%{
#include <complex>
%}
namespace std {
%naturalvar complex;
template<typename T> class complex;
%template() complex<double>;
%template() complex<float>;
}
/* defining the complex as/from converters */
%swig_cplxdbl_convn(std::complex<double>, std::complex<double>, std::real, std::imag)
%swig_cplxflt_convn(std::complex<float>, std::complex<float>, std::real, std::imag)
/* defining the typemaps */
%typemaps_primitive(%checkcode(CPLXDBL), std::complex<double>);
%typemaps_primitive(%checkcode(CPLXFLT), std::complex<float>);

View File

@ -0,0 +1 @@
%include <std/_std_deque.i>

View File

@ -0,0 +1 @@
%include <typemaps/std_except.swg>

View File

@ -0,0 +1,80 @@
/* -----------------------------------------------------------------------------
* std_map.i
*
* SWIG typemaps for std::map
* ----------------------------------------------------------------------------- */
%include <std_common.i>
// ------------------------------------------------------------------------
// std::map
// ------------------------------------------------------------------------
%{
#include <map>
#include <algorithm>
#include <stdexcept>
%}
// exported class
namespace std {
template<class K, class T, class C = std::less<K> > class map {
// add typemaps here
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef K key_type;
typedef T mapped_type;
typedef std::pair< const K, T > value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
map();
map(const map& other);
unsigned int size() const;
bool empty() const;
void clear();
%extend {
const T& get(const K& key) throw (std::out_of_range) {
std::map< K, T, C >::iterator i = self->find(key);
if (i != self->end())
return i->second;
else
throw std::out_of_range("key not found");
}
void set(const K& key, const T& x) {
(*self)[key] = x;
}
void del(const K& key) throw (std::out_of_range) {
std::map< K, T, C >::iterator i = self->find(key);
if (i != self->end())
self->erase(i);
else
throw std::out_of_range("key not found");
}
bool has_key(const K& key) {
std::map< K, T, C >::iterator i = self->find(key);
return i != self->end();
}
}
};
// Legacy macros (deprecated)
%define specialize_std_map_on_key(K,CHECK,CONVERT_FROM,CONVERT_TO)
#warning "specialize_std_map_on_key ignored - macro is deprecated and no longer necessary"
%enddef
%define specialize_std_map_on_value(T,CHECK,CONVERT_FROM,CONVERT_TO)
#warning "specialize_std_map_on_value ignored - macro is deprecated and no longer necessary"
%enddef
%define specialize_std_map_on_both(K,CHECK_K,CONVERT_K_FROM,CONVERT_K_TO, T,CHECK_T,CONVERT_T_FROM,CONVERT_T_TO)
#warning "specialize_std_map_on_both ignored - macro is deprecated and no longer necessary"
%enddef
}

View File

@ -0,0 +1,35 @@
/* -----------------------------------------------------------------------------
* std_pair.i
*
* SWIG typemaps for std::pair
* ----------------------------------------------------------------------------- */
%include <std_common.i>
// ------------------------------------------------------------------------
// std::pair
// ------------------------------------------------------------------------
%{
#include <utility>
%}
namespace std {
template<class T, class U> struct pair {
typedef T first_type;
typedef U second_type;
pair();
pair(T first, U second);
pair(const pair& other);
template <class U1, class U2> pair(const pair<U1, U2> &other);
T first;
U second;
};
// add specializations here
}

View File

@ -0,0 +1 @@
%include <typemaps/std_string.swg>

View File

@ -0,0 +1,39 @@
/* -----------------------------------------------------------------------------
* std_unique_ptr.i
*
* SWIG library file for handling std::unique_ptr.
* Memory ownership is passed from the std::unique_ptr C++ layer to the proxy
* class when returning a std::unique_ptr from a function.
* Memory ownership is passed from the proxy class to the std::unique_ptr in the
* C++ layer when passed as a parameter to a wrapped function.
* ----------------------------------------------------------------------------- */
%define %unique_ptr(TYPE)
%typemap(in, noblock=1) std::unique_ptr< TYPE > (void *argp = 0, int res = 0) {
res = SWIG_ConvertPtr($input, &argp, $descriptor(TYPE *), SWIG_POINTER_RELEASE | %convertptr_flags);
if (!SWIG_IsOK(res)) {
if (res == SWIG_ERROR_RELEASE_NOT_OWNED) {
%releasenotowned_fail(res, "TYPE *", $symname, $argnum);
} else {
%argument_fail(res, "TYPE *", $symname, $argnum);
}
}
$1.reset((TYPE *)argp);
}
%typemap (out) std::unique_ptr< TYPE > %{
%set_output(SWIG_NewPointerObj($1.release(), $descriptor(TYPE *), SWIG_POINTER_OWN | %newpointer_flags));
%}
%typemap(typecheck, precedence=SWIG_TYPECHECK_POINTER, equivalent="TYPE *", noblock=1) std::unique_ptr< TYPE > {
void *vptr = 0;
int res = SWIG_ConvertPtr($input, &vptr, $descriptor(TYPE *), 0);
$1 = SWIG_CheckState(res);
}
%template() std::unique_ptr< TYPE >;
%enddef
namespace std {
template <class T> class unique_ptr {};
}

View File

@ -0,0 +1,99 @@
/* -----------------------------------------------------------------------------
* std_vector.i
* ----------------------------------------------------------------------------- */
%include <std_common.i>
%{
#include <vector>
#include <stdexcept>
%}
namespace std {
template<class T> class vector {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
vector();
vector(size_type n);
vector(const vector& other);
size_type size() const;
size_type capacity() const;
void reserve(size_type n);
%rename(isEmpty) empty;
bool empty() const;
void clear();
%rename(add) push_back;
void push_back(const value_type& x);
%extend {
const_reference get(int i) throw (std::out_of_range) {
int size = int(self->size());
if (i>=0 && i<size)
return (*self)[i];
else
throw std::out_of_range("vector index out of range");
}
void set(int i, const value_type& val) throw (std::out_of_range) {
int size = int(self->size());
if (i>=0 && i<size)
(*self)[i] = val;
else
throw std::out_of_range("vector index out of range");
}
}
};
// bool specialization
template<> class vector<bool> {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef bool value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef bool const_reference;
vector();
vector(size_type n);
vector(const vector& other);
size_type size() const;
size_type capacity() const;
void reserve(size_type n);
%rename(isEmpty) empty;
bool empty() const;
void clear();
%rename(add) push_back;
void push_back(const value_type& x);
%extend {
bool get(int i) throw (std::out_of_range) {
int size = int(self->size());
if (i>=0 && i<size)
return (*self)[i];
else
throw std::out_of_range("vector index out of range");
}
void set(int i, const value_type& val) throw (std::out_of_range) {
int size = int(self->size());
if (i>=0 && i<size)
(*self)[i] = val;
else
throw std::out_of_range("vector index out of range");
}
}
};
}
%define specialize_std_vector(T)
#warning "specialize_std_vector - specialization for type T no longer needed"
%enddef

10
Lib/javascript/napi/stl.i Normal file
View File

@ -0,0 +1,10 @@
/* -----------------------------------------------------------------------------
* stl.i
* ----------------------------------------------------------------------------- */
%include <std_common.i>
%include <std_string.i>
%include <std_vector.i>
%include <std_map.i>
%include <std_pair.i>

View File

@ -0,0 +1 @@
%include <typemaps/swigmove.swg>

View File

@ -0,0 +1,148 @@
/* -----------------------------------------------------------------------------
* typemaps.i
*
* Pointer handling
* These mappings provide support for input/output arguments and common
* uses for C/C++ pointers.
* ----------------------------------------------------------------------------- */
// INPUT typemaps.
// These remap a C pointer to be an "INPUT" value which is passed by value
// instead of reference.
/*
The following methods can be applied to turn a pointer into a simple
"input" value. That is, instead of passing a pointer to an object,
you would use a real value instead.
int *INPUT
short *INPUT
long *INPUT
long long *INPUT
unsigned int *INPUT
unsigned short *INPUT
unsigned long *INPUT
unsigned long long *INPUT
unsigned char *INPUT
bool *INPUT
float *INPUT
double *INPUT
To use these, suppose you had a C function like this :
double fadd(double *a, double *b) {
return *a+*b;
}
You could wrap it with SWIG as follows :
%include <typemaps.i>
double fadd(double *INPUT, double *INPUT);
or you can use the %apply directive :
%include <typemaps.i>
%apply double *INPUT { double *a, double *b };
double fadd(double *a, double *b);
*/
// OUTPUT typemaps. These typemaps are used for parameters that
// are output only. The output value is appended to the result as
// a list element.
/*
The following methods can be applied to turn a pointer into an "output"
value. When calling a function, no input value would be given for
a parameter, but an output value would be returned. In the case of
multiple output values, they are returned in the form of a Python tuple.
int *OUTPUT
short *OUTPUT
long *OUTPUT
long long *OUTPUT
unsigned int *OUTPUT
unsigned short *OUTPUT
unsigned long *OUTPUT
unsigned long long *OUTPUT
unsigned char *OUTPUT
bool *OUTPUT
float *OUTPUT
double *OUTPUT
For example, suppose you were trying to wrap the modf() function in the
C math library which splits x into integral and fractional parts (and
returns the integer part in one of its parameters) :
double modf(double x, double *ip);
You could wrap it with SWIG as follows :
%include <typemaps.i>
double modf(double x, double *OUTPUT);
or you can use the %apply directive :
%include <typemaps.i>
%apply double *OUTPUT { double *ip };
double modf(double x, double *ip);
The Python output of the function would be a tuple containing both
output values.
*/
// INOUT
// Mappings for an argument that is both an input and output
// parameter
/*
The following methods can be applied to make a function parameter both
an input and output value. This combines the behavior of both the
"INPUT" and "OUTPUT" methods described earlier. Output values are
returned in the form of a Python tuple.
int *INOUT
short *INOUT
long *INOUT
long long *INOUT
unsigned int *INOUT
unsigned short *INOUT
unsigned long *INOUT
unsigned long long *INOUT
unsigned char *INOUT
bool *INOUT
float *INOUT
double *INOUT
For example, suppose you were trying to wrap the following function :
void neg(double *x) {
*x = -(*x);
}
You could wrap it with SWIG as follows :
%include <typemaps.i>
void neg(double *INOUT);
or you can use the %apply directive :
%include <typemaps.i>
%apply double *INOUT { double *x };
void neg(double *x);
Unlike C, this mapping does not directly modify the input value (since
this makes no sense in Python). Rather, the modified input value shows
up as the return value of the function. Thus, to apply this function
to a Python variable you might do this :
x = neg(x)
Note : previous versions of SWIG used the symbol 'BOTH' to mark
input/output arguments. This is still supported, but will be slowly
phased out in future releases.
*/
%include <typemaps/typemaps.swg>

View File

@ -1,40 +0,0 @@
#ifndef JAVASCRIPT_JAVASCRIPTKW_SWG_
#define JAVASCRIPT_JAVASCRIPTKW_SWG_
/* Warnings for Java keywords */
#define JAVASCRIPTKW(x) %keywordwarn("'" `x` "' is a javascript keyword, renaming to '_"`x`"'",rename="_%s") `x`
/* Taken from https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Reserved_Words */
JAVASCRIPTKW(break);
JAVASCRIPTKW(case);
JAVASCRIPTKW(catch);
JAVASCRIPTKW(continue);
JAVASCRIPTKW(default);
JAVASCRIPTKW(delete);
JAVASCRIPTKW(do);
JAVASCRIPTKW(else);
JAVASCRIPTKW(finally);
JAVASCRIPTKW(for);
JAVASCRIPTKW(function);
JAVASCRIPTKW(if);
JAVASCRIPTKW(in);
JAVASCRIPTKW(instanceof);
JAVASCRIPTKW(new);
JAVASCRIPTKW(return);
JAVASCRIPTKW(switch);
JAVASCRIPTKW(this);
JAVASCRIPTKW(throw);
JAVASCRIPTKW(try);
JAVASCRIPTKW(typeof);
JAVASCRIPTKW(var);
JAVASCRIPTKW(void);
JAVASCRIPTKW(while);
JAVASCRIPTKW(with);
/* others bad names if any*/
// for example %namewarn("321:clone() is a javascript bad method name") *::clone();
#undef JAVASCRIPTKW
#endif //JAVASCRIPT_JAVASCRIPTKW_SWG_

View File

@ -4,24 +4,46 @@
/* Warnings for Java keywords */
#define JAVASCRIPTKW(x) %keywordwarn("'" `x` "' is a javascript keyword, renaming to '_"`x`"'",rename="_%s") `x`
/* Taken from https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Reserved_Words */
/* Taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords */
/* This the union of all currently reserved keywords in ECMAScript 4 to 6 in both sloppy and strict mode */
JAVASCRIPTKW(arguments);
JAVASCRIPTKW(await);
JAVASCRIPTKW(break);
JAVASCRIPTKW(case);
JAVASCRIPTKW(catch);
JAVASCRIPTKW(class);
JAVASCRIPTKW(const);
JAVASCRIPTKW(continue);
JAVASCRIPTKW(debugger);
JAVASCRIPTKW(default);
JAVASCRIPTKW(delete);
JAVASCRIPTKW(do);
JAVASCRIPTKW(else);
JAVASCRIPTKW(enum);
JAVASCRIPTKW(eval);
JAVASCRIPTKW(export);
JAVASCRIPTKW(extends);
JAVASCRIPTKW(false);
JAVASCRIPTKW(finally);
JAVASCRIPTKW(for);
JAVASCRIPTKW(function);
JAVASCRIPTKW(if);
JAVASCRIPTKW(implements);
JAVASCRIPTKW(import);
JAVASCRIPTKW(in);
JAVASCRIPTKW(instanceof);
JAVASCRIPTKW(interface);
JAVASCRIPTKW(let);
JAVASCRIPTKW(new);
JAVASCRIPTKW(null);
JAVASCRIPTKW(package);
JAVASCRIPTKW(private);
JAVASCRIPTKW(protected);
JAVASCRIPTKW(public);
JAVASCRIPTKW(return);
JAVASCRIPTKW(static);
JAVASCRIPTKW(super);
JAVASCRIPTKW(switch);
JAVASCRIPTKW(this);
JAVASCRIPTKW(throw);
@ -31,6 +53,7 @@ JAVASCRIPTKW(var);
JAVASCRIPTKW(void);
JAVASCRIPTKW(while);
JAVASCRIPTKW(with);
JAVASCRIPTKW(yield);
/* others bad names if any*/
// for example %namewarn("321:clone() is a javascript bad method name") *::clone();

View File

@ -436,7 +436,7 @@ install-main:
lib-languages = typemaps tcl perl5 python guile java mzscheme ruby php ocaml octave \
csharp lua r go d javascript javascript/jsc \
javascript/v8 scilab xml
javascript/v8 javascript/napi scilab xml
lib-modules = std

View File

@ -31,6 +31,7 @@ static bool js_template_enable_debug = false;
#define IS_IMMUTABLE "is_immutable"
#define IS_STATIC "is_static"
#define IS_ABSTRACT "is_abstract"
#define IS_WRAPPED "is_wrapped"
#define GETTER "getter"
#define SETTER "setter"
#define PARENT "parent"
@ -127,7 +128,8 @@ public:
enum JSEngine {
JavascriptCore,
V8,
NodeJS
NodeJS,
NAPI
};
JSEmitter(JSEngine engine);
@ -274,6 +276,15 @@ protected:
virtual int emitNamespaces() = 0;
virtual const char *getFunctionTemplate(bool);
virtual const char *getFunctionDispatcherTemplate(bool);
virtual const char *getOverloadedFunctionTemplate(bool);
virtual const char *getSetterTemplate(bool);
virtual const char *getGetterTemplate(bool);
protected:
@ -295,6 +306,7 @@ protected:
JSEmitter *swig_javascript_create_JSCEmitter();
JSEmitter *swig_javascript_create_V8Emitter();
JSEmitter *swig_javascript_create_NodeJSEmitter();
JSEmitter *swig_javascript_create_NAPIEmitter();
/**********************************************************************
* JAVASCRIPT: SWIG module implementation
@ -514,14 +526,14 @@ int JAVASCRIPT::top(Node *n) {
return SWIG_OK;
}
static const char *usage = (char *) "\
static const char *usage = (char *)"\
Javascript Options (available with -javascript)\n\
-jsc - creates a JavascriptCore extension \n\
-v8 - creates a v8 extension \n\
-node - creates a node.js extension \n\
-napi - creates a NAPI extension \n\
-debug-codetemplates - generates information about the origin of code templates\n";
/* ---------------------------------------------------------------------
* main()
*
@ -557,6 +569,13 @@ void JAVASCRIPT::main(int argc, char *argv[]) {
}
Swig_mark_arg(i);
engine = JSEmitter::NodeJS;
} else if (strcmp(argv[i], "-napi") == 0) {
if (engine != -1) {
Printf(stderr, ERR_MSG_ONLY_ONE_ENGINE_PLEASE);
Exit(EXIT_FAILURE);
}
Swig_mark_arg(i);
engine = JSEmitter::NAPI;
} else if (strcmp(argv[i], "-debug-codetemplates") == 0) {
Swig_mark_arg(i);
js_template_enable_debug = true;
@ -590,9 +609,20 @@ void JAVASCRIPT::main(int argc, char *argv[]) {
SWIG_library_directory("javascript/jsc");
break;
}
case JSEmitter::NAPI:
{
emitter = swig_javascript_create_NAPIEmitter();
Preprocessor_define("SWIG_JAVASCRIPT_NAPI 1", 0);
SWIG_library_directory("javascript/napi");
Preprocessor_define("BUILDING_NODE_EXTENSION 1", 0);
if (!cparse_cplusplus) {
Swig_cparse_cplusplusout(1);
}
break;
}
default:
{
Printf(stderr, "SWIG Javascript: Unknown engine. Please specify one of '-jsc', '-v8' or '-node'.\n");
Printf(stderr, "SWIG Javascript: Unknown engine. Please specify one of '-jsc', '-v8', '-node' or '-napi'.\n");
Exit(EXIT_FAILURE);
break;
}
@ -846,6 +876,26 @@ int JSEmitter::enterVariable(Node *n) {
return SWIG_OK;
}
const char *JSEmitter::getFunctionTemplate(bool) {
return "js_function";
}
const char *JSEmitter::getFunctionDispatcherTemplate(bool) {
return "js_function_dispatcher";
}
const char *JSEmitter::getOverloadedFunctionTemplate(bool) {
return "js_overloaded_function";
}
const char *JSEmitter::getGetterTemplate(bool) {
return "js_getter";
}
const char *JSEmitter::getSetterTemplate(bool) {
return "js_setter";
}
int JSEmitter::emitCtor(Node *n) {
Wrapper *wrapper = NewWrapper();
@ -876,11 +926,13 @@ int JSEmitter::emitCtor(Node *n) {
emitCleanupCode(n, wrapper, params);
t_ctor.replace("$jswrapper", wrap_name)
t_ctor.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.replace("$jsargcount", Getattr(n, ARGCOUNT))
.replace("$jsparent", state.clazz(PARENT_MANGLED))
.replace("$jsargrequired", Getattr(n, ARGREQUIRED))
.pretty_print(f_wrappers);
@ -898,8 +950,10 @@ int JSEmitter::emitCtor(Node *n) {
String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name"));
Template t_mainctor(getTemplate("js_ctor_dispatcher"));
t_mainctor.replace("$jswrapper", wrap_name)
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsdispatchcases", state.clazz(CTOR_DISPATCHERS))
.replace("$jsparent", state.clazz(PARENT_MANGLED))
.pretty_print(f_wrappers);
state.clazz(CTOR, wrap_name);
}
@ -1036,7 +1090,7 @@ int JSEmitter::emitDtor(Node *n) {
int JSEmitter::emitGetter(Node *n, bool is_member, bool is_static) {
Wrapper *wrapper = NewWrapper();
Template t_getter(getTemplate("js_getter"));
Template t_getter(getTemplate(getGetterTemplate(is_member)));
// prepare wrapper name
String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name"));
@ -1055,7 +1109,8 @@ int JSEmitter::emitGetter(Node *n, bool is_member, bool is_static) {
emitCleanupCode(n, wrapper, params);
t_getter.replace("$jswrapper", wrap_name)
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.pretty_print(f_wrappers);
@ -1074,7 +1129,7 @@ int JSEmitter::emitSetter(Node *n, bool is_member, bool is_static) {
Wrapper *wrapper = NewWrapper();
Template t_setter(getTemplate("js_setter"));
Template t_setter(getTemplate(getSetterTemplate(is_member)));
// prepare wrapper name
String *wrap_name = Swig_name_wrapper(Getattr(n, "sym:name"));
@ -1093,7 +1148,8 @@ int JSEmitter::emitSetter(Node *n, bool is_member, bool is_static) {
emitCleanupCode(n, wrapper, params);
t_setter.replace("$jswrapper", wrap_name)
t_setter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.pretty_print(f_wrappers);
@ -1128,7 +1184,8 @@ int JSEmitter::emitConstant(Node *n) {
value = Getattr(n, "cppvalue");
}
Template t_getter(getTemplate("js_getter"));
bool is_member = GetFlag(n, "ismember");
Template t_getter(getTemplate(getGetterTemplate(is_member)));
// call the variable methods as a constants are
// registered in same way
@ -1151,13 +1208,19 @@ int JSEmitter::emitConstant(Node *n) {
marshalOutput(n, 0, wrapper, NewString(""), value, false);
t_getter.replace("$jswrapper", wname)
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wname)
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.pretty_print(f_wrappers);
exitVariable(n);
// This is the counterpart to the "constant" test in
// exitVariable, it prevents double setting of
// symbols that are both constants and variables
SetFlag(n, "constant");
DelWrapper(wrapper);
return SWIG_OK;
@ -1165,7 +1228,7 @@ int JSEmitter::emitConstant(Node *n) {
int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) {
Wrapper *wrapper = NewWrapper();
Template t_function(getTemplate("js_function"));
Template t_function(getTemplate(getFunctionTemplate(is_member)));
bool is_overloaded = GetFlag(n, "sym:overloaded") != 0;
@ -1173,7 +1236,7 @@ int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) {
String *iname = Getattr(n, "sym:name");
String *wrap_name = Swig_name_wrapper(iname);
if (is_overloaded) {
t_function = getTemplate("js_overloaded_function");
t_function = getTemplate(getOverloadedFunctionTemplate(is_member));
Append(wrap_name, Getattr(n, "sym:overname"));
}
Setattr(n, "wrap:name", wrap_name);
@ -1190,7 +1253,8 @@ int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) {
emitCleanupCode(n, wrapper, params);
Replaceall(wrapper->code, "$symname", iname);
t_function.replace("$jswrapper", wrap_name)
t_function.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", wrap_name)
.replace("$jslocals", wrapper->locals)
.replace("$jscode", wrapper->code)
.replace("$jsargcount", Getattr(n, ARGCOUNT))
@ -1202,7 +1266,7 @@ int JSEmitter::emitFunction(Node *n, bool is_member, bool is_static) {
return SWIG_OK;
}
int JSEmitter::emitFunctionDispatcher(Node *n, bool /*is_member */ ) {
int JSEmitter::emitFunctionDispatcher(Node *n, bool is_member) {
Wrapper *wrapper = NewWrapper();
// Generate call list, go to first node
@ -1226,7 +1290,7 @@ int JSEmitter::emitFunctionDispatcher(Node *n, bool /*is_member */ ) {
} while ((sibl = Getattr(sibl, "sym:nextSibling")));
Template t_function(getTemplate("js_function_dispatcher"));
Template t_function(getTemplate(getFunctionDispatcherTemplate(is_member)));
// Note: this dispatcher function gets called after the last overloaded function has been created.
// At this time, n.wrap:name contains the name of the last wrapper function.
@ -1255,6 +1319,7 @@ int JSEmitter::emitFunctionDispatcher(Node *n, bool /*is_member */ ) {
// call this here, to replace all variables
t_function.replace("$jswrapper", final_wrap_name)
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.pretty_print(f_wrappers);
@ -2355,10 +2420,624 @@ int V8Emitter::emitNamespaces() {
return SWIG_OK;
}
/**********************************************************************
* NAPI: JSEmitter implementation for N-API
**********************************************************************/
class NAPIEmitter : public JSEmitter {
public:
NAPIEmitter();
virtual ~NAPIEmitter();
virtual int initialize(Node *n);
virtual int dump(Node *n);
virtual int close();
virtual int enterClass(Node *n);
virtual int exitClass(Node *n);
virtual int enterVariable(Node *n);
virtual int exitVariable(Node *n);
virtual int exitFunction(Node *n);
protected:
virtual void marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper,
MarshallingMode mode, bool is_member,
bool is_static);
virtual int emitNamespaces();
virtual int emitCtor(Node *);
virtual int emitDtor(Node *);
virtual int emitClassMethodDeclaration(Node *);
virtual const char *getFunctionTemplate(bool is_member);
virtual const char *getFunctionDispatcherTemplate(bool is_member);
virtual const char *getOverloadedFunctionTemplate(bool is_member);
virtual const char *getSetterTemplate(bool is_member);
virtual const char *getGetterTemplate(bool is_member);
protected:
/* built-in parts */
String *f_runtime;
String *f_header;
String *f_init;
String *f_post_init;
/* class declarations */
String *f_class_declarations;
/* parts for initilizer */
String *f_init_namespaces;
String *f_init_wrappers;
String *f_init_inheritance;
String *f_init_static_wrappers;
String *f_init_register_classes;
String *f_init_register_namespaces;
// the output cpp file
File *f_wrap_cpp;
String *NULL_STR;
String *VETO_SET;
String *moduleName;
// the current index in the class table
size_t class_idx;
};
NAPIEmitter::NAPIEmitter()
: JSEmitter(JSEmitter::NAPI), NULL_STR(NewString("0")),
VETO_SET(NewString("JS_veto_set_variable")), class_idx(0) {}
NAPIEmitter::~NAPIEmitter() {
Delete(NULL_STR);
Delete(VETO_SET);
}
int NAPIEmitter::initialize(Node *n) {
JSEmitter::initialize(n);
moduleName = Getattr(n, "name");
// Get the output file name
String *outfile = Getattr(n, "outfile");
f_wrap_cpp = NewFile(outfile, "w", SWIG_output_files());
if (!f_wrap_cpp) {
FileErrorDisplay(outfile);
Exit(EXIT_FAILURE);
}
f_runtime = NewString("");
f_header = NewString("");
f_init = NewString("");
f_post_init = NewString("");
f_class_declarations = NewString("");
f_init_namespaces = NewString("");
f_init_wrappers = NewString("");
f_init_inheritance = NewString("");
f_init_static_wrappers = NewString("");
f_init_register_classes = NewString("");
f_init_register_namespaces = NewString("");
// note: this is necessary for built-in generation of SWIG runtime code
Swig_register_filebyname("begin", f_wrap_cpp);
Swig_register_filebyname("runtime", f_runtime);
Swig_register_filebyname("header", f_header);
Swig_register_filebyname("wrapper", f_wrappers);
Swig_register_filebyname("init", f_init);
Swig_register_filebyname("post-init", f_post_init);
state.globals(FORCE_CPP, NewString("1"));
Swig_banner(f_wrap_cpp);
Swig_obligatory_macros(f_runtime, "JAVASCRIPT");
return SWIG_OK;
}
int NAPIEmitter::dump(Node *n) {
/* Get the module name */
String *module = Getattr(n, "name");
Template initializer_define(getTemplate("js_initializer_define"));
initializer_define.replace("$jsname", module).pretty_print(f_header);
SwigType_emit_type_table(f_runtime, f_wrappers);
Printv(f_wrap_cpp, f_runtime, "\n", 0);
Printv(f_wrap_cpp, f_header, "\n", 0);
Printv(f_wrap_cpp, f_class_declarations, "\n", 0);
Printv(f_wrap_cpp, f_wrappers, "\n", 0);
emitNamespaces();
String *inheritance = NewStringEmpty();
if (Len(f_init_inheritance) > 0) {
Template t_inheritance(getTemplate("js_init_inheritance"));
t_inheritance.pretty_print(inheritance);
}
// compose the initializer function using a template
// filled with sub-parts
Template initializer(getTemplate("js_initializer"));
initializer.replace("$jsname", moduleName)
.replace("$jsnapinspaces", f_init_namespaces)
.replace("$jsnapipreinheritance", inheritance)
.replace("$jsnapiinitinheritance", f_init_inheritance)
.replace("$jsnapiregisterclasses", f_init_register_classes)
.replace("$jsnapiregisternspaces", f_init_register_namespaces);
Printv(f_init, initializer.str(), 0);
Printv(f_wrap_cpp, f_init, 0);
Printv(f_wrap_cpp, f_post_init, 0);
Delete(inheritance);
return SWIG_OK;
}
int NAPIEmitter::close() {
Delete(f_runtime);
Delete(f_header);
Delete(f_class_declarations);
Delete(f_init_namespaces);
Delete(f_init_wrappers);
Delete(f_init_inheritance);
Delete(f_init_static_wrappers);
Delete(f_init_register_classes);
Delete(f_init_register_namespaces);
Delete(f_init);
Delete(f_post_init);
Delete(f_wrap_cpp);
return SWIG_OK;
}
const char *NAPIEmitter::getFunctionTemplate(bool is_member) {
return is_member ? "js_function" : "js_global_function";
}
const char *NAPIEmitter::getFunctionDispatcherTemplate(bool is_member) {
return is_member ? "js_function_dispatcher" : "js_global_function_dispatcher";
}
const char *NAPIEmitter::getOverloadedFunctionTemplate(bool is_member) {
return is_member ? "js_overloaded_function" : "js_global_overloaded_function";
}
const char *NAPIEmitter::getGetterTemplate(bool is_member) {
return is_member ? "js_getter" : "js_global_getter";
}
const char *NAPIEmitter::getSetterTemplate(bool is_member) {
return is_member ? "js_setter" : "js_global_setter";
}
int NAPIEmitter::enterClass(Node *n) {
JSEmitter::enterClass(n);
// emit registration of class template
String *idx = NewString("");
Printf(idx, "%d", class_idx++);
Template t_register = getTemplate("jsnapi_registerclass");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsparent", Getattr(state.clazz("nspace"), NAME_MANGLED))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsclassidx", idx)
.trim()
.pretty_print(f_init_register_classes);
Delete(idx);
// emit inheritance
String *baseMangled;
Node *baseClass = getBaseClass(n);
SetFlag(n, IS_WRAPPED);
if (baseClass && GetFlag(baseClass, IS_WRAPPED)) {
String *jsName = NewString("");
String *nspace = Getattr(baseClass, "sym:nspace");
if (Len(nspace) == 0) nspace = Getattr(current_namespace, NAME_MANGLED);
Printf(jsName, "%s_%s", nspace, Getattr(baseClass, "sym:name"));
baseMangled = SwigType_manglestr(jsName);
Delete(jsName);
f_init_wrappers = Copy(Getattr(baseClass, MEMBER_FUNCTIONS));
f_init_static_wrappers = Copy(Getattr(baseClass, STATIC_FUNCTIONS));
} else {
baseMangled = NewString("SWIG_NAPI_ObjectWrap");
f_init_wrappers = NewString("");
f_init_static_wrappers = NewString("");
}
state.clazz(PARENT_MANGLED, baseMangled);
Template t_setup_inheritance(getTemplate("jsnapi_setup_inheritance"));
t_setup_inheritance.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", state.clazz(CTOR))
.replace("$jsname", state.clazz(NAME))
.replace("$jsparent", baseMangled)
.pretty_print(f_init_inheritance);
// emit declaration of a NAPI class template
Template t_decl_class(getTemplate("jsnapi_class_prologue_template"));
t_decl_class.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsparent", baseMangled)
.trim()
.pretty_print(f_class_declarations);
Delete(baseMangled);
return SWIG_OK;
}
int NAPIEmitter::exitClass(Node *n) {
if (GetFlag(state.clazz(), IS_ABSTRACT)) {
Template t_veto_ctor(getTemplate("js_veto_ctor"));
t_veto_ctor.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", state.clazz(CTOR))
.replace("$jsname", state.clazz(NAME))
.replace("$jsparent", state.clazz(PARENT_MANGLED))
.pretty_print(f_wrappers);
}
/* Note: this makes sure that there is a swig_type added for this class */
String *clientData = NewString("");
Printf(clientData, "&%s_clientData", state.clazz(NAME_MANGLED));
/* Note: this makes sure that there is a swig_type added for this class */
SwigType_remember_clientdata(state.clazz(TYPE_MANGLED), NewString("0"));
// emit definition of NAPI class template
Template t_def_class = getTemplate("jsnapi_class_epilogue_template");
t_def_class.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.trim()
.pretty_print(f_class_declarations);
Template t_class_instance = getTemplate("jsnapi_declare_class_instance");
t_class_instance.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.trim()
.pretty_print(f_class_declarations);
Template t_class_template = getTemplate("jsnapi_getclass");
t_class_template.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsnapiwrappers", f_init_wrappers)
.replace("$jsnapistaticwrappers", f_init_static_wrappers)
.replace("$jsparent", state.clazz(PARENT_MANGLED))
.trim()
.pretty_print(f_class_declarations);
/* Save these to be reused in the child classes */
Setattr(n, MEMBER_FUNCTIONS, f_init_wrappers);
Setattr(n, STATIC_FUNCTIONS, f_init_static_wrappers);
return SWIG_OK;
}
int NAPIEmitter::enterVariable(Node *n) {
// Somehow, this is not always reset
// (some constructs like smart pointers reuse Nodes)
UnsetFlag(n, "constant");
JSEmitter::enterVariable(n);
state.variable(GETTER, VETO_SET);
state.variable(SETTER, VETO_SET);
return SWIG_OK;
}
int NAPIEmitter::exitVariable(Node *n) {
// Due to special handling of C++ "static const" member variables
// (refer to the comment in lang.cxx:Language::staticmembervariableHandler)
// a static const member variable may get transformed into a constant
// and be emitted by emitConstant which will result calling exitVariable twice
if (GetFlag(n, "constant")) {
return SWIG_OK;
}
if (GetFlag(n, "ismember")) {
String *modifier = NewStringEmpty();
if (GetFlag(state.variable(), IS_STATIC) ||
Equal(Getattr(n, "nodeType"), "enumitem")) {
Template t_register = getTemplate("jsnapi_register_static_variable");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER) != VETO_SET
? state.variable(SETTER)
: "JS_veto_set_static_variable")
.trim()
.pretty_print(f_init_static_wrappers);
Append(modifier, "static");
} else {
Template t_register = getTemplate("jsnapi_register_member_variable");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER))
.trim()
.pretty_print(f_init_wrappers);
}
// emit declaration of a class member function
Template t_getter = getTemplate("jsnapi_class_method_declaration");
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.replace("$jswrapper", state.variable(GETTER))
.replace("$jsstatic", modifier)
.trim()
.pretty_print(f_class_declarations);
if (state.variable(SETTER) != VETO_SET) {
Template t_setter = getTemplate("jsnapi_class_setter_declaration");
t_setter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.replace("$jswrapper", state.variable(SETTER))
.replace("$jsstatic", modifier)
.trim()
.pretty_print(f_class_declarations);
}
Delete(modifier);
} else {
Template t_register = getTemplate("jsnapi_register_global_variable");
t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED))
.replace("$jsname", state.variable(NAME))
.replace("$jsgetter", state.variable(GETTER))
.replace("$jssetter", state.variable(SETTER))
.trim()
.pretty_print(f_init_register_namespaces);
}
return SWIG_OK;
}
int NAPIEmitter::emitClassMethodDeclaration(Node *) {
// emit declaration of a class member function
Template t_def_class = getTemplate("jsnapi_class_method_declaration");
t_def_class.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.clazz(NAME))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsdtor", state.clazz(DTOR))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.replace("$jsstatic", GetFlag(state.function(), IS_STATIC) ? "static" : "")
.trim()
.pretty_print(f_class_declarations);
return SWIG_OK;
}
int NAPIEmitter::exitFunction(Node *n) {
bool is_member =
GetFlag(n, "ismember") != 0 || GetFlag(n, "feature:extend") != 0;
// create a dispatcher for overloaded functions
bool is_overloaded = GetFlag(n, "sym:overloaded") != 0;
if (is_overloaded) {
emitClassMethodDeclaration(n);
if (!Getattr(n, "sym:nextSibling")) {
emitFunctionDispatcher(n, is_member);
} else {
return SWIG_OK;
}
}
// register the function at the specific context
if (is_member) {
if (GetFlag(state.function(), IS_STATIC)) {
Template t_register = getTemplate("jsnapi_register_static_function");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_static_wrappers);
} else {
Template t_register = getTemplate("jsnapi_register_member_function");
t_register.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_wrappers);
}
emitClassMethodDeclaration(n);
} else {
// Note: a global function is treated like a static function
// with the parent being a nspace object instead of class object
Template t_register = getTemplate("jsnapi_register_global_function");
t_register.replace("$jsparent", Getattr(current_namespace, NAME_MANGLED))
.replace("$jsname", state.function(NAME))
.replace("$jswrapper", state.function(WRAPPER_NAME))
.trim()
.pretty_print(f_init_register_namespaces);
}
return SWIG_OK;
}
void NAPIEmitter::marshalInputArgs(Node *n, ParmList *parms, Wrapper *wrapper,
MarshallingMode mode, bool is_member,
bool is_static) {
Parm *p;
String *tm;
int startIdx = 0;
if (is_member && !is_static && mode != Ctor) {
startIdx = 1;
}
// store number of arguments for argument checks
int num_args = emit_num_arguments(parms) - startIdx;
String *argcount = NewString("");
Printf(argcount, "%d", num_args);
Setattr(n, ARGCOUNT, argcount);
int num_required = emit_num_required(parms) - startIdx;
SetInt(n, ARGREQUIRED, num_required);
int i = 0;
for (p = parms; p;) {
String *arg = NewString("");
String *type = Getattr(p, "type");
// ignore varargs
if (SwigType_isvarargs(type))
break;
switch (mode) {
case Getter:
if (is_member && !is_static && i == 0) {
Printv(arg, "info.This()", 0);
i++;
} else {
Printf(arg, "info[%d]", i - startIdx);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
}
break;
case Function:
if (is_member && !is_static && i == 0) {
Printv(arg, "info.This()", 0);
i++;
} else {
Printf(arg, "info[%d]", i - startIdx);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
}
break;
case Setter:
if (is_member && !is_static && i == 0) {
Printv(arg, "info.This()", 0);
i++;
} else {
Printv(arg, "value", 0);
i++;
}
break;
case Ctor:
Printf(arg, "info[%d]", i);
SetInt(p, INDEX, i - startIdx);
i += GetInt(p, "tmap:in:numinputs");
break;
default:
Printf(stderr, "Illegal MarshallingMode.");
Exit(EXIT_FAILURE);
}
tm = emitInputTypemap(n, p, wrapper, arg);
Delete(arg);
if (tm) {
p = Getattr(p, "tmap:in:next");
} else {
p = nextSibling(p);
}
}
for (p = parms; p;) {
tm = emitCheckTypemap(n, p, wrapper, Getattr(p, "emit:input"));
if (tm) {
p = Getattr(p, "tmap:in:next");
} else {
p = nextSibling(p);
}
}
}
int NAPIEmitter::emitNamespaces() {
Iterator it;
for (it = First(namespaces); it.item; it = Next(it)) {
Hash *entry = it.item;
String *name = Getattr(entry, NAME);
String *name_mangled = Getattr(entry, NAME_MANGLED);
String *parent = Getattr(entry, PARENT);
String *parent_mangled = Getattr(entry, PARENT_MANGLED);
bool do_create = true;
bool do_register = true;
if (Equal(parent, "")) {
do_register = false;
}
// Note: 'exports' is by convention the name of the object where
// globals are stored into
if (Equal(name, "exports")) {
do_create = false;
}
if (do_create) {
// create namespace object and register it to the parent scope
Template t_create_ns = getTemplate("jsnapi_create_namespace");
t_create_ns.replace("$jsmangledname", name_mangled)
.trim()
.pretty_print(f_init_namespaces);
}
if (do_register) {
Template t_register_ns = getTemplate("jsnapi_register_namespace");
t_register_ns.replace("$jsmangledname", name_mangled)
.replace("$jsname", name)
.replace("$jsparent", parent_mangled)
.trim();
// prepend in order to achieve reversed order of registration statements
String *tmp_register_stmt = NewString("");
t_register_ns.pretty_print(tmp_register_stmt);
Insert(f_init_register_namespaces, 0, tmp_register_stmt);
Delete(tmp_register_stmt);
}
}
return SWIG_OK;
}
int NAPIEmitter::emitCtor(Node *n) {
int r;
// Constructor renaming does not work in JavaScript
// This allows us to slip past the unit test which
// is broken for all JavaScript backends
if (GetFlag(n, "sym:overloaded")) {
if (!Getattr(n, "sym:nextSibling")) {
if (GetFlag(state.clazz(), "ctor:dispatcher:emitted")) {
return SWIG_OK;
}
SetFlag(state.clazz(), "ctor:dispatcher:emitted");
}
}
r = JSEmitter::emitCtor(n);
if (r != SWIG_OK)
return r;
Template t_getter = getTemplate("jsnapi_class_method_declaration");
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.replace("$jswrapper", Getattr(n, "wrap:name"))
.replace("$jsmangledtype", state.clazz(TYPE_MANGLED))
.replace("$jsstatic", "")
.trim()
.pretty_print(f_class_declarations);
return SWIG_OK;
}
int NAPIEmitter::emitDtor(Node *n) {
// NAPI destructors must have a class declaration
Template t_getter = getTemplate("jsnapi_class_dtor_declaration");
t_getter.replace("$jsmangledname", state.clazz(NAME_MANGLED))
.trim()
.pretty_print(f_class_declarations);
return JSEmitter::emitDtor(n);
}
JSEmitter *swig_javascript_create_V8Emitter() {
return new V8Emitter();
}
JSEmitter *swig_javascript_create_NAPIEmitter() {
return new NAPIEmitter();
}
/**********************************************************************
* Helper implementations
**********************************************************************/

View File

@ -14,7 +14,7 @@ case "$SWIGLANG" in
;;
"javascript")
case "$ENGINE" in
"node")
"node"|"napi")
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
nvm use ${VER}

View File

@ -40,7 +40,7 @@ case "$SWIGLANG" in
;;
"javascript")
case "$ENGINE" in
"node")
"node"|"napi")
$RETRY wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.10/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
@ -56,6 +56,7 @@ case "$SWIGLANG" in
else
$RETRY npm install -g node-gyp
fi
$RETRY npm install -g node-addon-api
;;
"jsc")
$RETRY sudo apt-get install -qq libjavascriptcoregtk-${VER}-dev

View File

@ -1186,11 +1186,35 @@ else
AC_CHECK_PROGS(NODEJS, [node nodejs])
if test -n "$NODEJS"; then
# node-gyp is needed to run the test-suite/examples
# node-gyp and npm are needed to run the test-suite/examples
AC_CHECK_PROGS(NODEGYP, node-gyp)
if test -z "$NODEGYP"; then
NODEJS=
fi
AC_CHECK_PROGS(NODENPM, npm)
if test -z "$NODENPM"; then
NODEJS=
fi
JSNAPIENABLED=
if test -n "$NODEJS"; then
AC_LANG_PUSH([C++])
NODENAPI_DIR=$(npm config get prefix)/lib/node_modules/node-addon-api
CXXFLAGS_SAVED=$CXXFLAGS
CXXFLAGS="$CXXFLAGS -I/usr/include/node -I/usr/local/include/node -I$NODENAPI_DIR"
AC_CHECK_HEADERS([node_api.h napi.h], [JSNAPIENABLED=1], [])
CXXFLAGS=$CXXFLAGS_SAVED
AC_LANG_POP([C++])
AC_SUBST(NODENAPI_DIR)
fi
AC_SUBST(JSNAPIENABLED)
AC_MSG_CHECKING(for Node-API (napi) generator support)
if test -n "$JSNAPIENABLED"; then
AC_MSG_RESULT(enabled)
else
AC_MSG_RESULT(disabled)
fi
fi
#----------------------------------------------------------------
@ -2624,7 +2648,7 @@ AC_SUBST(SKIP_JAVA)
SKIP_JAVASCRIPT=
if test -z "$JAVASCRIPT" || ( test -z "$NODEJS" && test -z "$JSCENABLED" && test -z "$JSV8ENABLED" ) ; then
if test -z "$JAVASCRIPT" || ( test -z "$NODEJS" && test -z "$JSCENABLED" && test -z "$JSV8ENABLED" && test -z "$JSNAPIENABLED" ) ; then
SKIP_JAVASCRIPT="1"
fi
AC_SUBST(SKIP_JAVASCRIPT)