説明なし

main.c 7.2KB

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <JavaScriptCore/JavaScript.h> #include "zip.h" #define CONSOLE_LOG_BUF_SIZE 1000 char console_log_buf[CONSOLE_LOG_BUF_SIZE]; JSStringRef to_string(JSContextRef ctx, JSValueRef val); JSValueRef evaluate_script(JSContextRef ctx, char *script, char *source); void bootstrap(JSContextRef ctx, char *deps_file_path, char *goog_base_path); char* get_contents(char *path); JSValueRef function_console_log(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { for (int i = 0; i < argumentCount; i++) { if (i > 0) { fprintf(stdout, " "); } JSStringRef str = to_string(ctx, arguments[i]); JSStringGetUTF8CString(str, console_log_buf, CONSOLE_LOG_BUF_SIZE); fprintf(stdout, "%s", console_log_buf); } fprintf(stdout, "\n"); return JSValueMakeUndefined(ctx); } JSValueRef function_console_error(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { for (int i = 0; i < argumentCount; i++) { if (i > 0) { fprintf(stderr, " "); } JSStringRef str = to_string(ctx, arguments[i]); JSStringGetUTF8CString(str, console_log_buf, CONSOLE_LOG_BUF_SIZE); fprintf(stderr, "%s", console_log_buf); } fprintf(stderr, "\n"); return JSValueMakeUndefined(ctx); } JSValueRef function_import_script(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { if (argumentCount == 1 && JSValueGetType(ctx, arguments[0]) == kJSTypeString) { JSStringRef path_str_ref = JSValueToStringCopy(ctx, arguments[0], NULL); char path[100]; path[0] = '\0'; JSStringGetUTF8CString(path_str_ref, path, 100); JSStringRelease(path_str_ref); char full_path[150]; snprintf(full_path, 150, "%s/%s", "out", path); char *buf = get_contents(full_path); if (buf == NULL) { goto err; } evaluate_script(ctx, buf, full_path); free(buf); } return JSValueMakeUndefined(ctx); err: // TODO: Fill exception with error from errno return JSValueMakeUndefined(ctx); } void register_global_function(JSContextRef ctx, char *name, JSObjectCallAsFunctionCallback handler) { JSObjectRef global_obj = JSContextGetGlobalObject(ctx); JSStringRef fn_name = JSStringCreateWithUTF8CString(name); JSObjectRef fn_obj = JSObjectMakeFunctionWithCallback(ctx, fn_name, handler); JSObjectSetProperty(ctx, global_obj, fn_name, fn_obj, kJSPropertyAttributeNone, NULL); } int main(int argc, char **argv) { JSGlobalContextRef ctx = JSGlobalContextCreate(NULL); JSStringRef nameRef = JSStringCreateWithUTF8CString("jsc-test"); JSGlobalContextSetName(ctx, nameRef); JSObjectRef global_obj = JSContextGetGlobalObject(ctx); register_global_function(ctx, "IMPORT_SCRIPT", function_import_script); register_global_function(ctx, "CONSOLE_LOG", function_console_log); register_global_function(ctx, "CONSOLE_ERROR", function_console_error); evaluate_script(ctx, "var console = {};"\ "console.log = CONSOLE_LOG;"\ "console.error = CONSOLE_ERROR;", "<init>"); bootstrap(ctx, "out/main.js", "out/goog/base.js"); char *script; if (argc == 0) { script = "CONSOLE_LOG(\"Hello, World!\");"; } else { script = argv[1]; } JSValueRef res = evaluate_script(ctx, script, "<inline>"); char res_buf[1000]; res_buf[0] = '\0'; JSStringRef res_str = to_string(ctx, res); JSStringGetUTF8CString(res_str, res_buf, 1000); printf("%s\n", res_buf); } JSStringRef to_string(JSContextRef ctx, JSValueRef val) { if (JSValueIsUndefined(ctx, val)) { return JSStringCreateWithUTF8CString("undefined"); } else if (JSValueIsNull(ctx, val)) { return JSStringCreateWithUTF8CString("null"); } else { JSStringRef to_string_name = JSStringCreateWithUTF8CString("toString"); JSObjectRef obj = JSValueToObject(ctx, val, NULL); JSValueRef to_string = JSObjectGetProperty(ctx, obj, to_string_name, NULL); JSObjectRef to_string_obj = JSValueToObject(ctx, to_string, NULL); JSValueRef obj_val = JSObjectCallAsFunction(ctx, to_string_obj, obj, 0, NULL, NULL); return JSValueToStringCopy(ctx, obj_val, NULL); } } JSValueRef evaluate_script(JSContextRef ctx, char *script, char *source) { JSStringRef script_ref = JSStringCreateWithUTF8CString(script); JSStringRef source_ref = NULL; if (source != NULL) { source_ref = JSStringCreateWithUTF8CString(source); } JSValueRef ex = NULL; JSValueRef val = JSEvaluateScript(ctx, script_ref, NULL, source_ref, 0, &ex); JSStringRelease(script_ref); if (source != NULL) { JSStringRelease(source_ref); } #ifdef DEBUG if (ex != NULL) { printf("\n---\n%s\n---\n", script); JSStringRef ex_str = to_string(ctx, ex); char ex_buf[1000]; ex_buf[0] = '\0'; JSStringGetUTF8CString(ex_str, ex_buf, 1000); printf("eval %s: %s\n", source, ex_buf); JSStringRelease(ex_str); } #endif return val; } void bootstrap(JSContextRef ctx, char *deps_file_path, char *goog_base_path) { char source[] = "<bootstrap>"; // Setup CLOSURE_IMPORT_SCRIPT evaluate_script(ctx, "CLOSURE_IMPORT_SCRIPT = function(src) { IMPORT_SCRIPT('goog/' + src); return true; }", source); // Load goog base char *base_script_str = get_contents(goog_base_path); if (base_script_str == NULL) { fprintf(stderr, "The goog base JavaScript text could not be loaded"); exit(1); } evaluate_script(ctx, base_script_str, "<bootstrap:base>"); free(base_script_str); // Load the deps file char *deps_script_str = get_contents(deps_file_path); if (deps_script_str == NULL) { fprintf(stderr, "The goog base JavaScript text could not be loaded"); exit(1); } evaluate_script(ctx, deps_script_str, "<bootstrap:deps>"); free(deps_script_str); evaluate_script(ctx, "goog.isProvided_ = function(x) { return false; };", source); evaluate_script(ctx, "goog.require = function (name) { return CLOSURE_IMPORT_SCRIPT(goog.dependencies_.nameToPath[name]); };", source); evaluate_script(ctx, "goog.require('cljs.core');", source); // redef goog.require to track loaded libs evaluate_script(ctx, "cljs.core._STAR_loaded_libs_STAR_ = cljs.core.into.call(null, cljs.core.PersistentHashSet.EMPTY, [\"cljs.core\"]);\n" "goog.require = function (name, reload) {\n" " if(!cljs.core.contains_QMARK_(cljs.core._STAR_loaded_libs_STAR_, name) || reload) {\n" " var AMBLY_TMP = cljs.core.PersistentHashSet.EMPTY;\n" " if (cljs.core._STAR_loaded_libs_STAR_) {\n" " AMBLY_TMP = cljs.core._STAR_loaded_libs_STAR_;\n" " }\n" " cljs.core._STAR_loaded_libs_STAR_ = cljs.core.into.call(null, AMBLY_TMP, [name]);\n" " CLOSURE_IMPORT_SCRIPT(goog.dependencies_.nameToPath[name]);\n" " }\n" "};", source); } char *get_contents(char *path) { FILE *f = fopen(path, "r"); if (f == NULL) { perror("fopen"); goto err; } struct stat f_stat; if (fstat(fileno(f), &f_stat) < 0) { perror("fstat"); goto err; } char *buf = malloc(f_stat.st_size); memset(buf, 0, f_stat.st_size); fread(buf, f_stat.st_size, 1, f); buf[f_stat.st_size] = '\0'; if (ferror(f)) { perror("fread"); free(buf); goto err; } if (fclose(f) < 0) { perror("fclose"); goto err; } return buf; err: return NULL; }