Skip to content

Commit

Permalink
Test Wpedantic warnings when moving all C functions to C++ files
Browse files Browse the repository at this point in the history
  • Loading branch information
andrjohns committed May 12, 2024
1 parent db93896 commit e2bee09
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 135 deletions.
8 changes: 4 additions & 4 deletions src/Makevars
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PKG_CPPFLAGS = -I"../inst/include/" -DSTRICT_R_HEADERS -D_GNU_SOURCE -DCONFIG_BIGNUM
PKG_CPPFLAGS = -I"../inst/include/" -D_GNU_SOURCE -DCONFIG_BIGNUM
PKG_CPPFLAGS += -DCONFIG_VERSION=\"$(shell cat quickjs/VERSION)\"
PKG_LIBS = ../inst/lib/$(R_ARCH)/libquickjs.a

Expand Down Expand Up @@ -31,8 +31,8 @@ QUICKJS_C_HEADERS = $(QUICKJS_C_FILES:.c=.h) \
QUICKJS_SOURCES = $(QUICKJS_C_FILES:%=quickjs/%)
QUICKJS_OBJECTS = $(QUICKJS_SOURCES:.c=.o)

SOURCES = quickjsr_impl.c quickjsr.cpp init.cpp
OBJECTS = quickjsr_impl.o quickjsr.o init.o
SOURCES = quickjsr.cpp init.cpp
OBJECTS = quickjsr.o init.o

.PHONY: all package-quickjs build-static

Expand All @@ -50,7 +50,7 @@ build-static: $(QUICKJS_OBJECTS)
$(AR) -rs ../inst/lib/$(R_ARCH)/libquickjs.a $(QUICKJS_OBJECTS)

$(QUICKJS_OBJECTS): quickjs/%.o : quickjs/%.c
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -funsigned-char -fwrapv -std=c11 -c $< -o $@
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -DSTRICT_R_HEADERS -funsigned-char -fwrapv -std=c11 -c $< -o $@

clean:
$(RM) $(QUICKJS_OBJECTS) ../inst/lib/$(R_ARCH)/libquickjs.a
114 changes: 80 additions & 34 deletions src/quickjsr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,12 @@
#include <cpp11/declarations.hpp>
#include <fstream>
#include <sstream>

using JSvalue = struct JSValue;
using JSRuntime = struct JSRuntime;
using JSContext = struct JSContext;

// We compile the functions as a separate C translation unit, as the QuickJS
// C headers trigger -Wpedantic warnings under C++
#ifdef __cplusplus
extern "C" {
#endif

JSRuntime* JS_NewRuntime(void);
void JS_SetMaxStackSize(JSRuntime* rt, size_t stack_size);
JSContext* JS_NewContext(JSRuntime* rt);
void JS_FreeContext(JSContext* ctx);
void JS_FreeRuntime(JSRuntime* rt);
void js_std_init_handlers(JSRuntime *rt);
void js_std_add_helpers(JSContext *ctx, int argc, char **argv);

bool qjs_source_impl(JSContext* ctx, const char* code_string);
bool qjs_validate_impl(JSContext* ctx, const char* function_name);
const char* qjs_call_impl(JSContext* ctx, const char* wrapped_name,
const char* call_wrapper, const char* args_json);
const char* qjs_eval_impl(const char* eval_string);

#ifdef __cplusplus
}
#endif
#include <quickjs-libc.h>

// Register the cpp11 external pointer types with the correct cleanup/finaliser functions
using ContextXPtr = cpp11::external_pointer<JSContext, JS_FreeContext>;
using RuntimeXPtr = cpp11::external_pointer<JSRuntime, JS_FreeRuntime>;


extern "C" SEXP qjs_context_(SEXP stack_size_) {
BEGIN_CPP11
int stack_size = cpp11::as_cpp<int>(stack_size_);
Expand All @@ -61,18 +33,49 @@ extern "C" SEXP qjs_source_(SEXP ctx_ptr_, SEXP code_string_) {
BEGIN_CPP11
JSContext* ctx = ContextXPtr(ctx_ptr_).get();
std::string code_string = cpp11::as_cpp<std::string>(code_string_);
return cpp11::as_sexp(qjs_source_impl(ctx, code_string.c_str()));
JSValue val = JS_Eval(ctx, code_string.c_str(), code_string.size(), "", 0);
bool failed = JS_IsException(val);
if (failed) {
js_std_dump_error(ctx);
}
JS_FreeValue(ctx, val);
return cpp11::as_sexp(!failed);
END_CPP11
}

extern "C" SEXP qjs_validate_(SEXP ctx_ptr_, SEXP code_string_) {
BEGIN_CPP11
JSContext* ctx = ContextXPtr(ctx_ptr_).get();
std::string code_string = cpp11::as_cpp<std::string>(code_string_);
return cpp11::as_sexp(qjs_validate_impl(ctx, code_string.c_str()));
JSValue val = JS_Eval(ctx, code_string.c_str(), code_string.size(), "", JS_EVAL_FLAG_COMPILE_ONLY);
bool failed = JS_IsException(val);
JS_FreeValue(ctx, val);
return cpp11::as_sexp(!failed);
END_CPP11
}

const char* JS_ValToJSON(JSContext* ctx, JSValue* val) {
JSValue global = JS_GetGlobalObject(ctx);
JSValue json = JS_GetPropertyStr(ctx, global, "JSON");
JSValue stringify = JS_GetPropertyStr(ctx, json, "stringify");

JSValue result_js = JS_Call(ctx, stringify, global, 1, val);
const char* result;
if (JS_IsException(result_js)) {
js_std_dump_error(ctx);
result = "Error!";
} else {
result = JS_ToCString(ctx, result_js);
}

JS_FreeValue(ctx, result_js);
JS_FreeValue(ctx, stringify);
JS_FreeValue(ctx, json);
JS_FreeValue(ctx, global);

return result;
}

extern "C" SEXP qjs_call_(SEXP ctx_ptr_, SEXP function_name_, SEXP args_json_) {
BEGIN_CPP11
JSContext* ctx = ContextXPtr(ctx_ptr_).get();
Expand All @@ -85,14 +88,57 @@ extern "C" SEXP qjs_call_(SEXP ctx_ptr_, SEXP function_name_, SEXP args_json_) {
"function " + wrapped_name + "(args_object) { return " + function_name +
"(...Object.values(JSON.parse(args_object))); }";

return cpp11::as_sexp(qjs_call_impl(ctx, wrapped_name.c_str(), call_wrapper.c_str(),
args_json.c_str()));
JSValue tmp = JS_Eval(ctx, call_wrapper.c_str(), call_wrapper.size(), "", 0);
bool failed = JS_IsException(tmp);
JS_FreeValue(ctx, tmp);
if (failed) {
js_std_dump_error(ctx);
return cpp11::as_sexp("Error!");
}

JSValue global = JS_GetGlobalObject(ctx);
JSValue function_wrapper = JS_GetPropertyStr(ctx, global, wrapped_name.c_str());
JSValue args[] = {
JS_NewString(ctx, args_json.c_str())
};

JSValue result_js = JS_Call(ctx, function_wrapper, global, 1, args);
const char* result;
if (JS_IsException(result_js)) {
js_std_dump_error(ctx);
result = "Error!";
} else {
result = JS_ValToJSON(ctx, &result_js);
}

JS_FreeValue(ctx, result_js);
JS_FreeValue(ctx, args[0]);
JS_FreeValue(ctx, function_wrapper);
JS_FreeValue(ctx, global);

return cpp11::as_sexp(result);
END_CPP11
}

extern "C" SEXP qjs_eval_(SEXP eval_string_) {
BEGIN_CPP11
std::string eval_string = cpp11::as_cpp<std::string>(eval_string_);
return cpp11::as_sexp(qjs_eval_impl(eval_string.c_str()));
JSRuntime* rt = JS_NewRuntime();
JSContext* ctx = JS_NewContext(rt);

JSValue val = JS_Eval(ctx, eval_string.c_str(), eval_string.size(), "", 0);
const char* result;
if (JS_IsException(val)) {
js_std_dump_error(ctx);
result = "Error!";
} else {
result = JS_ValToJSON(ctx, &val);
}

JS_FreeValue(ctx, val);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);

return cpp11::as_sexp(result);
END_CPP11
}
97 changes: 0 additions & 97 deletions src/quickjsr_impl.c

This file was deleted.

0 comments on commit e2bee09

Please sign in to comment.