Skip to content

Commit

Permalink
Allow modules to optionally import nothing at all (JuliaLang#40110)
Browse files Browse the repository at this point in the history
See: https://discourse.julialang.org/t/even-more-bare-baremodule/56156/

A module that imports nothing at all can be used to build a sandbox.
Sandboxes are useful for defining smaller teaching languages (see Racket
and the HTDP2e book) and, if they can be made secure, for evaluating
untrusted code in a capability programming paradigm.

This commit changes the API of libjulia:

Old:

    JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports)

New:

    JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports, uint8_t using_core)

Co-authored-by: Simeon Schaub <[email protected]>
  • Loading branch information
2 people authored and johanmon committed Jul 5, 2021
1 parent e4300cd commit 4db448a
Show file tree
Hide file tree
Showing 5 changed files with 15 additions and 5 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Julia v1.8 Release Notes
New language features
---------------------

* `Module(:name, false, false)` can be used to create a `module` that does not import `Core`. ([#40110])

Language changes
----------------
Expand Down
2 changes: 1 addition & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ eval(Core, :(InterConditional(slot::Int, @nospecialize(vtype), @nospecialize(els
eval(Core, :(MethodMatch(@nospecialize(spec_types), sparams::SimpleVector, method::Method, fully_covers::Bool) =
$(Expr(:new, :MethodMatch, :spec_types, :sparams, :method, :fully_covers))))

Module(name::Symbol=:anonymous, std_imports::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool), name, std_imports)
Module(name::Symbol=:anonymous, std_imports::Bool=true, using_core::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool, Bool), name, std_imports, using_core)

function _Task(@nospecialize(f), reserved_stack::Int, completion_future)
return ccall(:jl_new_task, Ref{Task}, (Any, Any, Int), f, completion_future, reserved_stack)
Expand Down
2 changes: 2 additions & 0 deletions doc/src/manual/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ include(p) = Base.include(Mod, p)
end
```

If even `Core` is not wanted, a module that imports nothing at all can be defined with `Module(:YourNameHere, false, false)` and code can be evaluated into it with [`@eval`](@ref) or [`Core.eval`](@ref).

### Standard modules

There are three important standard modules:
Expand Down
13 changes: 9 additions & 4 deletions src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
extern "C" {
#endif

JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name)
JL_DLLEXPORT jl_module_t *jl_new_module_(jl_sym_t *name, uint8_t using_core)
{
jl_task_t *ct = jl_current_task;
const jl_uuid_t uuid_zero = {0, 0};
Expand All @@ -36,7 +36,7 @@ JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name)
htable_new(&m->bindings, 0);
arraylist_new(&m->usings, 0);
JL_GC_PUSH1(&m);
if (jl_core_module) {
if (jl_core_module && using_core) {
jl_module_using(m, jl_core_module);
}
// export own name, so "using Foo" makes "Foo" itself visible
Expand All @@ -46,15 +46,20 @@ JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name)
return m;
}

JL_DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name)
{
return jl_new_module_(name, 1);
}

uint32_t jl_module_next_counter(jl_module_t *m)
{
return jl_atomic_fetch_add(&m->counter, 1);
}

JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports)
JL_DLLEXPORT jl_value_t *jl_f_new_module(jl_sym_t *name, uint8_t std_imports, uint8_t using_core)
{
// TODO: should we prohibit this during incremental compilation?
jl_module_t *m = jl_new_module(name);
jl_module_t *m = jl_new_module_(name, using_core);
JL_GC_PUSH1(&m);
m->parent = jl_main_module; // TODO: this is a lie
jl_gc_wb(m, m->parent);
Expand Down
2 changes: 2 additions & 0 deletions test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -997,6 +997,8 @@ end
# Module() constructor
@test names(Module(:anonymous), all = true, imported = true) == [:anonymous]
@test names(Module(:anonymous, false), all = true, imported = true) == [:anonymous]
@test Module(:anonymous, false, true).Core == Core
@test_throws UndefVarError Module(:anonymous, false, false).Core

# exception from __init__()
let didthrow =
Expand Down

0 comments on commit 4db448a

Please sign in to comment.