Created
July 20, 2021 03:37
-
-
Save MCJack123/7383b9ecdff625ef04d8fd8a147b2004 to your computer and use it in GitHub Desktop.
JavaScriptCore integration for CraftOS-PC (bad code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <JavaScriptCore/JavaScriptCore.h> | |
#include <CraftOS-PC.hpp> | |
#include <math.h> | |
#include <float.h> | |
#include <stdarg.h> | |
static JSContext * ctx; | |
static JSValue * Function; | |
static int jsc_call(lua_State *L); | |
static void ObjCToLua(lua_State *L, id obj) { | |
if (obj == nil || [obj isKindOfClass:[NSNull class]]) lua_pushnil(L); | |
else if ([obj isKindOfClass:[NSString class]]) lua_pushlstring(L, [obj UTF8String], [obj length]); | |
else if ([obj isKindOfClass:[NSNumber class]]) lua_pushnumber(L, [obj doubleValue]); | |
else if ([obj isKindOfClass:[NSDictionary class]]) { | |
lua_newtable(L); | |
[obj enumerateKeysAndObjectsUsingBlock:^(id key, id val, BOOL *stop) { | |
ObjCToLua(L, key); | |
ObjCToLua(L, val); | |
lua_settable(L, -3); | |
}]; | |
} else if ([obj isKindOfClass:[NSArray class]]) { | |
lua_newtable(L); | |
for (NSUInteger i = 0; i < [obj count]; i++) { | |
ObjCToLua(L, [obj objectAtIndex:i]); | |
lua_rawseti(L, -2, i + 1); | |
} | |
} else { | |
NSString * name = [obj className]; | |
lua_pushliteral(L, "["); | |
lua_pushlstring(L, [name UTF8String], [name length]); | |
lua_pushliteral(L, "]"); | |
lua_concat(L, 3); | |
[name release]; | |
} | |
} | |
static int jsc_fn_free(lua_State *L) { | |
[*(JSValue**)lua_touserdata(L, 1) release]; | |
return 0; | |
} | |
static bool JSValueToLua(lua_State *L, JSValue * val) { | |
if ([val isUndefined] || [val isNull]) lua_pushnil(L); | |
else if ([val isBoolean]) lua_pushboolean(L, [val toBool]); | |
else if ([val isNumber]) lua_pushnumber(L, [val toDouble]); | |
else if ([val isObject]) { | |
if ([val isInstanceOf:Function]) { | |
*(JSValue**)lua_newuserdata(L, sizeof(val)) = val; | |
lua_createtable(L, 0, 1); | |
lua_pushcfunction(L, jsc_fn_free); | |
lua_setfield(L, -2, "__gc"); | |
lua_setmetatable(L, -2); | |
lua_pushcclosure(L, jsc_call, 1); | |
return false; | |
} | |
NSDictionary * dict = [val toDictionary]; | |
ObjCToLua(L, dict); | |
[dict release]; | |
} else if ([val isArray]) { | |
NSArray * arr = [val toArray]; | |
ObjCToLua(L, arr); | |
[arr release]; | |
} else { | |
NSString * strval = [val toString]; | |
lua_pushlstring(L, strval.UTF8String, strval.length); | |
[strval release]; | |
} | |
return true; | |
} | |
static JSValue * LuaToJSValue(lua_State *L, int idx, JSContext * ctx) { | |
switch (lua_type(L, idx)) { | |
case LUA_TNIL: return [JSValue valueWithNullInContext:ctx]; | |
case LUA_TBOOLEAN: return [JSValue valueWithBool:lua_toboolean(L, idx) inContext:ctx]; | |
case LUA_TNUMBER: return [JSValue valueWithDouble:lua_tonumber(L, idx) inContext:ctx]; | |
case LUA_TSTRING: { | |
size_t len = 0; | |
const char * str = lua_tolstring(L, idx, &len); | |
return [JSValue valueWithObject:[[NSString alloc] initWithBytes:str length:len encoding:NSISOLatin1StringEncoding] inContext:ctx]; | |
} | |
case LUA_TTABLE: { | |
NSMutableArray * keys = [NSMutableArray array]; | |
NSMutableArray * values = [NSMutableArray array]; | |
int i = 0; | |
lua_Integer arraySize = 0; | |
lua_pushnil(L); | |
while (lua_next(L, idx) != 0) { | |
if (arraySize >= 0) { | |
if (lua_type(L, -2) != LUA_TNUMBER) arraySize = -1; | |
else { | |
lua_Number num = lua_tonumber(L, -2); | |
if (fmod(num, 1) > DBL_MIN) arraySize = -1; | |
else if (arraySize < num) arraySize = (lua_Integer)num; | |
} | |
} | |
keys[i] = LuaToJSValue(L, lua_gettop(L) - 1, ctx); | |
values[i++] = LuaToJSValue(L, lua_gettop(L), ctx); | |
lua_pop(L, 1); | |
} | |
if (arraySize > 0) { | |
NSMutableArray * arr = [NSMutableArray arrayWithCapacity:arraySize]; | |
for (int j = 0; j < i; j++) arr[[(NSNumber*)keys[j] integerValue]] = values[j]; | |
[keys release]; | |
[values release]; | |
return [JSValue valueWithObject:arr inContext:ctx]; | |
} else { | |
NSDictionary * dict = [NSDictionary dictionaryWithObjects:values forKeys:keys]; | |
[keys release]; | |
[values release]; | |
return [JSValue valueWithObject:dict inContext:ctx]; | |
} | |
} | |
case LUA_TLIGHTUSERDATA: case LUA_TUSERDATA: case LUA_TTHREAD: return [JSValue valueWithNullInContext:ctx]; // ? | |
case LUA_TFUNCTION: { | |
void * ptr = (void*)lua_topointer(L, idx); | |
lua_getfield(L, LUA_REGISTRYINDEX, "jsc_stack"); | |
lua_State *stack = lua_tothread(L, -1); | |
lua_getfield(L, LUA_REGISTRYINDEX, "jsc_functions"); | |
lua_pushlightuserdata(L, ptr); | |
lua_pushvalue(L, idx); | |
lua_settable(L, -3); | |
lua_pop(L, 2); | |
return [JSValue valueWithObject:^JSValue *() { | |
NSArray * args = [JSContext currentArguments]; | |
lua_getfield(stack, LUA_REGISTRYINDEX, "jsc_functions"); | |
lua_pushlightuserdata(stack, ptr); | |
lua_gettable(stack, -2); | |
lua_remove(stack, -2); | |
for (int i = 0; i < args.count; i++) JSValueToLua(stack, args[i]); | |
int status = lua_pcall(stack, args.count, 1, 0); | |
if (status != 0) { | |
ctx.exception = [JSValue valueWithNewErrorFromMessage:[NSString stringWithCString:lua_tostring(stack, -1) encoding:NSISOLatin1StringEncoding] inContext:ctx]; | |
lua_pop(stack, 1); | |
return [JSValue valueWithNullInContext:ctx]; | |
} | |
JSValue * retval = LuaToJSValue(stack, lua_gettop(stack), ctx); | |
lua_pop(stack, 1); | |
return retval; | |
} inContext:ctx]; | |
} | |
default: return nil; | |
} | |
} | |
static int jsc_call(lua_State *L) { | |
JSValue * fn = *(JSValue**)lua_touserdata(L, lua_upvalueindex(1)); | |
NSMutableArray * args = [NSMutableArray arrayWithCapacity:lua_gettop(L)]; | |
for (int i = 1; i <= lua_gettop(L); i++) args[i-1] = LuaToJSValue(L, i, ctx); | |
ctx.exceptionHandler = ^void(JSContext *context, JSValue *exception) { | |
NSString * err = [exception toString]; | |
lua_pushlstring(L, err.UTF8String, err.length); | |
[err release]; | |
lua_error(L); | |
}; | |
JSValue * retval = [fn callWithArguments:args]; | |
JSValueToLua(L, retval); | |
[retval release]; | |
return 1; | |
} | |
static int jsc_exec(lua_State *L) { | |
size_t len = 0; | |
const char * str = luaL_checklstring(L, 1, &len); | |
NSString * code = [[NSString alloc] initWithBytes:str length:len encoding:NSISOLatin1StringEncoding]; | |
ctx.exceptionHandler = ^void(JSContext *context, JSValue *exception) { | |
NSString * err = [exception toString]; | |
lua_pushlstring(L, err.UTF8String, err.length); | |
[err release]; | |
lua_error(L); | |
}; | |
JSValue * val = [ctx evaluateScript:code]; | |
if (JSValueToLua(L, val)) [val release]; | |
[code release]; | |
return 1; | |
} | |
static int jsc_window_index(lua_State *L) { | |
if (lua_isnumber(L, 2) && fmod(lua_tonumber(L, 2), 1) <= DBL_MIN) JSValueToLua(L, [ctx.globalObject valueAtIndex:lua_tointeger(L, 2)]); | |
else if (lua_isstring(L, 2)) { | |
NSString * key = [NSString stringWithCString:lua_tostring(L, 2) encoding:NSISOLatin1StringEncoding]; | |
JSValueToLua(L, [ctx.globalObject valueForProperty:key]); | |
[key release]; | |
} else lua_pushnil(L); | |
return 1; | |
} | |
static int jsc_window_newindex(lua_State *L) { | |
id val = LuaToJSValue(L, 3, ctx); | |
if (lua_isnumber(L, 2) && fmod(lua_tonumber(L, 2), 1) <= DBL_MIN) [ctx.globalObject setValue:val atIndex:lua_tointeger(L, 2)]; | |
else if (lua_isstring(L, 2)) { | |
NSString * key = [NSString stringWithCString:lua_tostring(L, 2) encoding:NSISOLatin1StringEncoding]; | |
[ctx.globalObject setValue:val forProperty:key]; | |
[key release]; | |
} | |
[val release]; | |
return 0; | |
} | |
static luaL_Reg jsc_lib[] = { | |
{"exec", jsc_exec}, | |
{NULL, NULL} | |
}; | |
static PluginInfo info("jsc"); | |
extern "C" { | |
PluginInfo * plugin_init(const PluginFunctions * func, const path_t& path) { | |
ctx = [[JSContext alloc] init]; | |
Function = [ctx evaluateScript:@"Function"]; | |
return &info; | |
} | |
int luaopen_jsc(lua_State *L) { | |
lua_newtable(L); | |
lua_setfield(L, LUA_REGISTRYINDEX, "jsc_functions"); | |
lua_newthread(L); | |
lua_setfield(L, LUA_REGISTRYINDEX, "jsc_stack"); | |
luaL_register(L, "jsc", jsc_lib); | |
lua_newtable(L); | |
lua_createtable(L, 0, 2); | |
lua_pushcfunction(L, jsc_window_index); | |
lua_setfield(L, -2, "__index"); | |
lua_pushcfunction(L, jsc_window_newindex); | |
lua_setfield(L, -2, "__newindex"); | |
lua_setmetatable(L, -2); | |
lua_setfield(L, -2, "window"); | |
return 1; | |
} | |
void plugin_deinit(PluginInfo * info) { | |
[ctx release]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment