diff --git a/src/gc.c b/src/gc.c index 96c9895646b41..b528c25688371 100644 --- a/src/gc.c +++ b/src/gc.c @@ -785,6 +785,7 @@ double clock_now(void); extern jl_module_t *jl_old_base_module; extern jl_array_t *typeToTypeId; +extern jl_array_t *jl_late_modules; static void gc_mark(void) { @@ -809,6 +810,7 @@ static void gc_mark(void) gc_push_root(jl_typetype_type, 0); gc_push_root(jl_tupletype_type, 0); gc_push_root(typeToTypeId, 0); + if (jl_late_modules) gc_push_root(jl_late_modules, 0); // constants gc_push_root(jl_null, 0); diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 481c427fa5cdb..bcd4234578399 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -1129,6 +1129,9 @@ `(const ,assgn)))) ((module baremodule) (let* ((name (parse-atom s)) + (parametrics (if (eqv? (peek-token s) 'requires) + (begin (take-token s) (cons 'tuple (parse-comma-separated s parse-module-path))) + '())) (body (parse-block s))) (expect-end s) (list 'module (eq? word 'module) name @@ -1141,7 +1144,7 @@ `(= (call eval m x) (call (|.| (top Core) 'eval) m x)) (cdr body)) - body)))) + body) parametrics))) ((export) (let ((es (map macrocall-to-atsym (parse-comma-separated s parse-atom)))) @@ -1229,8 +1232,15 @@ (cons (macrocall-to-atsym (parse-atom s)) l))))) (define (parse-import s word) - (let loop ((path (parse-import-dots s))) - (if (not (symbol? (car path))) + (parse-dotted-path s #t word word)) + +(define (parse-module-path s) + (parse-dotted-path s #f 'module 'tuple)) + +(define (parse-dotted-path s allow-leading-dots-and-macrosym? word head) + (let ((macrocall-to-atsym (if allow-leading-dots-and-macrosym? macrocall-to-atsym (lambda (x) x)))) + (let loop ((path (if allow-leading-dots-and-macrosym? (parse-import-dots s) (cons (parse-atom s) '())))) + (if (and allow-leading-dots-and-macrosym? (not (symbol? (car path)))) (error (string "invalid \"" word "\" statement: expected identifier"))) (let ((nxt (peek-token s))) (cond @@ -1239,13 +1249,13 @@ (loop (cons (macrocall-to-atsym (parse-atom s)) path))) ((or (memv nxt '(#\newline #\; #\, :)) (eof-object? nxt)) - `(,word ,@(reverse path))) + `(,head ,@(reverse path))) ((eqv? (string.sub (string nxt) 0 1) ".") (take-token s) (loop (cons (symbol (string.sub (string nxt) 1)) path))) (else - (error (string "invalid \"" word "\" statement"))))))) + (error (string "invalid \"" word "\" statement")))))))) ; parse comma-separated assignments, like "i=1:n,j=1:m,..." (define (parse-comma-separated s what) diff --git a/src/toplevel.c b/src/toplevel.c index b59056a5c7cd7..441e9c7928657 100644 --- a/src/toplevel.c +++ b/src/toplevel.c @@ -62,28 +62,49 @@ jl_module_t *jl_new_main_module(void) return old_main; } +int jl_module_reqs_met(jl_expr_t *reqs, jl_module_t *newm) +{ + int reeval = !newm; + size_t i, tlen = jl_array_len(reqs->args); + for (i = 0; i < tlen; i++) { + jl_expr_t *req = (jl_expr_t*)jl_exprarg(reqs, i); + if (!jl_is_expr(req) || req->head != tuple_sym) { + jl_error("syntax: malformed module-requires statement"); + } + size_t j, rlen = jl_array_len(req->args); + jl_module_t *m = jl_main_module; + for (j = 0; j < rlen; j++) { + jl_sym_t *s = (jl_sym_t*)jl_exprarg(req, j); + if (!jl_is_symbol(s)) { + jl_error("syntax: malformed module-requires statement"); + } + m = (jl_module_t*)jl_get_global(m, s); + if (!m || !jl_is_module(m)) { + return 0; + } + } + reeval |= (m == newm); + } + return reeval; +} + extern void jl_get_system_hooks(void); extern void jl_get_uv_hooks(int); extern int base_module_conflict; -jl_value_t *jl_eval_module_expr(jl_expr_t *ex) -{ +jl_array_t *jl_late_modules; +jl_value_t *jl_eval_module_expr_(jl_expr_t *ex, jl_module_t *parent_module) { static arraylist_t module_stack; static int initialized=0; if (!initialized) { arraylist_new(&module_stack, 0); initialized = 1; } - assert(ex->head == module_sym); jl_module_t *last_module = jl_current_module; - if (jl_array_len(ex->args) != 3 || !jl_is_expr(jl_exprarg(ex,2))) { - jl_error("syntax: malformed module expression"); - } int std_imports = (jl_exprarg(ex,0)==jl_true); jl_sym_t *name = (jl_sym_t*)jl_exprarg(ex, 1); if (!jl_is_symbol(name)) { jl_type_error("module", (jl_value_t*)jl_sym_type, (jl_value_t*)name); } - jl_module_t *parent_module = jl_current_module; jl_binding_t *b = jl_get_binding_wr(parent_module, name); jl_declare_constant(b); if (b->value != NULL) { @@ -169,8 +190,64 @@ jl_value_t *jl_eval_module_expr(jl_expr_t *ex) } } + if (jl_late_modules) { + size_t i, len = jl_array_len(jl_late_modules); + for (i = 0; i < len; i++) { + jl_tuple_t *late_m = (jl_tuple_t*)jl_arrayref(jl_late_modules, i); + jl_expr_t *ex2 = (jl_expr_t*)jl_tupleref(late_m, 0); + if (jl_module_reqs_met((jl_expr_t*)jl_exprarg(ex2, 3), newm)) { + JL_TRY { + (void)jl_eval_module_expr_(ex2, (jl_module_t*)jl_tupleref(late_m, 1)); + } + JL_CATCH { + JL_PRINTF(JL_STDERR, "Warning: error initializing module %s:\n", ((jl_sym_t*)jl_exprarg(ex2, 1))->name); + jl_static_show(JL_STDERR, jl_exception_in_transit); + JL_PRINTF(JL_STDERR, "\n"); + } + } + } + } return jl_nothing; } +jl_value_t *jl_eval_module_expr(jl_expr_t *ex) +{ + assert(ex->head == module_sym); + assert(jl_array_len(ex->args) > 2 && jl_is_expr(jl_exprarg(ex,2)) && jl_is_symbol(jl_exprarg(ex,1))); + if (jl_array_len(ex->args) == 4) { + jl_expr_t *reqs = (jl_expr_t*)jl_exprarg(ex,3); + if (!jl_is_null(reqs)) { + if (!jl_is_expr(reqs) || reqs->head != tuple_sym) { + jl_error("syntax: malformed module-requires statement"); + } + if (jl_array_len(reqs->args)) { + if (!jl_late_modules) { + jl_late_modules = jl_alloc_cell_1d(0); + } + int met = jl_module_reqs_met(reqs, NULL); // note: might throw instead of return, if reqs is invalid + size_t i, len = jl_array_len(jl_late_modules); + jl_value_t* late_info = (jl_value_t*)jl_tuple2(ex, jl_current_module); + for (i = 0; i < len; i++) { + jl_tuple_t *late_m = (jl_tuple_t*)jl_arrayref(jl_late_modules, i); + if (jl_exprarg(jl_tupleref(late_m, 0), 1) == jl_exprarg(ex, 1) && + jl_tupleref(late_m, 1) == (jl_value_t*)jl_current_module) { + jl_cellset(jl_late_modules, i, late_info); + break; + } + } + if (i == len) { + jl_cell_1d_push(jl_late_modules, late_info); + } + if (!met) { + return jl_nothing; + } + } + } + } + else if (jl_array_len(ex->args) != 3) { + jl_error("syntax: malformed module expression"); + } + return jl_eval_module_expr_(ex, jl_current_module); +} static int is_intrinsic(jl_module_t *m, jl_sym_t *s) {