JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr) { if (expr && jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; size_t i, l = jl_array_len(e->args); jl_expr_t *ne = jl_exprn(e->head, l); JL_GC_PUSH2(&ne, &expr); for (i = 0; i < l; i++) { jl_value_t *a = jl_exprarg(e, i); jl_exprargset(ne, i, jl_copy_ast(a)); } JL_GC_POP(); return (jl_value_t*)ne; } return expr; }
jl_value_t *jl_resolve_globals(jl_value_t *expr, jl_lambda_info_t *lam) { if (jl_is_symbol(expr)) { if (lam->def->module == NULL) return expr; return jl_module_globalref(lam->def->module, (jl_sym_t*)expr); } else if (jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; if (jl_is_toplevel_only_expr(expr) || e->head == const_sym || e->head == copyast_sym || e->head == global_sym || e->head == quote_sym || e->head == inert_sym || e->head == line_sym || e->head == meta_sym || e->head == inbounds_sym || e->head == boundscheck_sym || e->head == simdloop_sym) { } else { if (e->head == call_sym && jl_expr_nargs(e) == 3 && jl_is_quotenode(jl_exprarg(e,2)) && lam->def->module != NULL) { // replace getfield(module_expr, :sym) with GlobalRef jl_value_t *s = jl_fieldref(jl_exprarg(e,2),0); jl_value_t *fe = jl_exprarg(e,0); if (jl_is_symbol(s) && jl_is_globalref(fe)) { jl_value_t *f = jl_static_eval(fe, NULL, lam->def->module, lam, 0, 0); if (f == jl_builtin_getfield) { jl_value_t *me = jl_exprarg(e,1); if (jl_is_globalref(me) || (jl_is_symbol(me) && jl_binding_resolved_p(lam->def->module, (jl_sym_t*)me))) { jl_value_t *m = jl_static_eval(me, NULL, lam->def->module, lam, 0, 0); if (m && jl_is_module(m)) return jl_module_globalref((jl_module_t*)m, (jl_sym_t*)s); } } } } size_t i = 0; if (e->head == method_sym || e->head == abstracttype_sym || e->head == compositetype_sym || e->head == bitstype_sym || e->head == module_sym) i++; for(; i < jl_array_len(e->args); i++) { jl_exprargset(e, i, jl_resolve_globals(jl_exprarg(e,i), lam)); } } } return expr; }
JL_DLLEXPORT jl_value_t *jl_copy_ast(jl_value_t *expr) { if (expr == NULL) { return NULL; } else if (jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; size_t i, l = jl_array_len(e->args); jl_expr_t *ne = NULL; JL_GC_PUSH2(&ne, &expr); ne = jl_exprn(e->head, l); if (l == 0) { ne->args = jl_alloc_vec_any(0); jl_gc_wb(ne, ne->args); } else { for(i=0; i < l; i++) { jl_exprargset(ne, i, jl_copy_ast(jl_exprarg(e,i))); } } JL_GC_POP(); return (jl_value_t*)ne; } else if (jl_typeis(expr,jl_array_any_type)) { jl_array_t *a = (jl_array_t*)expr; size_t i, l = jl_array_len(a); jl_array_t *na = NULL; JL_GC_PUSH2(&na, &expr); na = jl_alloc_vec_any(l); for(i=0; i < l; i++) jl_array_ptr_set(na, i, jl_copy_ast(jl_array_ptr_ref(a,i))); JL_GC_POP(); return (jl_value_t*)na; } return expr; }
static jl_value_t *jl_expand_macros(jl_value_t *expr, jl_module_t *inmodule, struct macroctx_stack *macroctx, int onelevel) { if (!expr || !jl_is_expr(expr)) return expr; jl_expr_t *e = (jl_expr_t*)expr; if (e->head == inert_sym || e->head == module_sym || //e->head == toplevel_sym || // TODO: enable this once julia-expand-macroscope is fixed / removed e->head == meta_sym) { return expr; } if (e->head == quote_sym && jl_expr_nargs(e) == 1) { expr = jl_call_scm_on_ast("julia-bq-macro", jl_exprarg(e, 0), inmodule); JL_GC_PUSH1(&expr); if (macroctx) { // in a macro, `quote` also implies `escape` jl_expr_t *e2 = jl_exprn(escape_sym, 1); jl_array_ptr_set(e2->args, 0, expr); expr = (jl_value_t*)e2; } expr = jl_expand_macros(expr, inmodule, macroctx, onelevel); JL_GC_POP(); return expr; } if (e->head == hygienicscope_sym && jl_expr_nargs(e) == 2) { struct macroctx_stack newctx; newctx.m = (jl_module_t*)jl_exprarg(e, 1); JL_TYPECHK(hygienic-scope, module, (jl_value_t*)newctx.m); newctx.parent = macroctx; jl_value_t *a = jl_exprarg(e, 0); jl_value_t *a2 = jl_expand_macros(a, inmodule, &newctx, onelevel); if (a != a2) jl_array_ptr_set(e->args, 0, a2); return expr; } if (e->head == macrocall_sym) { struct macroctx_stack newctx; newctx.m = macroctx ? macroctx->m : inmodule; newctx.parent = macroctx; jl_value_t *result = jl_invoke_julia_macro(e->args, inmodule, &newctx.m); jl_value_t *wrap = NULL; JL_GC_PUSH3(&result, &wrap, &newctx.m); // copy and wrap the result in `(hygienic-scope ,result ,newctx) if (jl_is_expr(result) && ((jl_expr_t*)result)->head == escape_sym) result = jl_exprarg(result, 0); else wrap = (jl_value_t*)jl_exprn(hygienicscope_sym, 2); result = jl_copy_ast(result); if (!onelevel) result = jl_expand_macros(result, inmodule, wrap ? &newctx : macroctx, onelevel); if (wrap) { jl_exprargset(wrap, 0, result); jl_exprargset(wrap, 1, newctx.m); result = wrap; } JL_GC_POP(); return result; } if (e->head == escape_sym && macroctx) { macroctx = macroctx->parent; } size_t i; for (i = 0; i < jl_array_len(e->args); i++) { jl_value_t *a = jl_array_ptr_ref(e->args, i); jl_value_t *a2 = jl_expand_macros(a, inmodule, macroctx, onelevel); if (a != a2) jl_array_ptr_set(e->args, i, a2); } return expr; }
DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_value_t *bp_owner, jl_binding_t *bnd, jl_svec_t *argdata, jl_function_t *f, jl_value_t *isstaged, jl_value_t *call_func, int iskw) { jl_module_t *module = (bnd ? bnd->owner : NULL); // argdata is svec({types...}, svec(typevars...)) jl_tupletype_t *argtypes = (jl_tupletype_t*)jl_svecref(argdata,0); jl_svec_t *tvars = (jl_svec_t*)jl_svecref(argdata,1); jl_value_t *gf = NULL; JL_GC_PUSH4(&gf, &tvars, &argtypes, &f); if (bnd && bnd->value != NULL && !bnd->constp) { jl_errorf("cannot define function %s; it already has a value", bnd->name->name); } if (*bp != NULL) { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_datatype(gf)) { // DataType: define `call`, for backwards compat with outer constructors if (call_func == NULL) call_func = (jl_value_t*)jl_module_call_func(jl_current_module); size_t na = jl_nparams(argtypes); jl_svec_t *newargtypes = jl_alloc_svec(1 + na); jl_lambda_info_t *new_linfo = NULL; JL_GC_PUSH2(&newargtypes, &new_linfo); new_linfo = jl_copy_lambda_info(f->linfo); f = jl_new_closure(f->fptr, f->env, new_linfo); size_t i=0; if (iskw) { assert(na > 0); // for kw sorter, keep container argument first jl_svecset(newargtypes, 0, jl_tparam(argtypes, 0)); i++; } jl_svecset(newargtypes, i, jl_wrap_Type(gf)); i++; for(; i < na+1; i++) { jl_svecset(newargtypes, i, jl_tparam(argtypes, i-1)); } argtypes = jl_apply_tuple_type(newargtypes); JL_GC_POP(); gf = call_func; name = call_sym; // edit args, insert type first if (!jl_is_expr(f->linfo->ast)) { f->linfo->ast = jl_uncompress_ast(f->linfo, f->linfo->ast); jl_gc_wb(f->linfo, f->linfo->ast); } else { // Do not mutate the original ast since it might // be reused somewhere else f->linfo->ast = jl_copy_ast(f->linfo->ast); jl_gc_wb(f->linfo, f->linfo->ast); } jl_array_t *al = jl_lam_args((jl_expr_t*)f->linfo->ast); if (jl_array_len(al) == 0) { al = jl_alloc_cell_1d(1); jl_exprargset(f->linfo->ast, 0, (jl_value_t*)al); } else { jl_array_grow_beg(al, 1); } if (iskw) { jl_cellset(al, 0, jl_cellref(al, 1)); jl_cellset(al, 1, (jl_value_t*)jl_gensym()); } else { jl_cellset(al, 0, (jl_value_t*)jl_gensym()); } } if (!jl_is_gf(gf)) { jl_errorf("cannot define function %s; it already has a value", name->name); } } if (iskw) { jl_methtable_t *mt = jl_gf_mtable(gf); assert(!module); module = mt->module; bp = (jl_value_t**)&mt->kwsorter; bp_owner = (jl_value_t*)mt; gf = *bp; } } // TODO size_t na = jl_nparams(argtypes); for(size_t i=0; i < na; i++) { jl_value_t *elt = jl_tparam(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_lambda_info_t *li = f->linfo; jl_exceptionf(jl_argumenterror_type, "invalid type for argument %s in method definition for %s at %s:%d", jl_lam_argname(li,i)->name, name->name, li->file->name, li->line); } } int ishidden = !!strchr(name->name, '#'); for(size_t i=0; i < jl_svec_len(tvars); i++) { jl_value_t *tv = jl_svecref(tvars,i); if (!jl_is_typevar(tv)) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, tv); if (!ishidden && !type_contains((jl_value_t*)argtypes, tv)) { jl_printf(JL_STDERR, "WARNING: static parameter %s does not occur in signature for %s", ((jl_tvar_t*)tv)->name->name, name->name); print_func_loc(JL_STDERR, f->linfo); jl_printf(JL_STDERR, ".\nThe method will not be callable.\n"); } } if (bnd) { bnd->constp = 1; } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name, module); *bp = gf; if (bp_owner) jl_gc_wb(bp_owner, gf); } assert(jl_is_function(f)); assert(jl_is_tuple_type(argtypes)); assert(jl_is_svec(tvars)); jl_add_method((jl_function_t*)gf, argtypes, f, tvars, isstaged == jl_true); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); jl_gc_wb(li, li->ast); } JL_GC_POP(); return gf; }
DLLEXPORT jl_value_t *jl_method_def(jl_sym_t *name, jl_value_t **bp, jl_value_t *bp_owner, jl_binding_t *bnd, jl_tuple_t *argtypes, jl_function_t *f, jl_value_t *isstaged, jl_value_t *call_func, int iskw) { // argtypes is a tuple ((types...), (typevars...)) jl_tuple_t *t = (jl_tuple_t*)jl_t1(argtypes); argtypes = (jl_tuple_t*)jl_t0(argtypes); jl_value_t *gf=NULL; JL_GC_PUSH3(&gf, &argtypes, &t); if (bnd && bnd->value != NULL && !bnd->constp) { jl_errorf("cannot define function %s; it already has a value", bnd->name->name); } if (*bp != NULL) { gf = *bp; if (!jl_is_gf(gf)) { if (jl_is_datatype(gf)) { // DataType: define `call`, for backwards compat with outer constructors if (call_func == NULL) call_func = (jl_value_t*)jl_module_call_func(jl_current_module); size_t na = jl_tuple_len(argtypes); jl_tuple_t *newargtypes = jl_alloc_tuple(1 + na); JL_GC_PUSH1(&newargtypes); size_t i=0; if (iskw) { assert(na > 0); // for kw sorter, keep container argument first jl_tupleset(newargtypes, 0, jl_tupleref(argtypes, 0)); i++; } jl_tupleset(newargtypes, i, jl_wrap_Type(gf)); i++; for(; i < na+1; i++) { jl_tupleset(newargtypes, i, jl_tupleref(argtypes, i-1)); } argtypes = newargtypes; JL_GC_POP(); gf = call_func; name = call_sym; // edit args, insert type first if (!jl_is_expr(f->linfo->ast)) { f->linfo->ast = jl_uncompress_ast(f->linfo, f->linfo->ast); gc_wb(f->linfo, f->linfo->ast); } jl_array_t *al = jl_lam_args((jl_expr_t*)f->linfo->ast); if (jl_array_len(al) == 0) { al = jl_alloc_cell_1d(1); jl_exprargset(f->linfo->ast, 0, (jl_value_t*)al); } else { jl_array_grow_beg(al, 1); } if (iskw) { jl_cellset(al, 0, jl_cellref(al, 1)); jl_cellset(al, 1, (jl_value_t*)jl_gensym()); } else { jl_cellset(al, 0, (jl_value_t*)jl_gensym()); } } if (!jl_is_gf(gf)) { jl_errorf("cannot define function %s; it already has a value", name->name); } } if (iskw) { bp = (jl_value_t**)&((jl_methtable_t*)((jl_function_t*)gf)->env)->kwsorter; bp_owner = (jl_value_t*)((jl_function_t*)gf)->env; gf = *bp; } } size_t na = jl_tuple_len(argtypes); for(size_t i=0; i < na; i++) { jl_value_t *elt = jl_tupleref(argtypes,i); if (!jl_is_type(elt) && !jl_is_typevar(elt)) { jl_lambda_info_t *li = f->linfo; jl_exceptionf(jl_argumenterror_type, "invalid type for argument %s in method definition for %s at %s:%d", jl_lam_argname(li,i)->name, name->name, li->file->name, li->line); } } int ishidden = !!strchr(name->name, '#'); for(size_t i=0; i < jl_tuple_len(t); i++) { jl_value_t *tv = jl_tupleref(t,i); if (!jl_is_typevar(tv)) jl_type_error_rt(name->name, "method definition", (jl_value_t*)jl_tvar_type, tv); if (!ishidden && !type_contains((jl_value_t*)argtypes, tv)) { jl_printf(JL_STDERR, "Warning: static parameter %s does not occur in signature for %s", ((jl_tvar_t*)tv)->name->name, name->name); print_func_loc(JL_STDERR, f->linfo); jl_printf(JL_STDERR, ".\nThe method will not be callable.\n"); } } if (bnd) { bnd->constp = 1; } if (*bp == NULL) { gf = (jl_value_t*)jl_new_generic_function(name); *bp = gf; if (bp_owner) gc_wb(bp_owner, gf); } assert(jl_is_function(f)); assert(jl_is_tuple(argtypes)); assert(jl_is_tuple(t)); jl_add_method((jl_function_t*)gf, argtypes, f, t, isstaged == jl_true); if (jl_boot_file_loaded && f->linfo && f->linfo->ast && jl_is_expr(f->linfo->ast)) { jl_lambda_info_t *li = f->linfo; li->ast = jl_compress_ast(li, li->ast); gc_wb(li, li->ast); } JL_GC_POP(); return gf; }
jl_value_t *jl_resolve_globals(jl_value_t *expr, jl_module_t *module, jl_svec_t *sparam_vals) { if (jl_is_symbol(expr)) { if (module == NULL) return expr; return jl_module_globalref(module, (jl_sym_t*)expr); } else if (jl_is_expr(expr)) { jl_expr_t *e = (jl_expr_t*)expr; if (e->head == global_sym) { // execute the side-effects of "global x" decl immediately: // creates uninitialized mutable binding in module for each global jl_toplevel_eval_flex(module, expr, 0, 1); expr = jl_nothing; } if (jl_is_toplevel_only_expr(expr) || e->head == const_sym || e->head == copyast_sym || e->head == quote_sym || e->head == inert_sym || e->head == meta_sym || e->head == inbounds_sym || e->head == boundscheck_sym || e->head == simdloop_sym) { // ignore these } else { if (e->head == call_sym && jl_expr_nargs(e) == 3 && jl_is_quotenode(jl_exprarg(e, 2)) && module != NULL) { // replace getfield(module_expr, :sym) with GlobalRef jl_value_t *s = jl_fieldref(jl_exprarg(e, 2), 0); jl_value_t *fe = jl_exprarg(e, 0); if (jl_is_symbol(s) && jl_is_globalref(fe)) { jl_binding_t *b = jl_get_binding(jl_globalref_mod(fe), jl_globalref_name(fe)); jl_value_t *f = NULL; if (b && b->constp) { f = b->value; } if (f == jl_builtin_getfield) { jl_value_t *me = jl_exprarg(e, 1); jl_module_t *me_mod = NULL; jl_sym_t *me_sym = NULL; if (jl_is_globalref(me)) { me_mod = jl_globalref_mod(me); me_sym = jl_globalref_name(me); } else if (jl_is_symbol(me) && jl_binding_resolved_p(module, (jl_sym_t*)me)) { me_mod = module; me_sym = (jl_sym_t*)me; } if (me_mod && me_sym) { jl_binding_t *b = jl_get_binding(me_mod, me_sym); if (b && b->constp) { jl_value_t *m = b->value; if (m && jl_is_module(m)) { return jl_module_globalref((jl_module_t*)m, (jl_sym_t*)s); } } } } } } size_t i = 0, nargs = jl_array_len(e->args); if (e->head == foreigncall_sym) { JL_NARGSV(ccall method definition, 5); // (fptr, rt, at, cc, narg) jl_value_t *rt = jl_exprarg(e, 1); jl_value_t *at = jl_exprarg(e, 2); if (!jl_is_type(rt)) { JL_TRY { rt = jl_interpret_toplevel_expr_in(module, rt, NULL, sparam_vals); } JL_CATCH { if (jl_typeis(jl_exception_in_transit, jl_errorexception_type)) jl_error("could not evaluate ccall return type (it might depend on a local variable)"); else jl_rethrow(); } jl_exprargset(e, 1, rt); } if (!jl_is_svec(at)) { JL_TRY { at = jl_interpret_toplevel_expr_in(module, at, NULL, sparam_vals); } JL_CATCH { if (jl_typeis(jl_exception_in_transit, jl_errorexception_type)) jl_error("could not evaluate ccall argument type (it might depend on a local variable)"); else jl_rethrow(); } jl_exprargset(e, 2, at); } if (jl_is_svec(rt)) jl_error("ccall: missing return type"); JL_TYPECHK(ccall method definition, type, rt); JL_TYPECHK(ccall method definition, simplevector, at); JL_TYPECHK(ccall method definition, quotenode, jl_exprarg(e, 3)); JL_TYPECHK(ccall method definition, symbol, *(jl_value_t**)jl_exprarg(e, 3)); JL_TYPECHK(ccall method definition, long, jl_exprarg(e, 4)); }