1+ # Non-incremental lowering API for non-toplevel non-module expressions.
2+ # May be removed?
3+
14function lower (mod:: Module , ex0; expr_compat_mode= false , world= Base. get_world_counter ())
25 ctx1, ex1 = expand_forms_1 ( mod, ex0, expr_compat_mode, world)
36 ctx2, ex2 = expand_forms_2 ( ctx1, ex1)
@@ -12,6 +15,96 @@ function macroexpand(mod::Module, ex; expr_compat_mode=false, world=Base.get_wor
1215 ex1
1316end
1417
18+ # Incremental lowering API which can manage toplevel and module expressions.
19+ #
20+ # This iteration API is oddly bespoke and arguably somewhat non-Julian for two
21+ # reasons:
22+ #
23+ # * Lowering knows when new modules are required, and may request them with
24+ # `:begin_module`. However `eval()` generates those modules so they need to
25+ # be passed back into lowering. So we can't just use `Base.iterate()`. (Put a
26+ # different way, we have a situation which is suited to coroutines but we
27+ # don't want to use full Julia `Task`s for this.)
28+ # * We might want to implement this `eval()` in Julia's C runtime code or early
29+ # in bootstrap. Hence using SimpleVector and Symbol as the return values of
30+ # `lower_step()`
31+ #
32+ # We might consider changing at least the second of these choices, depending on
33+ # how we end up putting this into Base.
34+
35+ struct LoweringIterator{GraphType}
36+ ctx:: MacroExpansionContext{GraphType}
37+ todo:: Vector{Tuple{SyntaxTree{GraphType}, Bool, Int}}
38+ end
39+
40+ function lower_init (ex:: SyntaxTree , mod:: Module , macro_world:: UInt ; expr_compat_mode:: Bool = false )
41+ graph = ensure_macro_attributes (syntax_graph (ex))
42+ ctx = MacroExpansionContext (graph, mod, expr_compat_mode, macro_world)
43+ ex = reparent (ctx, ex)
44+ LoweringIterator {typeof(graph)} (ctx, [(ex, false , 0 )])
45+ end
46+
47+ function lower_step (iter, push_mod= nothing )
48+ if ! isnothing (push_mod)
49+ push_layer! (iter. ctx, push_mod, false )
50+ end
51+
52+ if isempty (iter. todo)
53+ return Core. svec (:done )
54+ end
55+
56+ ex, is_module_body, child_idx = pop! (iter. todo)
57+ if child_idx > 0
58+ next_child = child_idx + 1
59+ if child_idx <= numchildren (ex)
60+ push! (iter. todo, (ex, is_module_body, next_child))
61+ ex = ex[child_idx]
62+ else
63+ if is_module_body
64+ pop_layer! (iter. ctx)
65+ return Core. svec (:end_module )
66+ else
67+ return lower_step (iter)
68+ end
69+ end
70+ end
71+
72+ k = kind (ex)
73+ if ! (k in KSet " toplevel module" )
74+ ex = expand_forms_1 (iter. ctx, ex)
75+ k = kind (ex)
76+ end
77+ if k == K " toplevel"
78+ push! (iter. todo, (ex, false , 1 ))
79+ return lower_step (iter)
80+ elseif k == K " module"
81+ name = ex[1 ]
82+ if kind (name) != K " Identifier"
83+ throw (LoweringError (name, " Expected module name" ))
84+ end
85+ newmod_name = Symbol (name. name_val)
86+ body = ex[2 ]
87+ if kind (body) != K " block"
88+ throw (LoweringError (body, " Expected block in module body" ))
89+ end
90+ std_defs = ! has_flags (ex, JuliaSyntax. BARE_MODULE_FLAG)
91+ loc = source_location (LineNumberNode, ex)
92+ push! (iter. todo, (body, true , 1 ))
93+ return Core. svec (:begin_module , newmod_name, std_defs, loc)
94+ else
95+ # Non macro expansion parts of lowering
96+ ctx2, ex2 = expand_forms_2 (iter. ctx, ex)
97+ ctx3, ex3 = resolve_scopes (ctx2, ex2)
98+ ctx4, ex4 = convert_closures (ctx3, ex3)
99+ ctx5, ex5 = linearize_ir (ctx4, ex4)
100+ thunk = to_lowered_expr (ex5)
101+ return Core. svec (:thunk , thunk)
102+ end
103+ end
104+
105+
106+ # -------------------------------------------------------------------------------
107+
15108function codeinfo_has_image_globalref (@nospecialize (e))
16109 if e isa GlobalRef
17110 return 0x00 != = @ccall jl_object_in_image (e. mod:: Any ):: UInt8
@@ -274,7 +367,7 @@ function _to_lowered_expr(ex::SyntaxTree, stmt_offset::Int)
274367 elseif k == K " code_info"
275368 ir = to_code_info (ex[1 ], ex. slots)
276369 if ex. is_toplevel_thunk
277- Expr (:thunk , ir)
370+ Expr (:thunk , ir) # TODO : Maybe nice to just return a CodeInfo here?
278371 else
279372 ir
280373 end
@@ -357,19 +450,74 @@ function _to_lowered_expr(ex::SyntaxTree, stmt_offset::Int)
357450end
358451
359452# -------------------------------------------------------------------------------
360- # Our version of eval takes our own data structures
361- @fzone " JL: eval" function eval (mod:: Module , ex:: SyntaxTree ; expr_compat_mode:: Bool = false )
362- k = kind (ex)
363- if k == K " toplevel"
364- x = nothing
365- for e in children (ex)
366- x = eval (mod, e; expr_compat_mode)
453+ # Our version of eval - should be upstreamed though?
454+ @fzone " JL: eval" function eval (mod:: Module , ex:: SyntaxTree ;
455+ macro_world:: UInt = Base. get_world_counter (),
456+ opts... )
457+ iter = lower_init (ex, mod, macro_world; opts... )
458+ _eval (mod, iter)
459+ end
460+
461+ if VERSION >= v " 1.13.0-DEV.1199" # https://github.com/JuliaLang/julia/pull/59604
462+
463+ function _eval (mod, iter)
464+ modules = Module[]
465+ new_mod = nothing
466+ result = nothing
467+ while true
468+ thunk = lower_step (iter, new_mod):: Core.SimpleVector
469+ new_mod = nothing
470+ type = thunk[1 ]:: Symbol
471+ if type == :done
472+ break
473+ elseif type == :begin_module
474+ push! (modules, mod)
475+ mod = @ccall jl_begin_new_module (mod:: Any , thunk[2 ]:: Symbol , thunk[3 ]:: Cint ,
476+ thunk[4 ]. file:: Cstring , thunk[4 ]. line:: Cint ):: Module
477+ new_mod = mod
478+ elseif type == :end_module
479+ @ccall jl_end_new_module (mod:: Module ):: Cvoid
480+ result = mod
481+ mod = pop! (modules)
482+ else
483+ @assert type == :thunk
484+ result = Core. eval (mod, thunk[2 ])
485+ end
486+ end
487+ @assert isempty (modules)
488+ return result
489+ end
490+
491+ else
492+
493+ function _eval (mod, iter, new_mod= nothing )
494+ in_new_mod = ! isnothing (new_mod)
495+ result = nothing
496+ while true
497+ thunk = lower_step (iter, new_mod):: Core.SimpleVector
498+ new_mod = nothing
499+ type = thunk[1 ]:: Symbol
500+ if type == :done
501+ @assert ! in_new_mod
502+ break
503+ elseif type == :begin_module
504+ name = thunk[2 ]:: Symbol
505+ std_defs = thunk[3 ]
506+ result = Core. eval (mod,
507+ Expr (:module , std_defs, name,
508+ Expr (:block , thunk[4 ], Expr (:call , m-> _eval (m, iter, m), name)))
509+ )
510+ elseif type == :end_module
511+ @assert in_new_mod
512+ return mod
513+ else
514+ @assert type == :thunk
515+ result = Core. eval (mod, thunk[2 ])
367516 end
368- return x
369517 end
370- linear_ir = lower (mod, ex; expr_compat_mode)
371- thunk = to_lowered_expr (linear_ir)
372- Core . eval (mod, thunk)
518+ return result
519+ end
520+
373521end
374522
375523"""
0 commit comments