Skip to content

Commit

Permalink
Cleanup eval() and include() implementations
Browse files Browse the repository at this point in the history
* Extends `Core.eval` rather than having our own separate `eval2`
* Use `include` rather than `include2` as the public API
  • Loading branch information
c42f committed Apr 22, 2024
1 parent ff67fd9 commit 85ee5c7
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 36 deletions.
29 changes: 18 additions & 11 deletions src/JuliaLowering.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
module JuliaLowering
baremodule JuliaLowering

# ^ Use baremodule because we're implementing `Base.include` and `Core.eval`.
using Base
# We define a separate _include() for use in this module to avoid mixing method
# tables with the public `JuliaLowering.include()` API
_include(path::AbstractString) = Base.include(JuliaLowering, path)
using Core: eval

using JuliaSyntax

Expand All @@ -8,20 +15,20 @@ using JuliaSyntax: filename, first_byte, last_byte, source_location, span

using JuliaSyntax: is_literal, is_number, is_operator, is_prec_assignment, is_infix_op_call, is_postfix_op_call, is_error

include("kinds.jl")
_insert_kinds()
abstract type AbstractLoweringContext end

include("syntax_graph.jl")
include("ast.jl")
include("utils.jl")
_include("kinds.jl")
_insert_kinds()

abstract type AbstractLoweringContext end
_include("syntax_graph.jl")
_include("ast.jl")
_include("utils.jl")

include("desugaring.jl")
include("scope_analysis.jl")
include("linear_ir.jl")
_include("desugaring.jl")
_include("scope_analysis.jl")
_include("linear_ir.jl")

include("eval.jl")
_include("eval.jl")

function __init__()
_insert_kinds()
Expand Down
53 changes: 30 additions & 23 deletions src/eval.jl
Original file line number Diff line number Diff line change
Expand Up @@ -129,37 +129,40 @@ function to_lowered_expr(mod, var_info, ex)
end

#-------------------------------------------------------------------------------
function eval2(mod, exs::AbstractVector)
res = nothing
for e in exs
res = eval2(mod, e)
end
return res
end

# Like eval(), but uses code lowering defined by this package
function eval2(mod, ex::SyntaxTree)
# Our version of eval takes our own data structures
function Core.eval(mod::Module, ex::SyntaxTree)
k = kind(ex)
if k == K"toplevel"
return eval2(mod, children(ex))
elseif k == K"module"
m2 = Module(ex[1].name_val)
eval2(m2, children(ex[2]))
return m2
x = nothing
for e in children(ex)
x = eval(mod, e)
end
return x
end
linear_ir = lower(mod, ex)
expr_form = to_lowered_expr(mod, linear_ir.var_info, linear_ir)
Base.eval(mod, expr_form)
eval(mod, expr_form)
end

#-------------------------------------------------------------------------------
function include2(mod, filename)
path, prev = Base._include_dependency(mod, filename)
"""
include(mod::Module, path::AbstractString)
Evaluate the contents of the input source file in the global scope of module
`mod`. Every module (except those defined with baremodule) has its own
definition of `include()` omitting the `mod` argument, which evaluates the file
in that module. Returns the result of the last evaluated expression of the
input file. During including, a task-local include path is set to the directory
containing the file. Nested calls to include will search relative to that path.
This function is typically used to load source interactively, or to combine
files in packages that are broken into multiple source files.
"""
function include(mod::Module, path::AbstractString)
path, prev = Base._include_dependency(mod, path)
code = read(path, String)
tls = task_local_storage()
tls[:SOURCE_PATH] = path
try
return include_string(mod, code; filename=path)
return include_string(mod, code, path)
finally
if prev === nothing
delete!(tls, :SOURCE_PATH)
Expand All @@ -169,8 +172,12 @@ function include2(mod, filename)
end
end

function include_string(mod, str; filename=nothing)
eval2(mod, parseall(SyntaxTree, str; filename=filename))
end
"""
include_string(mod::Module, code::AbstractString, filename::AbstractString="string")
Like `include`, except reads code from the given string rather than from a file.
"""
function include_string(mod::Module, code::AbstractString, filename::AbstractString="string")
eval(mod, parseall(SyntaxTree, code; filename=filename))
end

4 changes: 2 additions & 2 deletions src/linear_ir.jl
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,11 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos)
nothing
elseif k == K"module" || k == K"toplevel"
# Both these forms can't be lowered here; they need to just be quoted
# and passed through to a call to eval2.
# and passed through to a call to eval.
# TODO: Is compile() the right place to do this?
# TODO: Restrict to toplevel only
call = makenode(ctx, ex, K"call",
makenode(ctx, ex, K"Value", JuliaLowering.eval2),
makenode(ctx, ex, K"Value", JuliaLowering.eval),
makenode(ctx, ex, K"Value", ex))
compile(ctx, call, needs_value, in_tail_pos)
elseif k == K"local_def" || k == K"local"
Expand Down

0 comments on commit 85ee5c7

Please sign in to comment.