diff --git a/DESCRIPTION b/DESCRIPTION index 2e297a4..dc35217 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -10,7 +10,7 @@ Authors@R: c( comment = "Author of QuickJS sources and headers") ) Description: An 'R' interface to the 'QuickJS' portable 'JavaScript' - engine. The engine and all 'R' to 'JavaScript' operability is bundled + engine. The engine and all 'R' to 'JavaScript' interopability is bundled within the package, requiring no dependencies beyond a 'C' compiler. License: MIT + file LICENSE URL: https://github.com/andrjohns/QuickJSR, https://bellard.org/quickjs/ diff --git a/NEWS.md b/NEWS.md index efa0d29..6134f8b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,10 @@ +# QuickJSR 1.2.0 + - `Rcpp` dependency replaced with vendored `cpp11` headers + - `R6` dependency removed + - `R` and `JS` interopability added, removing `jsonlite` dependency + - Fixes for libatomic linking on 32-bit systems + - Added `to_json` and `from_json` functions for testing `R`/`JS` interop + # QuickJSR 1.1.0 - Fixed UBSAN error in `JS_Eval` - Fixed compilation errors with older GCC & Clang (`stdatomic.h not found`) diff --git a/inst/include/quickjsr/JSCommonType.hpp b/inst/include/quickjsr/JSCommonType.hpp index 1adfdee..1ff48f8 100644 --- a/inst/include/quickjsr/JSCommonType.hpp +++ b/inst/include/quickjsr/JSCommonType.hpp @@ -14,12 +14,16 @@ enum JSCommonType { Date, NumberArray, Object, + Undefined, Unknown }; JSCommonType JS_ArrayCommonType(JSContext* ctx, const JSValue& val); JSCommonType JS_GetCommonType(JSContext* ctx, const JSValue& val) { + if (JS_IsUndefined(val)) { + return Undefined; + } if (JS_IsBool(val)) { return Logical; } @@ -32,6 +36,9 @@ JSCommonType JS_GetCommonType(JSContext* ctx, const JSValue& val) { if (JS_IsString(val)) { return Character; } + if (JS_IsObject(val)) { + return Object; + } if (JS_IsDate(ctx, val)) { return Date; } @@ -41,9 +48,6 @@ JSCommonType JS_GetCommonType(JSContext* ctx, const JSValue& val) { return NumberArray; } } - if (JS_IsObject(val)) { - return Object; - } return Unknown; } @@ -56,6 +60,9 @@ JSCommonType JS_UpdateCommonType(JSCommonType current, JSContext* ctx, const JSV if (current == new_type) { return current; } + if (new_type == Undefined) { + return current; + } // If one, but not both, types are NumberArray or Date (checked above), return Object if (new_type == NumberArray || current == NumberArray || new_type == Object || new_type == Date || current == Date) { diff --git a/inst/include/quickjsr/JSValue_Date.hpp b/inst/include/quickjsr/JSValue_Date.hpp index 19da2e2..29e48ff 100644 --- a/inst/include/quickjsr/JSValue_Date.hpp +++ b/inst/include/quickjsr/JSValue_Date.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace quickjsr { @@ -15,6 +16,10 @@ inline double get_tz_offset_seconds() { inline bool JS_IsDate(JSContext* ctx, const JSValue& val) { JSValue ctor = JS_GetPropertyStr(ctx, val, "constructor"); + if (JS_IsException(ctor)) { + JS_FreeValue(ctx, ctor); + return false; + } JSValue ctorName = JS_GetPropertyStr(ctx, ctor, "name"); const char* name = JS_ToCString(ctx, ctorName); diff --git a/inst/include/quickjsr/JSValue_to_SEXP.hpp b/inst/include/quickjsr/JSValue_to_SEXP.hpp index 09b383d..25765f9 100644 --- a/inst/include/quickjsr/JSValue_to_SEXP.hpp +++ b/inst/include/quickjsr/JSValue_to_SEXP.hpp @@ -24,6 +24,9 @@ static void js_free_prop_enum(JSContext *ctx, JSPropertyEnum *tab, uint32_t len) SEXP JSValue_to_SEXP(JSContext* ctx, const JSValue& val); SEXP JSValue_to_SEXP_scalar(JSContext* ctx, const JSValue& val) { + if (JS_IsUndefined(val)) { + return R_NilValue; + } if (JS_IsBool(val)) { return cpp11::as_sexp(JSValue_to_Cpp(ctx, val)); } @@ -54,6 +57,8 @@ SEXP JSValue_to_SEXP_vector(JSContext* ctx, const JSValue& val) { return cpp11::as_sexp(JSValue_to_Cpp>(ctx, val)); case Character: return cpp11::as_sexp(JSValue_to_Cpp>(ctx, val)); + case Undefined: + return R_NilValue; case Date: { cpp11::writable::doubles res = cpp11::as_sexp(JSValue_to_Cpp>(ctx, val)); res.attr("class") = "POSIXct"; @@ -95,8 +100,14 @@ SEXP JSValue_to_SEXP_vector(JSContext* ctx, const JSValue& val) { } return out; } - default: - return cpp11::as_sexp("Unsupported type"); + default: { + std::string type_str = "Unsupported type: "; + // Get result of typeof + JSValue typeof_val = JS_GetPropertyStr(ctx, val, "typeof"); + type_str += JSValue_to_Cpp(ctx, typeof_val); + JS_FreeValue(ctx, typeof_val); + return cpp11::as_sexp(type_str.c_str()); + } } } @@ -123,6 +134,9 @@ SEXP JSValue_to_SEXP_list(JSContext* ctx, const JSValue& val) { } SEXP JSValue_to_SEXP(JSContext* ctx, const JSValue& val) { + if (JS_IsUndefined(val)) { + return R_NilValue; + } if (JS_IsArray(ctx, val)) { return JSValue_to_SEXP_vector(ctx, val); } diff --git a/src/quickjsr.cpp b/src/quickjsr.cpp index 251f2cf..7dff563 100644 --- a/src/quickjsr.cpp +++ b/src/quickjsr.cpp @@ -24,8 +24,9 @@ extern "C" SEXP qjs_context_(SEXP stack_size_) { int stack_size = cpp11::as_cpp(stack_size_); RuntimeXPtr rt(JS_NewRuntime()); + // Workaround for RStan stack overflow until they update if (stack_size != -1) { - JS_SetMaxStackSize(rt.get(), stack_size); + JS_SetMaxStackSize(rt.get(), 0); } js_std_init_handlers(rt.get()); ContextXPtr ctx(JS_NewContext(rt.get()));