Skip to content

Commit eede4fc

Browse files
committed
Implement definition(method, String) and add internal data
1 parent 4ba9c6f commit eede4fc

File tree

5 files changed

+112
-5
lines changed

5 files changed

+112
-5
lines changed

src/CodeTracking.jl

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,80 @@
11
module CodeTracking
22

3-
export whereis
3+
using Core: LineInfoNode
44

5-
# This is just a stub implementation for now
5+
export whereis, definition, pkgfiles
6+
7+
include("data.jl")
8+
include("utils.jl")
9+
10+
"""
11+
filepath, line = whereis(method::Method)
12+
13+
Return the file and line of the definition of `method`. `line`
14+
is the first line of the method's body.
15+
"""
616
function whereis(method::Method)
7-
file, line = String(method.file), method.line
17+
lin = get(method_locations, method.sig, nothing)
18+
if lin === nothing
19+
file, line = String(method.file), method.line
20+
else
21+
file, line = fileline(lin)
22+
end
823
if !isabspath(file)
9-
# This is a Base method
24+
# This is a Base or Core method
1025
file = Base.find_source_file(file)
1126
end
1227
return normpath(file), line
1328
end
1429

30+
"""
31+
src = definition(method::Method, String)
32+
33+
Return a string with the code that defines `method`.
34+
35+
Note this may not be terribly useful for methods that are defined inside `@eval` statements;
36+
see [`definition(method::Method, Expr)`](@ref) instead.
37+
"""
38+
function definition(method::Method, ::Type{String})
39+
file, line = whereis(method)
40+
src = read(file, String)
41+
eol = isequal('\n')
42+
linestarts = Int[]
43+
istart = 0
44+
for i = 1:line-1
45+
push!(linestarts, istart+1)
46+
istart = findnext(eol, src, istart+1)
47+
end
48+
ex, iend = Meta.parse(src, istart)
49+
if isfuncexpr(ex)
50+
return src[istart+1:iend-1]
51+
end
52+
# The function declaration was presumably on a previous line
53+
lineindex = lastindex(linestarts)
54+
while !isfuncexpr(ex)
55+
istart = linestarts[lineindex]
56+
ex, iend = Meta.parse(src, istart)
57+
end
58+
return src[istart:iend-1]
59+
end
60+
61+
"""
62+
ex = definition(method::Method, Expr)
63+
ex = definition(method::Method)
64+
65+
Return an expression that defines `method`.
66+
"""
67+
definition(method::Method, ::Type{Expr}) = get(method_definitions, method.sig, nothing)
68+
69+
definition(method::Method) = definition(method, Expr)
70+
71+
"""
72+
files = pkgfiles(mod::Module)
73+
74+
Return a list of the files that were loaded to define `mod`.
75+
"""
76+
function pkgfiles(mod::Module)
77+
error("not implemented")
78+
end
79+
1580
end # module

src/data.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# The variables here get populated by Revise.jl.
2+
3+
const method_locations = IdDict{Type,LineInfoNode}()
4+
5+
const method_definitions = IdDict{Type,Expr}()

src/utils.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
function isfuncexpr(ex)
2+
ex.head == :function && return true
3+
if ex.head == :(=)
4+
a = ex.args[1]
5+
if isa(a, Expr)
6+
while a.head == :where
7+
a = a.args[1]
8+
isa(a, Expr) || return false
9+
end
10+
a.head == :call && return true
11+
end
12+
end
13+
return false
14+
end
15+
16+
fileline(lin::LineInfoNode) = String(lin.file), lin.line

test/runtests.jl

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,22 @@
11
using CodeTracking
22
using Test
33

4+
include("script.jl")
5+
46
@testset "CodeTracking.jl" begin
5-
# Write your own tests here.
7+
m = first(methods(f1))
8+
file, line = whereis(m)
9+
@test file == normpath(joinpath(@__DIR__, "script.jl"))
10+
src = definition(m, String)
11+
@test src == """
12+
function f1(x, y)
13+
return x + y
14+
end
15+
"""
16+
17+
m = first(methods(f2))
18+
src = definition(m, String)
19+
@test src == """
20+
f2(x, y) = x + y
21+
"""
622
end

test/script.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function f1(x, y)
2+
return x + y
3+
end
4+
5+
f2(x, y) = x + y

0 commit comments

Comments
 (0)