2020-04-25 13:33:17 +00:00
|
|
|
#include <limits.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <cutils.h>
|
|
|
|
#include <quickjs.h>
|
|
|
|
|
|
|
|
#include "com_thebrokenrail_scriptcraft_quickjs_QuickJS.h"
|
|
|
|
#include "console.h"
|
|
|
|
|
|
|
|
static JavaVM *jvm;
|
|
|
|
|
2020-04-25 17:25:37 +00:00
|
|
|
static void *get_pointer(JNIEnv *env, jobject obj, const char *name) {
|
2020-04-25 13:33:17 +00:00
|
|
|
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
|
|
|
jfieldID field = (*env)->GetFieldID(env, clazz, name, "J");
|
|
|
|
return (void *) (long) (*env)->GetLongField(env, obj, field);
|
|
|
|
}
|
|
|
|
|
2020-04-25 17:25:37 +00:00
|
|
|
static void set_pointer(JNIEnv *env, jobject obj, const char *name, void *value) {
|
2020-04-25 13:33:17 +00:00
|
|
|
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
|
|
|
jfieldID field = (*env)->GetFieldID(env, clazz, name, "J");
|
|
|
|
(*env)->SetLongField(env, obj, field, (jlong) (long) value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *js_module_normalize_name(JSContext *ctx, const char *base_name, const char *name, void *opaque) {
|
|
|
|
JNIEnv *env;
|
|
|
|
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
|
|
|
|
|
|
|
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
|
|
|
jmethodID methodID = (*env)->GetStaticMethodID(env, clazz, "normalizeModule", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
|
|
|
|
|
|
|
|
jstring java_name = (*env)->NewStringUTF(env, name);
|
|
|
|
jstring java_base_name = (*env)->NewStringUTF(env, base_name);
|
|
|
|
jstring java_string = (jstring) (*env)->CallStaticObjectMethod(env, clazz, methodID, java_base_name, java_name);
|
|
|
|
(*env)->DeleteLocalRef(env, java_name);
|
|
|
|
(*env)->DeleteLocalRef(env, java_base_name);
|
|
|
|
|
|
|
|
if (java_string) {
|
|
|
|
const char *native_string = (*env)->GetStringUTFChars(env, java_string, 0);
|
|
|
|
char *new_string = js_strdup(ctx, native_string);
|
|
|
|
(*env)->ReleaseStringUTFChars(env, java_string, native_string);
|
|
|
|
|
|
|
|
(*env)->DeleteLocalRef(env, java_string);
|
|
|
|
|
|
|
|
(*jvm)->DetachCurrentThread(jvm);
|
|
|
|
return new_string;
|
|
|
|
} else {
|
|
|
|
jthrowable err = (*env)->ExceptionOccurred(env);
|
|
|
|
if (err) {
|
|
|
|
jmethodID to_string = (*env)->GetMethodID(env, (*env)->FindClass(env, "java/lang/Object"), "toString", "()Ljava/lang/String;");
|
|
|
|
jstring java_string = (jstring) (*env)->CallObjectMethod(env, err, to_string);
|
|
|
|
const char *str = (*env)->GetStringUTFChars(env, java_string, 0);
|
|
|
|
|
|
|
|
JS_ThrowReferenceError(ctx, "could not normalize module name '%s': %s", name, str);
|
|
|
|
|
|
|
|
(*env)->ExceptionClear(env);
|
|
|
|
} else {
|
|
|
|
JS_ThrowReferenceError(ctx, "could not normalize module name '%s'", name);
|
|
|
|
}
|
|
|
|
(*jvm)->DetachCurrentThread(jvm);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val, JS_BOOL use_realpath, JS_BOOL is_main) {
|
|
|
|
JSModuleDef *m;
|
|
|
|
char buf[PATH_MAX + 16];
|
|
|
|
JSValue meta_obj;
|
|
|
|
JSAtom module_name_atom;
|
|
|
|
const char *module_name;
|
|
|
|
|
|
|
|
assert(JS_VALUE_GET_TAG(func_val) == JS_TAG_MODULE);
|
|
|
|
m = JS_VALUE_GET_PTR(func_val);
|
|
|
|
|
|
|
|
module_name_atom = JS_GetModuleName(ctx, m);
|
|
|
|
module_name = JS_AtomToCString(ctx, module_name_atom);
|
|
|
|
JS_FreeAtom(ctx, module_name_atom);
|
|
|
|
if (!module_name) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!strchr(module_name, ':')) {
|
|
|
|
strcpy(buf, "file://");
|
|
|
|
}
|
|
|
|
pstrcpy(buf, sizeof(buf), module_name);
|
|
|
|
JS_FreeCString(ctx, module_name);
|
|
|
|
|
|
|
|
meta_obj = JS_GetImportMeta(ctx, m);
|
|
|
|
if (JS_IsException(meta_obj)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
JS_DefinePropertyValueStr(ctx, meta_obj, "url", JS_NewString(ctx, buf), JS_PROP_C_W_E);
|
|
|
|
JS_DefinePropertyValueStr(ctx, meta_obj, "main", JS_NewBool(ctx, is_main), JS_PROP_C_W_E);
|
|
|
|
JS_FreeValue(ctx, meta_obj);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *js_load_file(JSContext *ctx, const char *filename) {
|
|
|
|
JNIEnv *env;
|
|
|
|
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
|
|
|
|
|
|
|
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
|
|
|
jmethodID methodID = (*env)->GetStaticMethodID(env, clazz, "loadModule", "(Ljava/lang/String;)Ljava/lang/String;");
|
|
|
|
|
|
|
|
jstring java_filename = (*env)->NewStringUTF(env, filename);
|
|
|
|
jstring java_string = (jstring) (*env)->CallStaticObjectMethod(env, clazz, methodID, java_filename);
|
|
|
|
(*env)->DeleteLocalRef(env, java_filename);
|
|
|
|
|
|
|
|
if (java_string) {
|
|
|
|
const char *native_string = (*env)->GetStringUTFChars(env, java_string, 0);
|
|
|
|
char *new_string = js_strdup(ctx, native_string);
|
|
|
|
(*env)->ReleaseStringUTFChars(env, java_string, native_string);
|
|
|
|
|
|
|
|
(*env)->DeleteLocalRef(env, java_string);
|
|
|
|
|
|
|
|
(*jvm)->DetachCurrentThread(jvm);
|
|
|
|
return new_string;
|
|
|
|
} else {
|
|
|
|
jthrowable err = (*env)->ExceptionOccurred(env);
|
|
|
|
if (err) {
|
|
|
|
jmethodID to_string = (*env)->GetMethodID(env, (*env)->FindClass(env, "java/lang/Object"), "toString", "()Ljava/lang/String;");
|
|
|
|
jstring java_string = (jstring) (*env)->CallObjectMethod(env, err, to_string);
|
|
|
|
const char *str = (*env)->GetStringUTFChars(env, java_string, 0);
|
|
|
|
|
|
|
|
JS_ThrowReferenceError(ctx, "could not load module filename '%s': %s", filename, str);
|
|
|
|
|
|
|
|
(*env)->ExceptionClear(env);
|
|
|
|
} else {
|
|
|
|
JS_ThrowReferenceError(ctx, "could not load module filename '%s'", filename);
|
|
|
|
}
|
|
|
|
(*jvm)->DetachCurrentThread(jvm);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSModuleDef *js_module_loader(JSContext *ctx, const char *module_name, void *opaque) {
|
|
|
|
JSModuleDef *m;
|
|
|
|
|
|
|
|
char *buf;
|
|
|
|
JSValue func_val;
|
|
|
|
|
|
|
|
buf = js_load_file(ctx, module_name);
|
|
|
|
if (!buf) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_json = has_suffix(module_name, ".json");
|
|
|
|
if (is_json) {
|
|
|
|
asprintf(&buf, "export default JSON.parse(`%s`);", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* compile the module */
|
|
|
|
func_val = JS_Eval(ctx, buf, strlen(buf), module_name, JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
|
|
|
js_free(ctx, buf);
|
|
|
|
if (JS_IsException(func_val)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* XXX: could propagate the exception */
|
|
|
|
js_module_set_import_meta(ctx, func_val, 1, 0);
|
|
|
|
/* the module is already referenced, so we must free it */
|
|
|
|
m = JS_VALUE_GET_PTR(func_val);
|
|
|
|
JS_FreeValue(ctx, func_val);
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2020-04-25 17:25:37 +00:00
|
|
|
static void throw_exception(JNIEnv *env, const char *message) {
|
2020-04-25 13:33:17 +00:00
|
|
|
jclass exception_clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/JSException");
|
|
|
|
(*env)->ThrowNew(env, exception_clazz, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSClassID JS_CLASS_JAVA_OBJECT_ID;
|
|
|
|
|
|
|
|
typedef struct java_object_data {
|
|
|
|
jobject obj;
|
|
|
|
} java_object_data;
|
|
|
|
|
|
|
|
static void java_object_finalizer(JSRuntime *rt, JSValue val) {
|
|
|
|
java_object_data *data = JS_GetOpaque(val, JS_CLASS_JAVA_OBJECT_ID);
|
|
|
|
if (data) {
|
|
|
|
JNIEnv *env;
|
|
|
|
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
|
|
|
|
|
|
|
(*env)->DeleteGlobalRef(env, data->obj);
|
|
|
|
js_free_rt(rt, data);
|
|
|
|
|
|
|
|
(*jvm)->DetachCurrentThread(jvm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSClassDef JS_CLASS_JAVA_OBJECT = {
|
|
|
|
"JavaObject",
|
|
|
|
.finalizer = java_object_finalizer
|
|
|
|
};
|
|
|
|
|
|
|
|
static JSValue java_object_to_js_object(JNIEnv *env, JSContext *ctx, jobject obj) {
|
|
|
|
JSValue out = JS_NULL;
|
|
|
|
|
|
|
|
jclass boolean_clazz = (*env)->FindClass(env, "java/lang/Boolean");
|
|
|
|
jclass double_clazz = (*env)->FindClass(env, "java/lang/Double");
|
|
|
|
jclass string_clazz = (*env)->FindClass(env, "java/lang/String");
|
|
|
|
jclass array_clazz = (*env)->FindClass(env, "[Ljava/lang/Object;");
|
|
|
|
if ((*env)->IsInstanceOf(env, obj, string_clazz)) {
|
|
|
|
const char *native_string = (*env)->GetStringUTFChars(env, (jstring) obj, 0);
|
|
|
|
out = JS_NewString(ctx, native_string);
|
|
|
|
(*env)->ReleaseStringUTFChars(env, (jstring) obj, native_string);
|
|
|
|
} else if ((*env)->IsInstanceOf(env, obj, boolean_clazz)) {
|
|
|
|
jmethodID boolean_methodID = (*env)->GetMethodID(env, boolean_clazz, "booleanValue", "()Z");
|
|
|
|
jboolean val = (*env)->CallBooleanMethod(env, obj, boolean_methodID);
|
|
|
|
out = JS_NewBool(ctx, val);
|
|
|
|
} else if ((*env)->IsInstanceOf(env, obj, double_clazz)) {
|
|
|
|
jmethodID double_methodID = (*env)->GetMethodID(env, double_clazz, "doubleValue", "()D");
|
|
|
|
jdouble val = (*env)->CallDoubleMethod(env, obj, double_methodID);
|
|
|
|
out = JS_NewFloat64(ctx, val);
|
|
|
|
} else if ((*env)->IsInstanceOf(env, obj, array_clazz)) {
|
|
|
|
out = JS_NewArray(ctx);
|
|
|
|
|
|
|
|
int length = (*env)->GetArrayLength(env, (jobjectArray) obj);
|
|
|
|
for (uint32_t i = 0; i < length; i++) {
|
|
|
|
JS_SetPropertyUint32(ctx, out, i, java_object_to_js_object(env, ctx, (*env)->GetObjectArrayElement(env, obj, i)));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
java_object_data *data = js_mallocz(ctx, sizeof (java_object_data));
|
|
|
|
data->obj = (*env)->NewGlobalRef(env, obj);
|
|
|
|
out = JS_NewObjectClass(ctx, JS_CLASS_JAVA_OBJECT_ID);
|
|
|
|
JS_SetOpaque(out, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
static jobject js_object_to_java_object(JNIEnv *env, JSContext *ctx, JSValue input) {
|
|
|
|
jobject obj = NULL;
|
|
|
|
if (JS_IsBool(input)) {
|
|
|
|
int val = JS_ToBool(ctx, input);
|
|
|
|
|
|
|
|
jclass boolean_clazz = (*env)->FindClass(env, "java/lang/Boolean");
|
|
|
|
jmethodID methodID = (*env)->GetMethodID(env, boolean_clazz, "<init>", "(Z)V");
|
|
|
|
obj = (*env)->NewObject(env, boolean_clazz, methodID, val);
|
|
|
|
} else if (JS_IsNumber(input)) {
|
|
|
|
double val;
|
|
|
|
JS_ToFloat64(ctx, &val, input);
|
|
|
|
|
|
|
|
jclass double_clazz = (*env)->FindClass(env, "java/lang/Double");
|
|
|
|
jmethodID methodID = (*env)->GetMethodID(env, double_clazz, "<init>", "(D)V");
|
|
|
|
obj = (*env)->NewObject(env, double_clazz, methodID, val);
|
|
|
|
} else if (JS_IsString(input)) {
|
|
|
|
const char *val = JS_ToCString(ctx, input);
|
|
|
|
obj = (*env)->NewStringUTF(env, val);
|
|
|
|
JS_FreeCString(ctx, val);
|
|
|
|
} else if (JS_IsArray(ctx, input)) {
|
|
|
|
uint32_t length;
|
|
|
|
|
|
|
|
JSValue js_length = JS_GetPropertyStr(ctx, input, "length");
|
|
|
|
JS_ToUint32(ctx, &length, js_length);
|
|
|
|
JS_FreeValue(ctx, js_length);
|
|
|
|
|
|
|
|
jclass obj_clazz = (*env)->FindClass(env, "java/lang/Object");
|
|
|
|
jobjectArray arr = (*env)->NewObjectArray(env, length, obj_clazz, NULL);
|
|
|
|
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
JSValue element = JS_GetPropertyUint32(ctx, input, i);
|
|
|
|
jobject obj = js_object_to_java_object(env, ctx, element);
|
|
|
|
(*env)->SetObjectArrayElement(env, arr, i - 1, obj);
|
|
|
|
(*env)->DeleteLocalRef(env, obj);
|
|
|
|
JS_FreeValue(ctx, element);
|
|
|
|
}
|
|
|
|
|
|
|
|
obj = arr;
|
|
|
|
} else {
|
|
|
|
java_object_data *data = JS_GetOpaque(input, JS_CLASS_JAVA_OBJECT_ID);
|
|
|
|
if (data) {
|
|
|
|
obj = (*env)->NewLocalRef(env, data->obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
static JSValue js_bridge(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
|
|
|
|
JNIEnv *env;
|
|
|
|
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
|
|
|
|
|
|
|
jclass obj_clazz = (*env)->FindClass(env, "java/lang/Object");
|
|
|
|
jobjectArray arr = (*env)->NewObjectArray(env, argc - 1, obj_clazz, NULL);
|
|
|
|
|
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
jobject obj = js_object_to_java_object(env, ctx, argv[i]);
|
|
|
|
(*env)->SetObjectArrayElement(env, arr, i - 1, obj);
|
|
|
|
(*env)->DeleteLocalRef(env, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/bridge/Bridges");
|
|
|
|
jmethodID methodID = (*env)->GetStaticMethodID(env, clazz, "useBridge", "(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/Object;");
|
|
|
|
|
|
|
|
const char *js_bridge_name = JS_ToCString(ctx, argv[0]);
|
|
|
|
jstring bridge_name = (*env)->NewStringUTF(env, js_bridge_name);
|
|
|
|
|
|
|
|
jobject out = (*env)->CallStaticObjectMethod(env, clazz, methodID, bridge_name, arr);
|
|
|
|
|
|
|
|
(*env)->DeleteLocalRef(env, bridge_name);
|
|
|
|
(*env)->DeleteLocalRef(env, arr);
|
|
|
|
|
|
|
|
JSValue js_out;
|
|
|
|
if (out) {
|
|
|
|
js_out = java_object_to_js_object(env, ctx, out);
|
|
|
|
(*env)->DeleteLocalRef(env, out);
|
|
|
|
} else {
|
|
|
|
jthrowable err = (*env)->ExceptionOccurred(env);
|
|
|
|
if (err) {
|
|
|
|
jmethodID to_string = (*env)->GetMethodID(env, (*env)->FindClass(env, "java/lang/Object"), "toString", "()Ljava/lang/String;");
|
|
|
|
jstring java_string = (jstring) (*env)->CallObjectMethod(env, err, to_string);
|
|
|
|
const char *str = (*env)->GetStringUTFChars(env, java_string, 0);
|
|
|
|
|
|
|
|
js_out = JS_ThrowReferenceError(ctx, "unable to use bridge '%s': %s", js_bridge_name, str);
|
|
|
|
|
|
|
|
(*env)->ExceptionClear(env);
|
|
|
|
} else {
|
|
|
|
js_out = JS_NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_FreeCString(ctx, js_bridge_name);
|
|
|
|
|
|
|
|
(*jvm)->DetachCurrentThread(jvm);
|
|
|
|
|
|
|
|
return js_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
JNIEXPORT jobject JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_bridge(JNIEnv *env, jobject this_val, jstring bridge_name, jobjectArray arr) {
|
|
|
|
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
|
|
|
|
|
|
|
int length = (*env)->GetArrayLength(env, arr);
|
|
|
|
JSValue args[length];
|
|
|
|
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
args[i] = java_object_to_js_object(env, ctx, (*env)->GetObjectArrayElement(env, arr, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
JSValue global_obj = JS_GetGlobalObject(ctx);
|
|
|
|
JSValue scriptcraft_obj = JS_GetPropertyStr(ctx, global_obj, "__scriptcraft__");
|
|
|
|
JSValue bridges = JS_GetPropertyStr(ctx, scriptcraft_obj, "bridges");
|
|
|
|
|
|
|
|
const char *native_string = (*env)->GetStringUTFChars(env, bridge_name, 0);
|
|
|
|
JSValue bridge = JS_GetPropertyStr(ctx, bridges, native_string);
|
|
|
|
(*env)->ReleaseStringUTFChars(env, bridge_name, native_string);
|
|
|
|
|
|
|
|
JSValue out;
|
|
|
|
if (JS_IsFunction(ctx, bridge)) {
|
|
|
|
out = JS_Call(ctx, bridge, global_obj, length, args);
|
|
|
|
if (JS_IsException(out)) {
|
|
|
|
js_std_dump_error(ctx);
|
|
|
|
out = JS_NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
out = JS_NULL;
|
|
|
|
throw_exception(env, "Invalid Bridge");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < length; i++) {
|
|
|
|
JS_FreeValue(ctx, args[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_FreeValue(ctx, bridge);
|
|
|
|
JS_FreeValue(ctx, bridges);
|
|
|
|
JS_FreeValue(ctx, scriptcraft_obj);
|
|
|
|
JS_FreeValue(ctx, global_obj);
|
|
|
|
|
|
|
|
jobject java_out = js_object_to_java_object(env, ctx, out);
|
|
|
|
JS_FreeValue(ctx, out);
|
|
|
|
|
|
|
|
return java_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_init(JNIEnv *env, jobject this_val) {
|
|
|
|
jint rc = (*env)->GetJavaVM(env, &jvm);
|
|
|
|
if (rc != JNI_OK) {
|
|
|
|
throw_exception(env, "qjs: unable to cache JavaVM");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSRuntime *rt = JS_NewRuntime();
|
|
|
|
if (!rt) {
|
|
|
|
throw_exception(env, "qjs: cannot allocate JS runtime");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
JSContext *ctx = JS_NewContext(rt);
|
|
|
|
if (!ctx) {
|
|
|
|
throw_exception(env, "qjs: cannot allocate JS context");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_SetModuleLoaderFunc(rt, js_module_normalize_name, js_module_loader, NULL);
|
|
|
|
|
|
|
|
js_console_init(ctx);
|
|
|
|
|
|
|
|
JSValue global_obj = JS_GetGlobalObject(ctx);
|
|
|
|
|
|
|
|
JSValue scriptcraft_obj = JS_NewObject(ctx);
|
|
|
|
JS_SetPropertyStr(ctx, scriptcraft_obj, "bridges", JS_NewObject(ctx));
|
|
|
|
JS_SetPropertyStr(ctx, scriptcraft_obj, "useBridge", JS_NewCFunction(ctx, js_bridge, "useBridge", 1));
|
|
|
|
JS_SetPropertyStr(ctx, global_obj, "__scriptcraft__", scriptcraft_obj);
|
|
|
|
|
|
|
|
JS_FreeValue(ctx, global_obj);
|
|
|
|
|
|
|
|
JS_NewClassID(&JS_CLASS_JAVA_OBJECT_ID);
|
|
|
|
JS_NewClass(JS_GetRuntime(ctx), JS_CLASS_JAVA_OBJECT_ID, &JS_CLASS_JAVA_OBJECT);
|
|
|
|
JS_SetClassProto(ctx, JS_CLASS_JAVA_OBJECT_ID, JS_NewObject(ctx));
|
|
|
|
|
|
|
|
set_pointer(env, this_val, "rt", rt);
|
|
|
|
set_pointer(env, this_val, "ctx", ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_free(JNIEnv *env, jobject this_val) {
|
|
|
|
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
|
|
|
JSRuntime *rt = (JSRuntime *) get_pointer(env, this_val, "rt");
|
|
|
|
|
|
|
|
JS_FreeContext(ctx);
|
|
|
|
JS_FreeRuntime(rt);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int eval_buf(JNIEnv *env, JSContext *ctx, const void *buf, int buf_len, const char *filename, int eval_flags) {
|
|
|
|
JSValue val;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((eval_flags & JS_EVAL_TYPE_MASK) == JS_EVAL_TYPE_MODULE) {
|
|
|
|
/* for the modules, we compile then run to be able to set
|
|
|
|
import.meta */
|
|
|
|
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags | JS_EVAL_FLAG_COMPILE_ONLY);
|
|
|
|
if (!JS_IsException(val)) {
|
|
|
|
js_module_set_import_meta(ctx, val, TRUE, TRUE);
|
|
|
|
val = JS_EvalFunction(ctx, val);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
val = JS_Eval(ctx, buf, buf_len, filename, eval_flags);
|
|
|
|
}
|
|
|
|
if (JS_IsException(val)) {
|
|
|
|
js_std_dump_error(ctx);
|
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
JS_FreeValue(ctx, val);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
JNIEXPORT void JNICALL Java_com_thebrokenrail_scriptcraft_quickjs_QuickJS_run(JNIEnv *env, jobject this_val, jstring data) {
|
|
|
|
JSContext *ctx = (JSContext *) get_pointer(env, this_val, "ctx");
|
|
|
|
|
|
|
|
const char *native_string = (*env)->GetStringUTFChars(env, data, 0);
|
|
|
|
eval_buf(env, ctx, native_string, strlen(native_string), "<init>", JS_EVAL_TYPE_MODULE);
|
|
|
|
(*env)->ReleaseStringUTFChars(env, data, native_string);
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_data(char *data, int err) {
|
|
|
|
JNIEnv *env;
|
|
|
|
(*jvm)->AttachCurrentThread(jvm, (void **) &env, NULL);
|
|
|
|
|
|
|
|
jclass clazz = (*env)->FindClass(env, "com/thebrokenrail/scriptcraft/quickjs/QuickJS");
|
|
|
|
jmethodID print_methodID = (*env)->GetStaticMethodID(env, clazz, "print", "(Ljava/lang/String;Z)V");
|
|
|
|
jstring str = (*env)->NewStringUTF(env, data);
|
|
|
|
(*env)->CallStaticVoidMethod(env, clazz, print_methodID, str, err);
|
|
|
|
(*env)->DeleteLocalRef(env, str);
|
|
|
|
|
|
|
|
(*jvm)->DetachCurrentThread(jvm);
|
|
|
|
}
|