inline value call(HVM vm, const char* funcpath, const value* argv = 0, unsigned argn = 0) { value function = value_by_path(vm,funcpath); if( is_function(function) || is_native_function(function)) return call(vm, get_current_ns(vm), function, argv, argn); else return v_undefined(); }
value current_ns() { assert(vm); return get_current_ns(vm); }
inline value call(HVM vm, value function, const value* argv = 0, unsigned argn = 0) { return call(vm, get_current_ns(vm), function, argv, argn); }
inline value eval(HVM vm, const WCHAR* text) { return eval( vm, get_current_ns(vm), text); }
inline value eval(HVM vm, stream& input, bool template_mode = false) { return eval( vm, get_current_ns(vm), &input, template_mode); }
bool process_line(repl_t *repl, JSContextRef ctx, char *input_line) { // Accumulate input lines if (repl->input == NULL) { repl->input = input_line; } else { repl->input = realloc(repl->input, (strlen(repl->input) + strlen(input_line) + 2) * sizeof(char)); sprintf(repl->input + strlen(repl->input), "\n%s", input_line); } repl->num_previous_lines += 1; repl->previous_lines = realloc(repl->previous_lines, repl->num_previous_lines * sizeof(char *)); repl->previous_lines[repl->num_previous_lines - 1] = strdup(input_line); // Check for explicit exit if (strcmp(repl->input, ":cljs/quit") == 0 || strcmp(repl->input, "quit") == 0 || strcmp(repl->input, "exit") == 0) { if (repl->session_id == 0) { exit_value = EXIT_SUCCESS_INTERNAL; } return true; } // Add input line to history if (repl->history_path != NULL && !is_whitespace(repl->input)) { linenoiseHistoryAdd(input_line); linenoiseHistorySave(repl->history_path); } // Check if we now have readable forms // and if so, evaluate them bool done = false; char *balance_text = NULL; while (!done) { if ((balance_text = cljs_is_readable(ctx, repl->input)) != NULL) { repl->input[strlen(repl->input) - strlen(balance_text)] = '\0'; if (!is_whitespace(repl->input)) { // Guard against empty string being read pthread_mutex_lock(&eval_lock); return_termsize = !config.dumb_terminal; if (repl->session_id == 0) { set_int_handler(); } // TODO: set exit value char *theme = repl->session_id == 0 ? config.theme : "dumb"; evaluate_source(ctx, "text", repl->input, true, true, repl->current_ns, theme, true, repl->session_id); if (repl->session_id == 0) { clear_int_handler(); } return_termsize = false; pthread_mutex_unlock(&eval_lock); if (exit_value != 0) { free(repl->input); return true; } } else { printf("\n"); } // Now that we've evaluated the input, reset for next round free(repl->input); repl->input = balance_text; empty_previous_lines(repl); // Fetch the current namespace and use it to set the prompt free(repl->current_ns); free(repl->current_prompt); repl->current_ns = get_current_ns(ctx); repl->current_prompt = form_prompt(repl->current_ns, false); if (is_whitespace(balance_text)) { done = true; free(repl->input); repl->input = NULL; } } else { // Prepare for reading non-1st of input with secondary prompt if (repl->history_path != NULL) { repl->indent_space_count = cljs_indent_space_count(ctx, repl->input); } free(repl->current_prompt); repl->current_prompt = form_prompt(repl->current_ns, true); done = true; } } return false; }
int main(int argc, char **argv) { struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"legal", no_argument, NULL, 'l'}, {"verbose", no_argument, NULL, 'v'}, {"quiet", no_argument, NULL, 'q'}, {"repl", no_argument, NULL, 'r'}, {"static-fns", no_argument, NULL, 's'}, {"elide-asserts", no_argument, NULL, 'a'}, {"cache", required_argument, NULL, 'k'}, {"eval", required_argument, NULL, 'e'}, {"theme", required_argument, NULL, 't'}, {"classpath", required_argument, NULL, 'c'}, {"auto-cache", no_argument, NULL, 'K'}, {"init", required_argument, NULL, 'i'}, {"main", required_argument, NULL, 'm'}, // development options {"javascript", no_argument, NULL, 'j'}, {"out", required_argument, NULL, 'o'}, {0, 0, 0, 0} }; int opt, option_index; while ((opt = getopt_long(argc, argv, "h?lvrsak:je:t:c:o:Ki:qm:", long_options, &option_index)) != -1) { switch (opt) { case 'h': usage(argv[0]); exit(0); case 'l': legal(); return 0; case 'v': verbose = true; break; case 'q': quiet = true; break; case 'r': repl = true; break; case 's': static_fns = true; break; case 'a': elide_asserts = true; break; case 'k': cache_path = argv[optind - 1]; break; case 'K': cache_path = ".planck_cache"; { char *path_copy = strdup(cache_path); char *dir = dirname(path_copy); if (mkdir_p(dir) < 0) { fprintf(stderr, "Could not create %s: %s\n", cache_path, strerror(errno)); } free(path_copy); } break; case 'j': javascript = true; break; case 'e': num_scripts += 1; scripts = realloc(scripts, num_scripts * sizeof(struct script)); scripts[num_scripts - 1].type = "text"; scripts[num_scripts - 1].expression = true; scripts[num_scripts - 1].source = argv[optind - 1]; break; case 'i': num_scripts += 1; scripts = realloc(scripts, num_scripts * sizeof(struct script)); scripts[num_scripts - 1].type = "path"; scripts[num_scripts - 1].expression = false; scripts[num_scripts - 1].source = argv[optind - 1]; break; case 'm': main_ns_name = argv[optind - 1]; case 't': theme = argv[optind - 1]; break; case 'c': { char *classpath = argv[optind - 1]; char *source = strtok(classpath, ":"); while (source != NULL) { char *type = "src"; if (str_has_suffix(source, ".jar") == 0) { type = "jar"; } num_src_paths += 1; src_paths = realloc(src_paths, num_src_paths * sizeof(struct src_path)); src_paths[num_src_paths - 1].type = type; src_paths[num_src_paths - 1].path = strdup(source); source = strtok(NULL, ":"); } break; } case 'o': out_path = argv[optind - 1]; break; case '?': usage(argv[0]); exit(1); default: printf("unhandled argument: %c\n", opt); } } int num_rest_args = 0; char **rest_args = NULL; if (optind < argc) { num_rest_args = argc - optind; rest_args = malloc((argc - optind) * sizeof(char*)); int i = 0; while (optind < argc) { rest_args[i++] = argv[optind++]; } } if (num_scripts == 0 && main_ns_name == NULL && num_rest_args == 0) { repl = true; } if (main_ns_name != NULL && repl) { printf("Only one main-opt can be specified."); } JSGlobalContextRef ctx = JSGlobalContextCreate(NULL); global_ctx = ctx; JSStringRef nameRef = JSStringCreateWithUTF8CString("planck"); JSGlobalContextSetName(ctx, nameRef); evaluate_script(ctx, "var global = this;", "<init>"); register_global_function(ctx, "AMBLY_IMPORT_SCRIPT", function_import_script); bootstrap(ctx, out_path); register_global_function(ctx, "PLANCK_CONSOLE_LOG", function_console_log); register_global_function(ctx, "PLANCK_CONSOLE_ERROR", function_console_error); evaluate_script(ctx, "var console = {};"\ "console.log = PLANCK_CONSOLE_LOG;"\ "console.error = PLANCK_CONSOLE_ERROR;", "<init>"); evaluate_script(ctx, "var PLANCK_VERSION = \"" PLANCK_VERSION "\";", "<init>"); // require app namespaces evaluate_script(ctx, "goog.require('planck.repl');", "<init>"); // without this things won't work evaluate_script(ctx, "var window = global;", "<init>"); register_global_function(ctx, "PLANCK_READ_FILE", function_read_file); register_global_function(ctx, "PLANCK_LOAD", function_load); register_global_function(ctx, "PLANCK_LOAD_DEPS_CLJS_FILES", function_load_deps_cljs_files); register_global_function(ctx, "PLANCK_CACHE", function_cache); register_global_function(ctx, "PLANCK_EVAL", function_eval); register_global_function(ctx, "PLANCK_GET_TERM_SIZE", function_get_term_size); register_global_function(ctx, "PLANCK_PRINT_FN", function_print_fn); register_global_function(ctx, "PLANCK_PRINT_ERR_FN", function_print_err_fn); register_global_function(ctx, "PLANCK_SET_EXIT_VALUE", function_set_exit_value); is_tty = isatty(STDIN_FILENO) == 1; register_global_function(ctx, "PLANCK_RAW_READ_STDIN", function_raw_read_stdin); register_global_function(ctx, "PLANCK_RAW_WRITE_STDOUT", function_raw_write_stdout); register_global_function(ctx, "PLANCK_RAW_FLUSH_STDOUT", function_raw_flush_stdout); register_global_function(ctx, "PLANCK_RAW_WRITE_STDERR", function_raw_write_stderr); register_global_function(ctx, "PLANCK_RAW_FLUSH_STDERR", function_raw_flush_stderr); register_global_function(ctx, "PLANCK_REQUEST", function_http_request); { JSValueRef arguments[num_rest_args]; for (int i = 0; i < num_rest_args; i++) { arguments[i] = c_string_to_value(ctx, rest_args[i]); } JSValueRef args_ref = JSObjectMakeArray(ctx, num_rest_args, arguments, NULL); JSValueRef global_obj = JSContextGetGlobalObject(ctx); JSStringRef prop = JSStringCreateWithUTF8CString("PLANCK_INITIAL_COMMAND_LINE_ARGS"); JSObjectSetProperty(ctx, JSValueToObject(ctx, global_obj, NULL), prop, args_ref, kJSPropertyAttributeNone, NULL); JSStringRelease(prop); } evaluate_script(ctx, "cljs.core.set_print_fn_BANG_.call(null,PLANCK_PRINT_FN);", "<init>"); evaluate_script(ctx, "cljs.core.set_print_err_fn_BANG_.call(null,PLANCK_PRINT_ERR_FN);", "<init>"); char *elide_script = str_concat("cljs.core._STAR_assert_STAR_ = ", elide_asserts ? "false" : "true"); evaluate_script(ctx, elide_script, "<init>"); free(elide_script); { JSValueRef arguments[4]; arguments[0] = JSValueMakeBoolean(ctx, repl); arguments[1] = JSValueMakeBoolean(ctx, verbose); JSValueRef cache_path_ref = NULL; if (cache_path != NULL) { JSStringRef cache_path_str = JSStringCreateWithUTF8CString(cache_path); cache_path_ref = JSValueMakeString(ctx, cache_path_str); } arguments[2] = cache_path_ref; arguments[3] = JSValueMakeBoolean(ctx, static_fns); JSValueRef ex = NULL; JSObjectCallAsFunction(ctx, get_function(ctx, "planck.repl", "init"), JSContextGetGlobalObject(ctx), 4, arguments, &ex); debug_print_value("planck.repl/init", ctx, ex); } if (repl) { evaluate_source(ctx, "text", "(require '[planck.repl :refer-macros [apropos dir find-doc doc source pst]])", true, false, "cljs.user", "dumb"); } evaluate_script(ctx, "goog.provide('cljs.user');", "<init>"); evaluate_script(ctx, "goog.require('cljs.core');", "<init>"); evaluate_script(ctx, "cljs.core._STAR_assert_STAR_ = true;", "<init>"); // Process init arguments for (int i = 0; i < num_scripts; i++) { // TODO: exit if not successfull evaluate_source(ctx, scripts[i].type, scripts[i].source, scripts[i].expression, false, NULL, theme); } // Process main arguments if (main_ns_name != NULL) { run_main_in_ns(ctx, main_ns_name, num_rest_args, rest_args); } else if (!repl && num_rest_args > 0) { char *path = rest_args[0]; struct script script; if (strcmp(path, "-") == 0) { char *source = read_all(stdin); script.type = "text"; script.source = source; script.expression = false; } else { script.type = "path"; script.source = path; script.expression = false; } evaluate_source(ctx, script.type, script.source, script.expression, false, NULL, theme); } else if (repl) { if (!quiet) { banner(); } char *home = getenv("HOME"); char *history_path = NULL; if (home != NULL) { char history_name[] = ".planck_history"; int len = strlen(home) + strlen(history_name) + 2; history_path = malloc(len * sizeof(char)); snprintf(history_path, len, "%s/%s", home, history_name); linenoiseHistoryLoad(history_path); } if (!javascript) { linenoiseSetCompletionCallback(completion); } char *prompt = javascript ? " > " : "cljs.user=> "; char *current_ns = get_current_ns(ctx); if (!javascript) { prompt = str_concat(current_ns, "=> "); } char *line; while ((line = linenoise(prompt, "\x1b[36m", 0)) != NULL) { if (javascript) { JSValueRef res = evaluate_script(ctx, line, "<stdin>"); print_value("", ctx, res); } else { evaluate_source(ctx, "text", line, true, true, current_ns, theme); char *new_ns = get_current_ns(ctx); free(current_ns); free(prompt); current_ns = new_ns; prompt = str_concat(current_ns, "=> "); } linenoiseHistoryAdd(line); if (history_path != NULL) { linenoiseHistorySave(history_path); } free(line); } } return exit_value; }
inline value eval(HVM vm, const wchar_t* text) { return eval( vm, get_current_ns(vm), text); }