Skip to content

Commit

Permalink
module-local eval(). fixes JuliaLang#1651
Browse files Browse the repository at this point in the history
also add doc for baremodule
  • Loading branch information
JeffBezanson committed Dec 5, 2012
1 parent dfad04a commit 9ecd207
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 39 deletions.
7 changes: 6 additions & 1 deletion base/abstractarray.jl
Expand Up @@ -233,6 +233,11 @@ end
function gen_cartesian_map(cache, genbodies, ranges, exargnames, exargs...) function gen_cartesian_map(cache, genbodies, ranges, exargnames, exargs...)
N = length(ranges) N = length(ranges)
if !has(cache,N) if !has(cache,N)
if isdefined(genbodies,:code)
mod = genbodies.code.module
else
mod = Main
end
dimargnames = { symbol(string("_d",i)) for i=1:N } dimargnames = { symbol(string("_d",i)) for i=1:N }
ivars = { symbol(string("_i",i)) for i=1:N } ivars = { symbol(string("_i",i)) for i=1:N }
bodies = genbodies(ivars) bodies = genbodies(ivars)
Expand Down Expand Up @@ -269,7 +274,7 @@ function gen_cartesian_map(cache, genbodies, ranges, exargnames, exargs...)
end end
_F_ _F_
end end
f = eval(fexpr) f = eval(mod,fexpr)
cache[N] = f cache[N] = f
else else
f = cache[N] f = cache[N]
Expand Down
2 changes: 1 addition & 1 deletion base/boot.jl
Expand Up @@ -133,7 +133,7 @@ export ..., ANY, ASCIIString, AbstractArray, AbstractKind, Any, Array,
GetfieldNode, GetfieldNode,
# functions # functions
setfield, applicable, apply, apply_type, arraylen, arrayref, arrayset, setfield, applicable, apply, apply_type, arraylen, arrayref, arrayset,
arraysize, convert_default, convert_tuple, eval, fieldtype, getfield, arraysize, convert_default, convert_tuple, fieldtype, getfield,
include, invoke, is, ===, isa, isdefined, method_exists, include, invoke, is, ===, isa, isdefined, method_exists,
subtype, throw, tuple, tuplelen, tupleref, typeassert, typeof, yieldto, subtype, throw, tuple, tuplelen, tupleref, typeassert, typeof, yieldto,
# constants # constants
Expand Down
10 changes: 5 additions & 5 deletions base/client.jl
Expand Up @@ -67,7 +67,7 @@ function _jl_eval_user_input(ast::ANY, show_value)
println() println()
iserr, lasterr = false, () iserr, lasterr = false, ()
else else
value = eval(ast) value = eval(Main,ast)
global ans = value global ans = value
if !is(value,nothing) && show_value if !is(value,nothing) && show_value
if _jl_have_color if _jl_have_color
Expand Down Expand Up @@ -143,7 +143,7 @@ function process_options(args::Array{Any,1})
repl = true repl = true
startup = true startup = true
if has(ENV, "JL_POST_BOOT") if has(ENV, "JL_POST_BOOT")
eval(parse_input_line(ENV["JL_POST_BOOT"])) eval(Main,parse_input_line(ENV["JL_POST_BOOT"]))
end end
i = 1 i = 1
while i <= length(args) while i <= length(args)
Expand All @@ -157,18 +157,18 @@ function process_options(args::Array{Any,1})
repl = false repl = false
i+=1 i+=1
ARGS = args[i+1:end] ARGS = args[i+1:end]
eval(parse_input_line(args[i])) eval(Main,parse_input_line(args[i]))
break break
elseif args[i]=="-E" elseif args[i]=="-E"
repl = false repl = false
i+=1 i+=1
ARGS = args[i+1:end] ARGS = args[i+1:end]
show(eval(parse_input_line(args[i]))) show(eval(Main,parse_input_line(args[i])))
println() println()
break break
elseif args[i]=="-P" elseif args[i]=="-P"
i+=1 i+=1
eval(parse_input_line(args[i])) eval(Main,parse_input_line(args[i]))
elseif args[i]=="-L" elseif args[i]=="-L"
i+=1 i+=1
load(args[i]) load(args[i])
Expand Down
2 changes: 1 addition & 1 deletion base/expr.jl
Expand Up @@ -60,5 +60,5 @@ macroexpand(x) = ccall(:jl_macroexpand, Any, (Any,), x)
## misc syntax ## ## misc syntax ##


macro eval(x) macro eval(x)
:(eval($(expr(:quote,x)))) :($(esc(:eval))($(expr(:quote,x))))
end end
2 changes: 1 addition & 1 deletion base/multi.jl
Expand Up @@ -1185,7 +1185,7 @@ end
macro everywhere(ex) macro everywhere(ex)
quote quote
@sync begin @sync begin
at_each(()->eval($(expr(:quote,ex)))) at_each(()->eval(Main,$(expr(:quote,ex))))
end end
end end
end end
Expand Down
2 changes: 1 addition & 1 deletion base/show.jl
Expand Up @@ -776,7 +776,7 @@ function whos(m::Module, pattern::Regex)
for s in sort(map(string, names(m))) for s in sort(map(string, names(m)))
v = symbol(s) v = symbol(s)
if isdefined(m,v) && ismatch(pattern, s) if isdefined(m,v) && ismatch(pattern, s)
println(rpad(v, 30), summary(eval(m,v))) println(rpad(s, 30), summary(eval(m,v)))
end end
end end
end end
Expand Down
3 changes: 3 additions & 0 deletions base/sysimg.jl
@@ -1,5 +1,8 @@
baremodule Base baremodule Base


eval(x) = Core.eval(Base,x)
eval(m,x) = Core.eval(m,x)

include("export.jl") include("export.jl")


if false if false
Expand Down
2 changes: 1 addition & 1 deletion base/util.jl
Expand Up @@ -262,7 +262,7 @@ function remote_load(dict)
end end
end end


evalfile(fname::String) = eval(parse(readall(fname))[1]) evalfile(fname::String) = eval(Main,parse(readall(fname))[1])


# help # help


Expand Down
36 changes: 27 additions & 9 deletions doc/manual/modules.rst
Expand Up @@ -14,7 +14,7 @@ and specify which of your names are intended to be public (via exporting).
The following example illustrates the major features of modules:: The following example illustrates the major features of modules::


module MyModule module MyModule
using Base using Lib
export MyType, foo export MyType, foo
Expand All @@ -38,13 +38,13 @@ and type ``MyType`` are
exported, and so will be available for importing into other modules. exported, and so will be available for importing into other modules.
Function ``bar`` is private to ``MyModule``. Function ``bar`` is private to ``MyModule``.


The statement ``using Base`` means that the ``Base`` module (which contains The statement ``using Lib`` means that a module called ``Lib``
the standard library definitions) will be available for resolving names will be available for resolving names
as needed. When a global variable is encountered that has no definition in as needed. When a global variable is encountered that has no definition in
the current module, the system will search for it in ``Base`` and import it the current module, the system will search for it in ``Lib`` and import it
if it is found there. if it is found there.
This means that all uses of that global within the current module will This means that all uses of that global within the current module will
resolve to the definition of that variable in ``Base``. resolve to the definition of that variable in ``Lib``.


Once a variable is imported this way (or, equivalently, with the ``import`` Once a variable is imported this way (or, equivalently, with the ``import``
keyword), a module may not create its own variable with the same name. keyword), a module may not create its own variable with the same name.
Expand Down Expand Up @@ -78,7 +78,6 @@ for example testing code by running it with "safe" versions of some
operators:: operators::


module Normal module Normal
using Base
include("mycode.jl") include("mycode.jl")
end end


Expand All @@ -96,15 +95,34 @@ There are three important standard modules: Main, Core, and Base.
Main is the top-level module, and Julia starts with Main set as the Main is the top-level module, and Julia starts with Main set as the
current module. current module.
Variables defined at the prompt go in Main, and ``whos()`` lists variables Variables defined at the prompt go in Main, and ``whos()`` lists variables
in Main. Main implicitly contains ``using Base``. in Main.


Core contains all identifiers considered "built in" to the language, i.e. Core contains all identifiers considered "built in" to the language, i.e.
part of the core language and not libraries. Every module implicitly part of the core language and not libraries. Every module implicitly
specifies ``using Core``, since you can't do anything without those specifies ``using Core``, since you can't do anything without those
definitions. definitions.


Base is the standard library (the contents of base/). This is not imported Base is the standard library (the contents of base/). All modules implicitly
by default, so most modules will want to start with ``using Base``. contain ``using Base``, since this is needed in the vast majority of cases.


Default top-level definitions and bare modules
----------------------------------------------

In addition to ``using Base``, a module automatically contains a definition
of the ``eval`` function, which evaluates expressions within the context of
that module.

If these definitions are not wanted, modules can be defined using the
keyword ``baremodule`` instead. In terms of ``baremodule``, a standard
``module`` looks like this:

baremodule Mod
using Base
eval(x) = Core.eval(Mod, x)
eval(m,x) = Core.eval(m, x)
...
end




Miscellaneous details Miscellaneous details
Expand Down
31 changes: 15 additions & 16 deletions src/builtins.c
Expand Up @@ -263,30 +263,29 @@ JL_CALLABLE(jl_f_apply)


JL_CALLABLE(jl_f_top_eval) JL_CALLABLE(jl_f_top_eval)
{ {
jl_module_t *m;
jl_value_t *ex;
if (nargs == 1) { if (nargs == 1) {
jl_expr_t *ex = (jl_expr_t*)args[0]; m = jl_main_module;
/* ex = args[0];
if (jl_is_expr(ex) && (ex->head == export_sym ||
ex->head == import_sym ||
ex->head == using_sym)) {
jl_errorf("unsupported or misplaced expression %s", ex->head->name);
}
*/
return jl_toplevel_eval((jl_value_t*)ex);
} }
if (nargs != 2) { else {
JL_NARGS(eval, 1, 1); JL_NARGS(eval, 2, 2);
JL_TYPECHK(eval, module, args[0]);
m = (jl_module_t*)args[0];
ex = args[1];
}
if (jl_is_symbol(ex)) {
return jl_eval_global_var(m, (jl_sym_t*)ex);
} }
JL_TYPECHK(eval, module, args[0]); if (m == jl_current_module) {
jl_module_t *m = (jl_module_t*)args[0]; return jl_toplevel_eval(ex);
if (jl_is_symbol(args[1])) {
return jl_eval_global_var(m, (jl_sym_t*)args[1]);
} }
jl_value_t *v=NULL; jl_value_t *v=NULL;
jl_module_t *last_m = jl_current_module; jl_module_t *last_m = jl_current_module;
JL_TRY { JL_TRY {
jl_current_module = m; jl_current_module = m;
v = jl_toplevel_eval(args[1]); v = jl_toplevel_eval(ex);
} }
JL_CATCH { JL_CATCH {
jl_current_module = last_m; jl_current_module = last_m;
Expand Down
2 changes: 2 additions & 0 deletions src/init.c
Expand Up @@ -210,6 +210,8 @@ void julia_init(char *imageFile)
// it does "using Base" if Base is available. // it does "using Base" if Base is available.
if (jl_base_module != NULL) if (jl_base_module != NULL)
jl_module_using(jl_main_module, jl_base_module); jl_module_using(jl_main_module, jl_base_module);
// eval() uses Main by default, so Main.eval === Core.eval
jl_module_import(jl_main_module, jl_core_module, jl_symbol("eval"));
jl_current_module = jl_main_module; jl_current_module = jl_main_module;


#ifndef __WIN32__ #ifndef __WIN32__
Expand Down
17 changes: 14 additions & 3 deletions src/julia-parser.scm
Expand Up @@ -965,9 +965,20 @@
(error "expected assignment after const") (error "expected assignment after const")
`(const ,assgn)))) `(const ,assgn))))
((module baremodule) ((module baremodule)
(let ((name (parse-atom s))) (let* ((name (parse-atom s))
(begin0 (list 'module (eq? word 'module) name (parse-block s)) (body (parse-block s)))
(expect-end s)))) (expect-end s)
(list 'module (eq? word 'module) name
(if (eq? word 'module)
(list* 'block
;; add definitions for module-local eval
(let ((x (gensym)))
`(= (call eval ,x)
(call (|.| Core 'eval) ,name ,x)))
`(= (call eval m x)
(call (|.| Core 'eval) m x))
(cdr body))
body))))
((export) ((export)
(let ((es (map macrocall-to-atsym (let ((es (map macrocall-to-atsym
(parse-comma-separated-assignments s)))) (parse-comma-separated-assignments s))))
Expand Down

0 comments on commit 9ecd207

Please sign in to comment.