Skip to content

Commit

Permalink
Add tuple assignments (#19)
Browse files Browse the repository at this point in the history
* Add tuple assignments

* Correct generated AST for tuple assignments

* Fix for non-global tuple assignment

* Tests for tuple assignment

* One more test for function assignment

* fixes

* test for expression inside tuple assignment

* Added extra Refs for broadcasting

* Ignore assignments to calls and add :ref

* fix ref

* whoops

* apply softscope recursively to tuples

* Added test for named tuples

* treat assignments like keywords in named tuples
  • Loading branch information
David Barton authored and stevengj committed Jan 9, 2019
1 parent ac58bed commit 1c696f6
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 7 deletions.
25 changes: 18 additions & 7 deletions src/SoftGlobalScope.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ else
using Base.Meta: isexpr

const assignments = Set((:(=), :(+=), :(-=), :(*=), :(/=), :(//=), :(\=), :(^=), :(÷=), :(%=), :(<<=), :(>>=), :(>>>=), :(|=), :(&=), :(⊻=), :($=)))
const calls = Set((:call, :comparison, :(&&), :(||)))
const calls = Set((:call, :comparison, :(&&), :(||), :ref, :tuple))

# extract the local variable names (e.g. `[:x]`) from assignments (e.g. `x=1`) etc.
function localvars(ex::Expr)
Expand Down Expand Up @@ -120,7 +120,7 @@ else
recursively set to `true` for local scopes introduced by `for` etcetera.)
NOTE: `_softscope`` may mutate the `globals` argument (if there are `local` declarations.)
"""
function _softscope(ex::Expr, globals, locals, insertglobal::Bool=false)
function _softscope(ex::Expr, globals, locals, insertglobal::Bool=false, noassignment::Bool=false)
if isexpr(ex, :for)
return Expr(ex.head, localassignment(ex.args[1], copy(globals), copy(locals), insertglobal),
_softscope(ex.args[2], copy(globals), copy(locals), true))
Expand Down Expand Up @@ -149,19 +149,30 @@ else
union!(locals, localvars(ex.args)) # affects globals in surrounding scope!
return ex
elseif ex.head in calls
return Expr(ex.head, (_softscope.(ex.args, Ref(globals), Ref(locals), insertglobal))...)
elseif isexpr(ex, :kw)
return Expr(ex.head, _softscope.(ex.args, Ref(globals), Ref(locals), insertglobal, ex.head === :tuple)...)
elseif isexpr(ex, :kw) || (noassignment && ex.head in assignments)
return Expr(ex.head, ex.args[1], _softscope(ex.args[2], globals, locals, insertglobal))
elseif insertglobal && ex.head in assignments && ex.args[1] in globals && !(ex.args[1] in locals)
return Expr(:global, Expr(ex.head, ex.args[1], _softscope(ex.args[2], globals, locals, insertglobal)))
elseif insertglobal && ex.head in assignments
if isexpr(ex.args[1], :call)
return ex
elseif ex.args[1] in globals && !(ex.args[1] in locals) # Simple assignment to global
return Expr(:global, Expr(ex.head, ex.args[1], _softscope(ex.args[2], globals, locals, insertglobal)))
end
softex = Expr(ex.head, _softscope.(ex.args, Ref(globals), Ref(locals), insertglobal)...)
if isexpr(ex.args[1], :tuple) # Assignment to a tuple
vars = [var for var in localvars(ex.args[1].args) if (var in globals) && !(var in locals)]
return isempty(vars) ? softex : Expr(:block, Expr(:global, vars...), softex)
else
return softex
end
elseif !insertglobal && isexpr(ex, :(=)) # only assignments in the global scope need to be considered
union!(globals, localvars(ex))
return ex
else
return ex
end
end
_softscope(ex, globals, locals, insertglobal::Bool=false) = ex
_softscope(ex, globals, locals, insertglobal::Bool=false, noassignment::Bool=false) = ex

softscope(m::Module, ast) = _softscope(ast, Set(@static VERSION < v"0.7.0-DEV.3526" ? names(m, true) : names(m, all=true)), Set{Symbol}())

Expand Down
6 changes: 6 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ end
@test softscope(TestMod, nl"for i=r; true && (a += 1); end") == nl"for i=r; true && (global a += 1); end"
@test softscope(TestMod, nl"for i=r; true || (a += 1); end") == nl"for i=r; true || (global a += 1); end"
@test softscope(TestMod, nl"for i=r; 0 < (a += 1) < 10; end") == nl"for i=r; 0 < (global a += 1) < 10; end"
@test softscope(TestMod, nl"for i = 1:10; x,y = (i+1, i+2); end") == nl"for i = 1:10; x,y = (i+1, i+2); end"
@test softscope(TestMod, nl"for i = 1:10; a,x = (i+a, i+1); end") == nl"for i = 1:10; begin; global a; a,x = (i+a, i+1); end; end"
@test softscope(TestMod, nl"for i = 1:10; a,b,x = (i+a, a+b, i+1); end") == nl"for i = 1:10; begin; global a, b; a,b,x = (i+a, a+b, i+1); end; end"
@test softscope(TestMod, nl"j=0; for i = 1:10; (a[j+=1],x) = (i, i+1); end") == nl"j=0; for i = 1:10; (a[global j+=1],x) = (i, i+1); end"
@test softscope(TestMod, nl"myfunc(a) = (b = 0; for i = 1:10; b += i; a += b; end; a)") == nl"myfunc(a) = (b = 0; for i = 1:10; b += i; a += b; end; a)"
@test softscope(TestMod, nl"let; x = (a=1, aa=2); end") == nl"let; x = (a=1, aa=2); end"
end
end

Expand Down

0 comments on commit 1c696f6

Please sign in to comment.