diff --git a/.gitignore b/.gitignore index 796b96d..b1f9f76 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /build +/node_modules \ No newline at end of file diff --git a/README.md b/README.md index f4e5f18..ec0a689 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,13 @@ After building, try running: If you like it, use and/or fork it. Corrections and improvements are welcome. +Using with windows +----------- + +You would need to install `npm install --global --production windows-build-tools`. + +It's also necessary to add `%SWI_HOME_DIR%\bin` to PATH. + Basic usage ----------- diff --git a/binding.gyp b/binding.gyp index 1860877..bc5c9fb 100644 --- a/binding.gyp +++ b/binding.gyp @@ -1,14 +1,15 @@ { "targets": [ { - "target_name": "libswipl", + "target_name": "swipl", "product_prefix": "lib", "sources": [ "./src/libswipl.cc" ], "include_dirs": [ "./src", - "$(SWI_HOME_DIR)/include" + "$(SWI_HOME_DIR)/include", + "=0.10.0", - "libswipl": ">=5.10.0" - }, - "scripts": { - "install": "node-gyp configure build", - "test": "node tests/a.js" - } + "name": "node-swipl", + "version": "0.2.0", + "main": "swipl.js", + "description": "A node.js interface to the SWI-Prolog library", + "keywords": [ + "swi", + "prolog", + "swipl", + "logic" + ], + "author": { + "name": "Tom Klonikowski", + "email": "klonik_t@informatik.haw-hamburg.de" + }, + "license": "LGPL", + "repository": { + "type": "git", + "url": "git@github.com:jansegre/node-swipl.git" + }, + "directories": { + "src": "src", + "tests": "tests" + }, + "engines": { + "node": ">=0.10.0", + "libswipl": ">=5.10.0" + }, + "scripts": { + "install": "node-gyp configure build", + "test": "node tests/a.js" + }, + "dependencies": { + "nan": "^2.4.0" + } } diff --git a/src/libswipl.cc b/src/libswipl.cc index f27ab6c..bc39464 100644 --- a/src/libswipl.cc +++ b/src/libswipl.cc @@ -21,21 +21,22 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include -#include -#include -#include -#include +#include #include + #include "libswipl.h" -using namespace v8; -using namespace node; +template +using Handle = v8::Handle; + +using v8::FunctionTemplate; +using v8::Local; +using v8::Array; Handle ExportSolution(term_t t, int len, Handle result_terms, Handle varnames); -module_t GetModule(const Arguments& args, int idx) { +module_t GetModule(const FunctionCallbackInfo& args, int idx) { module_t mo = NULL; if (args.Length() > idx && !(args[idx]->IsUndefined() || args[idx]->IsNull()) && args[idx]->IsString()) { @@ -44,28 +45,28 @@ module_t GetModule(const Arguments& args, int idx) { return mo; } -Handle Initialise(const Arguments& args) { +void Initialise(const FunctionCallbackInfo& info) { int rval; - const char *plav[2]; + const char *plav[3]; HandleScope scope; /* make the argument vector for Prolog */ - String::Utf8Value str(args[0]); + String::Utf8Value str(info[0]); plav[0] = *str; plav[1] = "--quiet"; - plav[2] = NULL; + plav[2] = nullptr; /* initialise Prolog */ rval = PL_initialise(2, (char **) plav); - return scope.Close(Number::New(rval)); + info.GetReturnValue().Set(Nan::New(rval)); } Handle CreateException(const char *msg) { - Handle result = Object::New(); - result->Set(String::New("exc"), String::New(msg)); + Handle result = Nan::New(); + result->Set(Nan::New("exc").ToLocalChecked(), Nan::New(msg).ToLocalChecked()); return result; } @@ -86,20 +87,20 @@ const char* GetExceptionString(term_t term) { /** * */ -Handle TermType(const Arguments& args) { +void TermType(const FunctionCallbackInfo& info) { int rval = 0; HandleScope scope; term_t term = PL_new_term_ref(); - rval = PL_chars_to_term(*String::Utf8Value(args[0]), term); + rval = PL_chars_to_term(*String::Utf8Value(info[0]), term); if (rval) { rval = PL_term_type(term); } - return scope.Close(Number::New(rval)); + info.GetReturnValue().Set(Nan::New(rval)); } void ExportTerm(term_t t, Handle result, Handle varnames) { int rval = 0; - Handle key = varnames->Get(Integer::New(t)); + Handle key = varnames->Get(t); Handle val; char *c; int i = 0; @@ -109,15 +110,15 @@ void ExportTerm(term_t t, Handle result, Handle varnames) { switch (type) { case PL_FLOAT: rval = PL_get_float(t, &d); - val = Number::New(d); + val = Nan::New(d); break; case PL_INTEGER: rval = PL_get_integer(t, &i); - val = Integer::New(i); + val = Nan::New(i); break; default: rval = PL_get_chars(t, &c, CVT_ALL); - val = String::New(c); + val = Nan::New(c).ToLocalChecked(); break; } if (rval) { @@ -134,38 +135,38 @@ Handle ExportSolution(term_t t, int len, Handle result_terms, return result_terms; } -Handle Cleanup(const Arguments& args) { +void Cleanup(const FunctionCallbackInfo& args) { HandleScope scope; int rval = PL_cleanup(0); - return scope.Close(Number::New(rval)); + args.GetReturnValue().Set(Nan::New(rval)); } Query::Query() { } -; + Query::~Query() { } -; + void Query::Init(Handle target) { // Prepare constructor template - Local tpl = FunctionTemplate::New(Open); - tpl->SetClassName(String::NewSymbol("Query")); + Local tpl = Nan::New(Open); + tpl->SetClassName(Nan::New("Query").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(3); // Prototype - tpl->PrototypeTemplate()->Set(String::NewSymbol("next_solution"), - FunctionTemplate::New(NextSolution)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("close"), - FunctionTemplate::New(Close)->GetFunction()); - tpl->PrototypeTemplate()->Set(String::NewSymbol("exception"), - FunctionTemplate::New(Exception)->GetFunction()); - - Persistent constructor = Persistent::New( - tpl->GetFunction()); - target->Set(String::NewSymbol("Query"), constructor); + tpl->PrototypeTemplate()->Set(Nan::New("next_solution").ToLocalChecked(), + Nan::New(NextSolution)); + tpl->PrototypeTemplate()->Set(Nan::New("close").ToLocalChecked(), + Nan::New(Close)); + tpl->PrototypeTemplate()->Set(Nan::New("exception").ToLocalChecked(), + Nan::New(Exception)); + + + auto constructor = Nan::GetFunction(tpl).ToLocalChecked(); + Nan::Set(target, Nan::New("Query").ToLocalChecked(), constructor); } -Handle Query::Open(const Arguments& args) { +void Query::Open(const FunctionCallbackInfo& args) { HandleScope scope; Query* obj = new Query(); @@ -178,13 +179,14 @@ Handle Query::Open(const Arguments& args) { if (args.Length() > 1 && args[0]->IsString() && args[1]->IsArray()) { int rval = 0; String::Utf8Value predicate(args[0]); - if (obj->cb_log) - obj->cb_log("Query::Open predicate: %s(", *predicate); + if (obj->cb_log) { + obj->cb_log("Query::Open predicate: %s(", *predicate); + } Handle terms = Handle::Cast(args[1]); predicate_t p = PL_predicate(*predicate, terms->Length(), module_name); obj->term = PL_new_term_refs(terms->Length()); obj->term_len = terms->Length(); - obj->varnames = Persistent::New(Object::New()); + obj->varnames.Reset(Nan::New()); term_t t = obj->term; for (unsigned int i = 0; i < terms->Length(); i++) { Local v = terms->Get(i); @@ -206,7 +208,7 @@ Handle Query::Open(const Arguments& args) { obj->cb_log(" [%i]", type); switch (type) { case PL_VARIABLE: - obj->varnames->Set(Integer::New(t), String::New(*s)); + Nan::New(obj->varnames)->Set(t, Nan::New(*s).ToLocalChecked()); break; case PL_ATOM: case PL_TERM: @@ -225,29 +227,28 @@ Handle Query::Open(const Arguments& args) { obj->cb_log(") #%li\n", obj->qid); if (obj->qid == 0) { - ThrowException( - Exception::Error( - String::New("not enough space on the environment stack"))); - return scope.Close(Undefined()); + Nan::ThrowError( + v8::Exception::Error( + Nan::New("not enough space on the environment stack").ToLocalChecked())); + args.GetReturnValue().SetUndefined(); } else if (rval == 0) { - ThrowException( - Exception::Error( - String::New(GetExceptionString(PL_exception(obj->qid))))); - return scope.Close(Undefined()); + Nan::ThrowError( + v8::Exception::Error( + Nan::New(GetExceptionString(PL_exception(obj->qid))).ToLocalChecked())); + args.GetReturnValue().SetUndefined(); } else { obj->open = OPEN; obj->Wrap(args.This()); - return args.This(); + args.GetReturnValue().Set(args.This()); } } else { - ThrowException( - Exception::SyntaxError( - String::New("invalid arguments (pred, [ args ], module)"))); - return scope.Close(Undefined()); + Nan::ThrowError( + v8::Exception::SyntaxError(Nan::New("invalid arguments (pred, [ args ], module)").ToLocalChecked())); + args.GetReturnValue().SetUndefined(); } } -Handle Query::NextSolution(const Arguments& args) { +void Query::NextSolution(const FunctionCallbackInfo& args) { HandleScope scope; int rval = 0; @@ -262,19 +263,17 @@ Handle Query::NextSolution(const Arguments& args) { obj->cb_log(": %i\n", rval); if (rval) { - return scope.Close( - ExportSolution(obj->term, obj->term_len, Object::New(), - obj->varnames)); + args.GetReturnValue().Set(ExportSolution(obj->term, obj->term_len, Nan::New(), Nan::New(obj->varnames))); } else { - return scope.Close(Boolean::New(false)); + args.GetReturnValue().Set(false); } } else { - ThrowException(Exception::Error(String::New("query is closed"))); - return scope.Close(Undefined()); + Nan::ThrowError(v8::Exception::Error(Nan::New("query is closed").ToLocalChecked())); + args.GetReturnValue().SetUndefined(); } } -Handle Query::Exception(const Arguments& args) { +void Query::Exception(const FunctionCallbackInfo& args) { HandleScope scope; Query* obj = ObjectWrap::Unwrap(args.This()); @@ -282,14 +281,14 @@ Handle Query::Exception(const Arguments& args) { obj->cb_log("Query::Exception #%li\n", obj->qid); term_t term = PL_exception(obj->qid); - if (term) { - return scope.Close(CreateException(GetExceptionString(term))); + if (term) { + args.GetReturnValue().Set(CreateException(GetExceptionString(term))); } else { - return scope.Close(Boolean::New(false)); + args.GetReturnValue().Set(Nan::True()); } } -Handle Query::Close(const Arguments& args) { +void Query::Close(const FunctionCallbackInfo& args) { HandleScope scope; Query* obj = ObjectWrap::Unwrap(args.This()); @@ -300,18 +299,21 @@ Handle Query::Close(const Arguments& args) { obj->open = CLOSED; } - return scope.Close(Boolean::New(true)); + args.GetReturnValue().Set(true); } -extern "C" void init(Handle target) { - target->Set(String::NewSymbol("initialise"), - FunctionTemplate::New(Initialise)->GetFunction()); - target->Set(String::NewSymbol("term_type"), - FunctionTemplate::New(TermType)->GetFunction()); - target->Set(String::NewSymbol("cleanup"), - FunctionTemplate::New(Cleanup)->GetFunction()); + +NAN_MODULE_INIT(init) { + Nan::Set(target, Nan::New("initialise").ToLocalChecked(), + Nan::GetFunction(Nan::New(Initialise)).ToLocalChecked()); + + Nan::Set(target, Nan::New("term_type").ToLocalChecked(), + Nan::GetFunction(Nan::New(TermType)).ToLocalChecked()); + + Nan::Set(target, Nan::New("cleanup").ToLocalChecked(), + Nan::GetFunction(Nan::New(Cleanup)).ToLocalChecked()); + Query::Init(target); } NODE_MODULE(libswipl, init) - diff --git a/src/libswipl.h b/src/libswipl.h index 3798657..27ae33f 100644 --- a/src/libswipl.h +++ b/src/libswipl.h @@ -24,20 +24,24 @@ #ifndef NODE_LIBSWIPL_H_ #define NODE_LIBSWIPL_H_ -#include -#include +#include #include -using namespace v8; -using namespace node; +using v8::String; +using v8::Object; +using v8::Value; +using Nan::HandleScope; +using v8::Number; +using FunctionCallbackInfo = Nan::FunctionCallbackInfo; +using Nan::Persistent; -Handle Initialise(const Arguments& args); +void Initialise(const FunctionCallbackInfo&); -Handle TermType(const Arguments& args); +void TermType(const FunctionCallbackInfo&); -Handle Cleanup(const Arguments& args); +void Cleanup(const FunctionCallbackInfo&); -class Query : public node::ObjectWrap { +class Query : public Nan::ObjectWrap { public: static const int OPEN = 1; static const int CLOSED = 0; @@ -47,10 +51,11 @@ class Query : public node::ObjectWrap { Query(); ~Query(); - static v8::Handle Open(const v8::Arguments& args); - static v8::Handle NextSolution(const v8::Arguments& args); - static v8::Handle Close(const v8::Arguments& args); - static v8::Handle Exception(const v8::Arguments& args); + static void Open(const FunctionCallbackInfo& args); + static void NextSolution(const FunctionCallbackInfo& args); + static void Close(const FunctionCallbackInfo& args); + static void Exception(const FunctionCallbackInfo& args); + int open; qid_t qid; term_t term;