From 8f506e1b445e20c6cfbbce866abf204f563e064b Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 27 Sep 2017 02:43:21 -0500 Subject: [PATCH] WIP --- src/Revise.jl | 72 +++++++++++++++++++++++++++++------------------- test/runtests.jl | 6 ++-- 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/Revise.jl b/src/Revise.jl index f47c6721..f2ea5ff0 100644 --- a/src/Revise.jl +++ b/src/Revise.jl @@ -267,7 +267,7 @@ end const file2modules = Dict{String,FileModules}() const module2files = Dict{Symbol,Vector{String}}() -const new_files = String[] +const included_files = Tuple{Module,String}[] function use_compiled_modules() @static if VERSION >= v"0.7.0-DEV.1698" @@ -290,22 +290,43 @@ function parse_pkg_files(modsym::Symbol) # can't fully exploit this just yet, see below. paths = Base.find_all_in_cache_path(modsym) end + files = String[] if !isempty(paths) # We got it from the precompile cache length(paths) > 1 && error("Multiple paths detected: ", paths) - _, files_mtimes = Base.cache_dependencies(paths[1]) - files = map(ft->normpath(first(ft)), files_mtimes) # idx 1 is the filename, idx 2 is the mtime - mainfile = first(files) - # We still have to parse the source code, and if there are - # multiple modules then we don't know which module to `eval` - # them into. - parse_source(mainfile, Main, dirname(mainfile)) + _, mods_files_mtimes = Base.parse_cache_header(paths[1]) + for (modname, fname, _) in mods_files_mtimes + modname == "__external__" && continue + if modname == "Base.__toplevel__" + modname = "Main" + end + mod = eval(Main, parse(modname)) + pr = parse_source(fname, mod, nothing) + if isa(pr, Pair) + push!(file2modules, pr) + end + push!(files, fname) + end else - # Non-precompiled package, so we learn the list of files through parsing - mainfile = Base.find_source_file(string(modsym)) - empty!(new_files) - parse_source(mainfile, Main, dirname(mainfile)) - files = map(normpath, new_files) + # Non-precompiled package(s) + i = 1 + while i <= length(included_files) + mod, fname = included_files[i] + if mod == Base.__toplevel__ + mod = Main + end + modstring = string(modsym) + if startswith(string(mod), modstring) || endswith(fname, modstring*".jl") + pr = parse_source(fname, mod, nothing) + if isa(pr, Pair) + push!(file2modules, pr) + end + push!(files, normpath(fname)) + deleteat!(included_files, i) + else + i += 1 + end + end end module2files[modsym] = files files @@ -330,20 +351,9 @@ function parse_source(file::AbstractString, mod::Module, path) # Create a blank ModDict to store the expressions. Parsing will "fill" this. md = ModDict(mod=>OrderedSet{RelocatableExpr}()) nfile = normpath(file) - if path != nothing - # Parsing is recursive (depth-first), so to preserve the order - # we add `file` to the list now - push!(new_files, nfile) - end - if !parse_source!(md, file, mod, path) - pop!(new_files) # since it failed, remove it from the list - return nothing - end + parse_source!(md, file, mod, path) || return nothing fm = FileModules(mod, md) - if path != nothing - file2modules[nfile] = fm - end - fm + nfile => fm end """ @@ -596,8 +606,9 @@ function revise_file_now(file0) error(file, " is not currently being tracked.") end oldmd = file2modules[file] - newmd = parse_source(file, oldmd.topmod, nothing) - if newmd != nothing + pr = parse_source(file, oldmd.topmod, nothing) + if pr != nothing + newmd = pr.second revmd = revised_statements(newmd.md, oldmd.md) try eval_revised(revmd) @@ -640,7 +651,8 @@ end Revise.track(file::AbstractString) Watch `file` for updates and [`revise`](@ref) loaded code with any -changes. If `mod` is omitted it defaults to `Main`. +changes. `mod` is the module into which `file` is evaluated; if omitted, +it defaults to `Main`. """ function track(mod::Module, file::AbstractString) isfile(file) || error(file, " is not a file") @@ -770,6 +782,8 @@ function __init__() end end push!(Base.package_callbacks, watch_package) + push!(Base.include_callbacks, + (mod::Module, fn::AbstractString) -> push!(included_files, (mod, String(fn)))) mode = get(ENV, "JULIA_REVISE", "auto") if mode == "auto" if isdefined(Base, :active_repl_backend) diff --git a/test/runtests.jl b/test/runtests.jl index 3e66d97a..153f3ff5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -62,8 +62,8 @@ k(x) = 4 # test the "mistakes" @test ReviseTest.cube(2) == 16 @test ReviseTest.Internal.mult3(2) == 8 - oldmd = Revise.parse_source(fl1, Main, dirname(fl1)) - newmd = Revise.parse_source(fl2, Main, nothing) + oldmd = Revise.parse_source(fl1, Main, dirname(fl1)).second + newmd = Revise.parse_source(fl2, Main, nothing).second revmd = Revise.revised_statements(newmd, oldmd) @test length(revmd) == 2 @test haskey(revmd, ReviseTest) && haskey(revmd, ReviseTest.Internal) @@ -84,7 +84,7 @@ k(x) = 4 @test ReviseTest.Internal.mult3(2) == 6 # Backtraces - newmd = Revise.parse_source(fl3, Main, nothing) + newmd = Revise.parse_source(fl3, Main, nothing).second revmd = Revise.revised_statements(newmd, oldmd) Revise.eval_revised(revmd) try