Skip to content

Commit d31055e

Browse files
committed
add @locals macro for obtaining dictionary of local vars and values
implements #29366
1 parent 8fe1d24 commit d31055e

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

base/reflection.jl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,42 @@ macro isdefined(s::Symbol)
250250
return Expr(:isdefined, esc(s))
251251
end
252252

253+
"""
254+
@locals()
255+
256+
Construct a dictionary of the names (as symbols) and values of all local
257+
variables defined as of the call site.
258+
259+
# Examples
260+
```jldoctest
261+
julia> let x = 1, y = 2
262+
Base.@locals
263+
end
264+
Dict{Symbol,Any} with 2 entries:
265+
:y => 2
266+
:x => 1
267+
268+
julia> function f(x)
269+
local y
270+
show(Base.@locals); println()
271+
for i = 1:1
272+
show(Base.@locals); println()
273+
end
274+
y = 2
275+
show(Base.@locals); println()
276+
nothing
277+
end;
278+
279+
julia> f(42)
280+
Dict{Symbol,Any}(:x=>42)
281+
Dict{Symbol,Any}(:i=>1,:x=>42)
282+
Dict{Symbol,Any}(:y=>2,:x=>42)
283+
```
284+
"""
285+
macro locals()
286+
return Expr(:locals)
287+
end
288+
253289
"""
254290
objectid(x)
255291

src/julia-syntax.scm

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,6 +2426,27 @@
24262426
(if (not (memq (cadr e) env))
24272427
(error "no outer local variable declaration exists for \"for outer\""))
24282428
'(null))
2429+
((eq? (car e) 'locals)
2430+
(let* ((names (filter (lambda (v)
2431+
(and (not (gensym? v))
2432+
(not (length= (string-split (string v) "#") 2))
2433+
(let ((r (assq v renames)))
2434+
(or (atom? r)
2435+
(let ((mapping (cdr r)))
2436+
(not (and (pair? mapping)
2437+
(eq? (car mapping) 'outerref))))))))
2438+
env))
2439+
(names (delete-duplicates
2440+
(filter (lambda (v) (not (eq? v '||)))
2441+
(map unmangled-name names))))
2442+
(d (make-ssavalue)))
2443+
`(block (= ,d (call (call (core apply_type) (top Dict) (core Symbol) (core Any))))
2444+
,@(map (lambda (v)
2445+
(let ((var (resolve-scopes- v env implicitglobals lam renames newlam sp)))
2446+
`(if (isdefined ,var)
2447+
(call (top setindex!) ,d ,var (quote ,v)))))
2448+
names)
2449+
,d)))
24292450
((eq? (car e) 'lambda)
24302451
(let* ((lv (lam:vars e))
24312452
(env (append lv env))
@@ -2478,6 +2499,7 @@
24782499
(new-renames (append (map cons need-rename renamed) ;; map from definition name -> gensym name
24792500
(map cons need-rename-def renamed-def)
24802501
(map (lambda (g) (cons g `(outerref ,g))) new-iglo)
2502+
(map (lambda (g) (cons g `(outerref ,g))) glob)
24812503
(filter (lambda (ren) ;; old renames list, with anything in vars removed
24822504
(let ((var (car ren)))
24832505
(not (or (memq var all-vars) ;; remove anything new

test/reflection.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,3 +805,36 @@ f20872(::Val, ::Val) = false
805805
@test which(f20872, Tuple{Val,Val}).sig == Tuple{typeof(f20872), Val, Val}
806806
@test which(f20872, Tuple{Val,Val{N}} where N).sig == Tuple{typeof(f20872), Val, Val}
807807
@test_throws ErrorException which(f20872, Tuple{Any,Val{N}} where N)
808+
809+
# @locals
810+
using Base: @locals
811+
let
812+
local x, y
813+
global z
814+
@test isempty(keys(@locals))
815+
x = 1
816+
@test @locals() == Dict{Symbol,Any}(:x=>1)
817+
y = ""
818+
@test @locals() == Dict{Symbol,Any}(:x=>1,:y=>"")
819+
for i = 8:8
820+
@test @locals() == Dict{Symbol,Any}(:x=>1,:y=>"",:i=>8)
821+
end
822+
for i = 42:42
823+
local x
824+
@test @locals() == Dict{Symbol,Any}(:y=>"",:i=>42)
825+
end
826+
@test @locals() == Dict{Symbol,Any}(:x=>1,:y=>"")
827+
x = (y,)
828+
@test @locals() == Dict{Symbol,Any}(:x=>("",),:y=>"")
829+
end
830+
831+
function _test_at_locals1(::Any, ::Any)
832+
x = 1
833+
@test @locals() == Dict{Symbol,Any}(:x=>1)
834+
end
835+
_test_at_locals1(1,1)
836+
function _test_at_locals2(a::Any, ::Any)
837+
x = 2
838+
@test @locals() == Dict{Symbol,Any}(:x=>2,:a=>a)
839+
end
840+
_test_at_locals2(1,1)

0 commit comments

Comments
 (0)