// this is for parsing one expression out of a string, keeping track of // the current position. JL_DLLEXPORT jl_value_t *jl_parse_string(const char *str, size_t len, int pos0, int greedy) { JL_TIMING(PARSING); if (pos0 < 0 || pos0 > len) { jl_array_t *buf = jl_pchar_to_array(str, len); JL_GC_PUSH1(&buf); // jl_bounds_error roots the arguments. jl_bounds_error((jl_value_t*)buf, jl_box_long(pos0)); } jl_ast_context_t *ctx = jl_ast_ctx_enter(); fl_context_t *fl_ctx = &ctx->fl; value_t s = cvalue_static_cstrn(fl_ctx, str, len); value_t p = fl_applyn(fl_ctx, 3, symbol_value(symbol(fl_ctx, "jl-parse-one-string")), s, fixnum(pos0), greedy?fl_ctx->T:fl_ctx->F); jl_value_t *expr=NULL, *pos1=NULL; JL_GC_PUSH2(&expr, &pos1); value_t e = car_(p); if (e == fl_ctx->FL_EOF) expr = jl_nothing; else expr = scm_to_julia(fl_ctx, e, NULL); pos1 = jl_box_long(tosize(fl_ctx, cdr_(p), "parse")); jl_ast_ctx_leave(ctx); jl_value_t *result = (jl_value_t*)jl_svec2(expr, pos1); JL_GC_POP(); return result; }
// expand in a context where the expression value is unused JL_DLLEXPORT jl_value_t *jl_expand_stmt(jl_value_t *expr, jl_module_t *inmodule) { JL_TIMING(LOWERING); JL_GC_PUSH1(&expr); expr = jl_copy_ast(expr); expr = jl_expand_macros(expr, inmodule, NULL, 0); expr = jl_call_scm_on_ast("jl-expand-to-thunk-stmt", expr, inmodule); JL_GC_POP(); return expr; }
JL_DLLEXPORT jl_value_t *jl_macroexpand1(jl_value_t *expr, jl_module_t *inmodule) { JL_TIMING(LOWERING); JL_GC_PUSH1(&expr); expr = jl_copy_ast(expr); expr = jl_expand_macros(expr, inmodule, NULL, 1); expr = jl_call_scm_on_ast("julia-expand-macroscope", expr, inmodule); JL_GC_POP(); return expr; }
static jl_value_t *jl_invoke_julia_macro(jl_array_t *args, jl_module_t *inmodule, jl_module_t **ctx) { jl_ptls_t ptls = jl_get_ptls_states(); JL_TIMING(MACRO_INVOCATION); size_t nargs = jl_array_len(args) + 1; JL_NARGSV("macrocall", 3); // macro name, location, and module jl_value_t **margs; JL_GC_PUSHARGS(margs, nargs); int i; margs[0] = jl_array_ptr_ref(args, 0); // __source__ argument jl_value_t *lno = jl_array_ptr_ref(args, 1); margs[1] = lno; if (!jl_typeis(lno, jl_linenumbernode_type)) { margs[1] = jl_new_struct(jl_linenumbernode_type, jl_box_long(0), jl_nothing); } margs[2] = (jl_value_t*)inmodule; for (i = 3; i < nargs; i++) margs[i] = jl_array_ptr_ref(args, i - 1); size_t last_age = ptls->world_age; size_t world = jl_world_counter; ptls->world_age = world; jl_value_t *result; JL_TRY { margs[0] = jl_toplevel_eval(*ctx, margs[0]); jl_method_instance_t *mfunc = jl_method_lookup(jl_gf_mtable(margs[0]), margs, nargs, 1, world); if (mfunc == NULL) { jl_method_error((jl_function_t*)margs[0], margs, nargs, world); // unreachable } *ctx = mfunc->def.method->module; result = mfunc->invoke(mfunc, margs, nargs); } JL_CATCH { if (jl_loaderror_type == NULL) { jl_rethrow(); } else { jl_value_t *lno = margs[1]; jl_value_t *file = jl_fieldref(lno, 1); if (jl_is_symbol(file)) margs[0] = jl_cstr_to_string(jl_symbol_name((jl_sym_t*)file)); else margs[0] = jl_cstr_to_string("<macrocall>"); margs[1] = jl_fieldref(lno, 0); // extract and allocate line number jl_rethrow_other(jl_new_struct(jl_loaderror_type, margs[0], margs[1], ptls->exception_in_transit)); } } ptls->world_age = last_age; JL_GC_POP(); return result; }
// this is used to parse a line of repl input JL_DLLEXPORT jl_value_t *jl_parse_input_line(const char *str, size_t len, const char *filename, size_t filename_len) { JL_TIMING(PARSING); jl_ast_context_t *ctx = jl_ast_ctx_enter(); fl_context_t *fl_ctx = &ctx->fl; value_t s = cvalue_static_cstrn(fl_ctx, str, len); value_t files = cvalue_static_cstrn(fl_ctx, filename, filename_len); value_t e = fl_applyn(fl_ctx, 2, symbol_value(symbol(fl_ctx, "jl-parse-string")), s, files); jl_value_t *res = e == fl_ctx->FL_EOF ? jl_nothing : scm_to_julia(fl_ctx, e, NULL); jl_ast_ctx_leave(ctx); return res; }
// parse and eval a whole file, possibly reading from a string (`content`) jl_value_t *jl_parse_eval_all(const char *fname, const char *content, size_t contentlen, jl_module_t *inmodule) { jl_ptls_t ptls = jl_get_ptls_states(); if (ptls->in_pure_callback) jl_error("cannot use include inside a generated function"); jl_ast_context_t *ctx = jl_ast_ctx_enter(); fl_context_t *fl_ctx = &ctx->fl; value_t f, ast, expression; size_t len = strlen(fname); f = cvalue_static_cstrn(fl_ctx, fname, len); fl_gc_handle(fl_ctx, &f); if (content != NULL) { JL_TIMING(PARSING); value_t t = cvalue_static_cstrn(fl_ctx, content, contentlen); fl_gc_handle(fl_ctx, &t); ast = fl_applyn(fl_ctx, 2, symbol_value(symbol(fl_ctx, "jl-parse-string-stream")), t, f); fl_free_gc_handles(fl_ctx, 1); } else { JL_TIMING(PARSING); assert(memchr(fname, 0, len) == NULL); // was checked already in jl_load ast = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "jl-parse-file")), f); } fl_free_gc_handles(fl_ctx, 1); if (ast == fl_ctx->F) { jl_ast_ctx_leave(ctx); jl_errorf("could not open file %s", fname); } fl_gc_handle(fl_ctx, &ast); fl_gc_handle(fl_ctx, &expression); int last_lineno = jl_lineno; const char *last_filename = jl_filename; size_t last_age = jl_get_ptls_states()->world_age; jl_lineno = 0; jl_filename = fname; jl_module_t *old_module = ctx->module; ctx->module = inmodule; jl_value_t *form = NULL; jl_value_t *result = jl_nothing; int err = 0; JL_GC_PUSH2(&form, &result); JL_TRY { assert(iscons(ast) && car_(ast) == symbol(fl_ctx, "toplevel")); ast = cdr_(ast); while (iscons(ast)) { expression = car_(ast); { JL_TIMING(LOWERING); if (fl_ctx->T == fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "contains-macrocall")), expression)) { form = scm_to_julia(fl_ctx, expression, inmodule); form = jl_expand_macros(form, inmodule, NULL, 0); expression = julia_to_scm(fl_ctx, form); } // expand non-final expressions in statement position (value unused) expression = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, iscons(cdr_(ast)) ? "jl-expand-to-thunk-stmt" : "jl-expand-to-thunk")), expression); } jl_get_ptls_states()->world_age = jl_world_counter; form = scm_to_julia(fl_ctx, expression, inmodule); JL_SIGATOMIC_END(); jl_get_ptls_states()->world_age = jl_world_counter; if (jl_is_linenode(form)) jl_lineno = jl_linenode_line(form); else result = jl_toplevel_eval_flex(inmodule, form, 1, 1); JL_SIGATOMIC_BEGIN(); ast = cdr_(ast); } } JL_CATCH { form = jl_pchar_to_string(fname, len); result = jl_box_long(jl_lineno); err = 1; } jl_get_ptls_states()->world_age = last_age; jl_lineno = last_lineno; jl_filename = last_filename; fl_free_gc_handles(fl_ctx, 2); ctx->module = old_module; jl_ast_ctx_leave(ctx); if (err) { if (jl_loaderror_type == NULL) jl_rethrow(); else jl_rethrow_other(jl_new_struct(jl_loaderror_type, form, result, ptls->exception_in_transit)); } JL_GC_POP(); return result; }
static jl_lambda_info_t *jl_instantiate_staged(jl_method_t *generator, jl_tupletype_t *tt, jl_svec_t *env) { JL_TIMING(STAGED_FUNCTION); size_t i, l; jl_expr_t *ex = NULL; jl_value_t *linenum = NULL; jl_svec_t *sparam_vals = env; jl_lambda_info_t *func = generator->lambda_template; JL_GC_PUSH4(&ex, &linenum, &sparam_vals, &func); int last_in = in_pure_callback; assert(jl_svec_len(func->sparam_syms) == jl_svec_len(sparam_vals)); JL_TRY { in_pure_callback = 1; ex = jl_exprn(lambda_sym, 2); int nargs = func->nargs; jl_array_t *argnames = jl_alloc_vec_any(nargs); jl_array_ptr_set(ex->args, 0, argnames); for (i = 0; i < nargs; i++) jl_array_ptr_set(argnames, i, jl_array_ptr_ref(func->slotnames, i)); jl_expr_t *scopeblock = jl_exprn(jl_symbol("scope-block"), 1); jl_array_ptr_set(ex->args, 1, scopeblock); jl_expr_t *body = jl_exprn(jl_symbol("block"), 2); jl_array_ptr_set(((jl_expr_t*)jl_exprarg(ex,1))->args, 0, body); linenum = jl_box_long(generator->line); jl_value_t *linenode = jl_new_struct(jl_linenumbernode_type, linenum); jl_array_ptr_set(body->args, 0, linenode); // invoke code generator assert(jl_nparams(tt) == jl_array_len(argnames) || (func->isva && (jl_nparams(tt) >= jl_array_len(argnames) - 1))); jl_array_ptr_set(body->args, 1, jl_call_staged(sparam_vals, func, jl_svec_data(tt->parameters), jl_nparams(tt))); if (func->sparam_syms != jl_emptysvec) { // mark this function as having the same static parameters as the generator size_t i, nsp = jl_svec_len(func->sparam_syms); jl_expr_t *newast = jl_exprn(jl_symbol("with-static-parameters"), nsp + 1); jl_exprarg(newast, 0) = (jl_value_t*)ex; // (with-static-parameters func_expr sp_1 sp_2 ...) for (i = 0; i < nsp; i++) jl_exprarg(newast, i+1) = jl_svecref(func->sparam_syms, i); ex = newast; } // need to eval macros in the right module, but not give a warning for the `eval` call unless that results in a call to `eval` func = (jl_lambda_info_t*)jl_toplevel_eval_in_warn(generator->module, (jl_value_t*)ex, 1); // finish marking this as a specialization of the generator func->isva = generator->lambda_template->isva; func->def = generator; jl_gc_wb(func, generator); func->sparam_vals = env; jl_gc_wb(func, env); func->specTypes = tt; jl_gc_wb(func, tt); jl_array_t *stmts = (jl_array_t*)func->code; for(i = 0, l = jl_array_len(stmts); i < l; i++) { jl_array_ptr_set(stmts, i, jl_resolve_globals(jl_array_ptr_ref(stmts, i), func)); } in_pure_callback = last_in; } JL_CATCH { in_pure_callback = last_in; jl_rethrow(); } JL_GC_POP(); return func; }