Skip to content

Commit

Permalink
Merge pull request #27098 from JuliaLang/jb/evalmodule
Browse files Browse the repository at this point in the history
RFC: deprecate per-module definition of `eval(module, expr)`
  • Loading branch information
JeffBezanson authored May 21, 2018
2 parents 95591e0 + c0b5583 commit 0d99811
Show file tree
Hide file tree
Showing 26 changed files with 169 additions and 152 deletions.
4 changes: 2 additions & 2 deletions base/Enums.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ macro enum(T, syms...)
typename = T
if isa(T, Expr) && T.head == :(::) && length(T.args) == 2 && isa(T.args[1], Symbol)
typename = T.args[1]
basetype = eval(__module__, T.args[2])
basetype = Core.eval(__module__, T.args[2])
if !isa(basetype, DataType) || !(basetype <: Integer) || !isbitstype(basetype)
throw(ArgumentError("invalid base type for Enum $typename, $T=::$basetype; base type must be an integer primitive type"))
end
Expand All @@ -98,7 +98,7 @@ macro enum(T, syms...)
elseif isa(s, Expr) &&
(s.head == :(=) || s.head == :kw) &&
length(s.args) == 2 && isa(s.args[1], Symbol)
i = eval(__module__, s.args[2]) # allow exprs, e.g. uint128"1"
i = Core.eval(__module__, s.args[2]) # allow exprs, e.g. uint128"1"
if !isa(i, Integer)
throw(ArgumentError("invalid value for Enum $typename, $s=$i; values must be integers"))
end
Expand Down
1 change: 0 additions & 1 deletion base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,6 @@ getptls() = ccall(:jl_get_ptls_states, Ptr{Cvoid}, ())

include(m::Module, fname::String) = ccall(:jl_load_, Any, (Any, Any), m, fname)

eval(@nospecialize(e)) = eval(Main, e)
eval(m::Module, @nospecialize(e)) = ccall(:jl_toplevel_eval_in, Any, (Any, Any), m, e)

kwfunc(@nospecialize(f)) = ccall(:jl_get_keyword_sorter, Any, (Any,), f)
Expand Down
109 changes: 38 additions & 71 deletions base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,69 +3,6 @@
## client.jl - frontend handling command line options, environment setup,
## and REPL

const text_colors = AnyDict(
:black => "\033[30m",
:red => "\033[31m",
:green => "\033[32m",
:yellow => "\033[33m",
:blue => "\033[34m",
:magenta => "\033[35m",
:cyan => "\033[36m",
:white => "\033[37m",
:light_black => "\033[90m", # gray
:light_red => "\033[91m",
:light_green => "\033[92m",
:light_yellow => "\033[93m",
:light_blue => "\033[94m",
:light_magenta => "\033[95m",
:light_cyan => "\033[96m",
:normal => "\033[0m",
:default => "\033[39m",
:bold => "\033[1m",
:underline => "\033[4m",
:blink => "\033[5m",
:reverse => "\033[7m",
:hidden => "\033[8m",
:nothing => "",
)

for i in 0:255
text_colors[i] = "\033[38;5;$(i)m"
end

const disable_text_style = AnyDict(
:bold => "\033[22m",
:underline => "\033[24m",
:blink => "\033[25m",
:reverse => "\033[27m",
:hidden => "\033[28m",
:normal => "",
:default => "",
:nothing => "",
)

# Create a docstring with an automatically generated list
# of colors.
available_text_colors = collect(Iterators.filter(x -> !isa(x, Integer), keys(text_colors)))
const possible_formatting_symbols = [:normal, :bold, :default]
available_text_colors = cat(1,
sort!(intersect(available_text_colors, possible_formatting_symbols), rev=true),
sort!(setdiff( available_text_colors, possible_formatting_symbols)))

const available_text_colors_docstring =
string(join([string("`:", key,"`")
for key in available_text_colors], ",\n", ", or \n"))

"""Dictionary of color codes for the terminal.
Available colors are: $available_text_colors_docstring as well as the integers 0 to 255 inclusive.
The color `:default` will print text in the default color while the color `:normal`
will print text with all text properties (like boldness) reset.
Printing with the color `:nothing` will print the string without modifications.
"""
text_colors

have_color = false
default_color_warn = :yellow
default_color_error = :light_red
Expand Down Expand Up @@ -180,8 +117,8 @@ function eval_user_input(@nospecialize(ast), show_value::Bool)
errcount, lasterr = 0, ()
else
ast = Meta.lower(Main, ast)
value = eval(Main, ast)
eval(Main, Expr(:body, Expr(:(=), :ans, QuoteNode(value)), Expr(:return, nothing)))
value = Core.eval(Main, ast)
Core.eval(Main, Expr(:body, Expr(:(=), :ans, QuoteNode(value)), Expr(:return, nothing)))
if !(value === nothing) && show_value
if have_color
print(answer_color())
Expand Down Expand Up @@ -291,7 +228,7 @@ function exec_options(opts)
# Load Distributed module only if any of the Distributed options have been specified.
distributed_mode = (opts.worker == 1) || (opts.nprocs > 0) || (opts.machine_file != C_NULL)
if distributed_mode
eval(Main, :(using Distributed))
Core.eval(Main, :(using Distributed))
invokelatest(Main.Distributed.process_opts, opts)
end

Expand All @@ -301,9 +238,9 @@ function exec_options(opts)
# process cmds list
for (cmd, arg) in cmds
if cmd == 'e'
eval(Main, parse_input_line(arg))
Core.eval(Main, parse_input_line(arg))
elseif cmd == 'E'
invokelatest(show, eval(Main, parse_input_line(arg)))
invokelatest(show, Core.eval(Main, parse_input_line(arg)))
println()
elseif cmd == 'L'
# load file immediately on all processors
Expand Down Expand Up @@ -388,8 +325,8 @@ function run_main_repl(interactive::Bool, quiet::Bool, banner::Bool, history_fil
if !isdefined(Main, :InteractiveUtils)
try
let InteractiveUtils = require(PkgId(UUID(0xb77e0a4c_d291_57a0_90e8_8db25a27a240), "InteractiveUtils"))
eval(Main, :(const InteractiveUtils = $InteractiveUtils))
eval(Main, :(using .InteractiveUtils))
Core.eval(Main, :(const InteractiveUtils = $InteractiveUtils))
Core.eval(Main, :(using .InteractiveUtils))
end
catch ex
@warn "Failed to insert InteractiveUtils into module Main" exception=(ex, catch_backtrace())
Expand Down Expand Up @@ -449,10 +386,40 @@ function run_main_repl(interactive::Bool, quiet::Bool, banner::Bool, history_fil
nothing
end

baremodule MainInclude
include(fname::AbstractString) = Main.Base.include(Main, fname)
eval(x) = Core.eval(Main, x)
Main.Base.@deprecate eval(m, x) Core.eval(m, x)
end

"""
eval(expr)
Evaluate an expression in the global scope of the containing module.
Every `Module` (except those defined with `baremodule`) has its own 1-argument
definition of `eval`, which evaluates expressions in that module.
"""
MainInclude.eval

"""
include(path::AbstractString)
Evaluate the contents of the input source file in the global scope of the containing module.
Every module (except those defined with `baremodule`) has its own 1-argument
definition of `include`, which evaluates the file in that module.
Returns the result of the last evaluated expression of the input file. During including,
a task-local include path is set to the directory containing the file. Nested calls to
`include` will search relative to that path. This function is typically used to load source
interactively, or to combine files in packages that are broken into multiple source files.
Use [`Base.include`](@ref) to evaluate a file into another module.
"""
MainInclude.include

function _start()
empty!(ARGS)
append!(ARGS, Core.ARGS)
@eval Main using Base.MainInclude
@eval Main import Base.MainInclude: eval, include
try
exec_options(JLOptions())
catch err
Expand Down
15 changes: 8 additions & 7 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,16 @@

macro deprecate(old, new, ex=true)
meta = Expr(:meta, :noinline)
@gensym oldmtname
if isa(old, Symbol)
oldname = Expr(:quote, old)
newname = Expr(:quote, new)
Expr(:toplevel,
ex ? Expr(:export, esc(old)) : nothing,
:(function $(esc(old))(args...)
$meta
depwarn($"`$old` is deprecated, use `$new` instead.", $oldmtname)
depwarn($"`$old` is deprecated, use `$new` instead.", Core.Typeof($(esc(old))).name.mt.name)
$(esc(new))(args...)
end),
:(const $oldmtname = Core.Typeof($(esc(old))).name.mt.name))
end))
elseif isa(old, Expr) && (old.head == :call || old.head == :where)
remove_linenums!(new)
oldcall = sprint(show_unquoted, old)
Expand All @@ -53,10 +51,9 @@ macro deprecate(old, new, ex=true)
ex ? Expr(:export, esc(oldsym)) : nothing,
:($(esc(old)) = begin
$meta
depwarn($"`$oldcall` is deprecated, use `$newcall` instead.", $oldmtname)
depwarn($"`$oldcall` is deprecated, use `$newcall` instead.", Core.Typeof($(esc(oldsym))).name.mt.name)
$(esc(new))
end),
:(const $oldmtname = Core.Typeof($(esc(oldsym))).name.mt.name))
end))
else
error("invalid usage of @deprecate")
end
Expand Down Expand Up @@ -1669,6 +1666,10 @@ end
@deprecate next(s::AbstractString, i::Integer) iterate(s, i)
@deprecate done(s::AbstractString, i::Integer) i > ncodeunits(s)

# issue #27093
# in src/jlfrontend.scm a call to `@deprecate` is generated for per-module `eval(m, x)`
@eval Core Main.Base.@deprecate(eval(e), Core.eval(Main, e))

# END 0.7 deprecations

# BEGIN 1.0 deprecations
Expand Down
6 changes: 3 additions & 3 deletions base/docs/Docs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ meta(m::Module) = isdefined(m, META) ? getfield(m, META) : IdDict()

function initmeta(m::Module)
if !isdefined(m, META)
eval(m, :(const $META = $(IdDict())))
Core.eval(m, :(const $META = $(IdDict())))
push!(modules, m)
end
nothing
Expand Down Expand Up @@ -374,7 +374,7 @@ function moduledoc(__source__, __module__, meta, def, def′)
docex = Expr(:call, doc!, name, bindingexpr(name),
docexpr(__source__, name, lazy_iterpolate(meta), metadata(__source__, __module__, name, true)))
if def === nothing
esc(:($eval($name, $(quot(docex)))))
esc(:(Core.eval($name, $(quot(docex)))))
else
def = unblock(def)
block = def.args[3].args
Expand Down Expand Up @@ -580,7 +580,7 @@ function loaddocs(docs)
data = Dict(:path => string(file), :linenumber => line)
doc = docstr(str, data)
docstring = docm(LineNumberNode(line, file), mod, doc, ex, false) # expand the real @doc macro now
eval(mod, Expr(:macrocall, unescape, nothing, docstring))
Core.eval(mod, Expr(:macrocall, unescape, nothing, docstring))
end
empty!(docs)
end
Expand Down
4 changes: 2 additions & 2 deletions base/essentials.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ Evaluate an expression with values interpolated into it using `eval`.
If two arguments are provided, the first is the module to evaluate in.
"""
macro eval(ex)
:(eval($__module__, $(Expr(:quote,ex))))
:(Core.eval($__module__, $(Expr(:quote,ex))))
end
macro eval(mod, ex)
:(eval($(esc(mod)), $(Expr(:quote,ex))))
:(Core.eval($(esc(mod)), $(Expr(:quote,ex))))
end

argtail(x, rest...) = rest
Expand Down
6 changes: 2 additions & 4 deletions base/expr.jl
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,9 @@ end
## misc syntax ##

"""
eval([m::Module], expr::Expr)
Core.eval(m::Module, expr)
Evaluate an expression in the given module and return the result. Every `Module` (except
those defined with `baremodule`) has its own 1-argument definition of `eval`, which
evaluates expressions in that module.
Evaluate an expression in the given module and return the result.
"""
Core.eval

Expand Down
36 changes: 10 additions & 26 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1080,9 +1080,8 @@ end
"""
Base.include([m::Module,] path::AbstractString)
Evaluate the contents of the input source file in the global scope of module `m`, or,
for the one argument call, in the global scope of the `Base` module.
Note that every `Module` (except those defined with `baremodule`) has its own 1-argument
Evaluate the contents of the input source file in the global scope of module `m`.
Every module (except those defined with `baremodule`) has its own 1-argument
definition of `include`, which evaluates the file in that module.
Returns the result of the last evaluated expression of the input file. During including,
a task-local include path is set to the directory containing the file. Nested calls to
Expand All @@ -1091,35 +1090,20 @@ interactively, or to combine files in packages that are broken into multiple sou
"""
Base.include # defined in sysimg.jl

"""
include(path::AbstractString)
Evaluate the contents of the input source file into the global scope of the containing module.
Every `Module` (except those defined with `baremodule`) has its own 1-argument
definition of `include`, which evaluates the file in that module.
Returns the result of the last evaluated expression of the input file. During including, a task-local include
path is set to the directory containing the file. Nested calls to `include` will search
relative to that path. This function is typically used to load source
interactively, or to combine files in packages that are broken into multiple source files.
Use [`Base.include`](@ref) to evaluate a file into another module.
"""
MainInclude.include # defined in sysimg.jl

"""
evalfile(path::AbstractString, args::Vector{String}=String[])
Load the file using [`Base.include`](@ref), evaluate all expressions,
and return the value of the last one.
"""
function evalfile(path::AbstractString, args::Vector{String}=String[])
return eval(Module(:__anon__),
Expr(:toplevel,
:(const ARGS = $args),
:(eval(x) = $(Expr(:core, :eval))(__anon__, x)),
:(eval(m, x) = $(Expr(:core, :eval))(m, x)),
:(include(x) = $(Expr(:top, :include))(__anon__, x)),
:(include($path))))
return Core.eval(Module(:__anon__),
Expr(:toplevel,
:(const ARGS = $args),
:(eval(x) = $(Expr(:core, :eval))(__anon__, x)),
:(@deprecate eval(m, x) Core.eval(m, x)),
:(include(x) = $(Expr(:top, :include))(__anon__, x)),
:(include($path))))
end
evalfile(path::AbstractString, args::Vector) = evalfile(path, String[args...])

Expand All @@ -1128,7 +1112,7 @@ function create_expr_cache(input::String, output::String, concrete_deps::typeof(
code_object = """
while !eof(stdin)
code = readuntil(stdin, '\\0')
eval(Main, Meta.parse(code))
eval(Meta.parse(code))
end
"""
io = open(pipeline(detach(`$(julia_cmd()) -O0
Expand Down
2 changes: 1 addition & 1 deletion base/osutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ macro static(ex)
@label loop
hd = ex.head
if hd (:if, :elseif, :&&, :||)
cond = eval(__module__, ex.args[1])
cond = Core.eval(__module__, ex.args[1])
if xor(cond, hd === :||)
return esc(ex.args[2])
elseif length(ex.args) == 3
Expand Down
11 changes: 4 additions & 7 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,11 @@ let SOURCE_PATH = ""
end
INCLUDE_STATE = 1 # include = Core.include

baremodule MainInclude
export include
include(fname::AbstractString) = Main.Base.include(Main, fname)
end

include("coreio.jl")

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

VecElement{T}(arg) where {T} = VecElement{T}(convert(T, arg))
convert(::Type{T}, arg) where {T<:VecElement} = T(arg)
convert(::Type{T}, arg::T) where {T<:VecElement} = arg
Expand Down Expand Up @@ -417,7 +413,6 @@ include("stacktraces.jl")
using .StackTraces

include("initdefs.jl")
include("client.jl")

# statistics
include("statistics.jl")
Expand Down Expand Up @@ -450,6 +445,8 @@ include("deprecated.jl")
# Some basic documentation
include("docs/basedocs.jl")

include("client.jl")

# Documentation -- should always be included last in sysimg.
include("docs/Docs.jl")
using .Docs
Expand Down
Loading

0 comments on commit 0d99811

Please sign in to comment.