Last active
August 21, 2018 19:52
-
-
Save stevengj/255cb778efcc72a84dbf97ecbbf221fe to your computer and use it in GitHub Desktop.
draft julia function to make ASTs use soft global scope
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Base.Meta: isexpr | |
const assignments = Set((:(=), :(+=), :(-=), :(*=), :(/=), :(//=), :(\=), :(^=), :(÷=), :(%=), :(<<=), :(>>=), :(>>>=), :(|=), :(&=), :(⊻=), :($=))) | |
localvar(ex::Expr) = isexpr(ex, :(=)) ? ex.args[1] : nothing | |
localvar(ex) = nothing | |
function soft_globals(ex::Expr, globals, insertglobal=false) | |
if isexpr(ex, :for) || isexpr(ex, :while) | |
return Expr(ex.head, ex.args[1], soft_globals(ex.args[2], globals, true)) | |
elseif isexpr(ex, :try) | |
try_clause = soft_globals(ex.args[1], globals, true) | |
catch_clause = soft_globals(ex.args[1], ex.args[2] isa Symbol ? setdiff(globals, ex.args[2:2]) : globals, true) | |
finally_clause = soft_globals(ex.args[4], globals, true) | |
return Expr(:try, try_clause, ex.args[2], catch_clause, finally_clause) | |
elseif isexpr(ex, :let) | |
letglobals = setdiff(globals, isexpr(ex.args[1], :(=)) ? [ex.args[1].args[1]] : [localvar(ex) for ex in ex.args[1].args]) | |
return Expr(ex.head, soft_globals(ex.args[1], globals, insertglobal), | |
soft_globals(ex.args[2], letglobals, true)) | |
elseif isexpr(ex, :block) || isexpr(ex, :if) | |
return Expr(ex.head, soft_globals.(ex.args, Ref(globals), insertglobal)...) | |
elseif insertglobal && ex.head in assignments && ex.args[1] in globals | |
return Expr(:global, Expr(ex.head, ex.args[1], soft_globals(ex.args[2], globals, insertglobal))) | |
else | |
return ex | |
end | |
end | |
soft_globals(ex, globals, insertglobal=false) = ex | |
globalize(m::Module, ast) = soft_globals(ast, Set(names(m)), false) | |
function globalize_include_string(m::Module, code::AbstractString, filename::AbstractString="string") | |
# use the undocumented parse_input_line function so that we preserve | |
# the filename and line-number information. | |
expr = Base.parse_input_line("begin; "*code*"\nend\n", filename=filename) | |
retval = nothing | |
# expr.args should consist of LineNumberNodes followed by expressions to evaluate | |
for i = 2:2:length(expr.args) | |
retval = Core.eval(m, globalize(m, Expr(:block, expr.args[i-1:i]...))) | |
end | |
return retval | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment