Skip to content

Commit 8ef53a0

Browse files
committed
Cleanup runtime.jl and move syntax extension macros to their own file.
This is pure code movement to groups code more logically and clearly and some edits to comments. There's no functional changes.
1 parent 9e7d9e4 commit 8ef53a0

File tree

3 files changed

+213
-193
lines changed

3 files changed

+213
-193
lines changed

src/JuliaLowering.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ _include("scope_analysis.jl")
2929
_include("closure_conversion.jl")
3030
_include("linear_ir.jl")
3131
_include("runtime.jl")
32+
_include("syntax_macros.jl")
3233

3334
_include("eval.jl")
3435

src/runtime.jl

Lines changed: 30 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
1-
# Runtime support functionality.
1+
# Runtime support for
2+
# 1. Functions called by the code emitted from lowering
3+
# 2. Introspecting Julia's state during lowering
24
#
3-
# Lowering generates code which uses these functions and types but it doesn't
4-
# call them directly.
5-
#
6-
# These should probably move to `Core` at some point?
5+
# These should probably all move to `Core` at some point.
6+
7+
#-------------------------------------------------------------------------------
8+
# Functions/types used by code emitted from lowering, but not called by it directly
79

10+
# Return the current exception. In JuliaLowering we use this rather than the
11+
# special form `K"the_exception"` to reduces the number of special forms.
12+
Base.@assume_effects :removable :nothrow function current_exception()
13+
@ccall jl_current_exception(current_task()::Any)::Any
14+
end
15+
16+
#--------------------------------------------------
17+
# Supporting functions for AST interpolation (`quote`)
818
struct InterpolationContext{Graph} <: AbstractLoweringContext
919
graph::Graph
1020
values::Tuple
@@ -98,6 +108,8 @@ function interpolate_ast(ex, values...)
98108
end
99109
end
100110

111+
#--------------------------------------------------
112+
# Functions called by closure conversion
101113
function eval_closure_type(mod, closure_type_name, field_names, field_is_box)
102114
type_params = Core.TypeVar[]
103115
field_types = []
@@ -132,6 +144,9 @@ function replace_captured_locals!(codeinfo, locals)
132144
codeinfo
133145
end
134146

147+
#--------------------------------------------------
148+
# Functions which create modules or mutate their bindings
149+
135150
# Construct new bare module including only the "default names"
136151
#
137152
# using Core
@@ -199,12 +214,8 @@ function module_public(mod::Module, is_exported::Bool, identifiers...)
199214
end
200215
end
201216

202-
# Return the current exception. In JuliaLowering we use this rather than the
203-
# special form `K"the_exception"` to reduces the number of special forms.
204-
Base.@assume_effects :removable :nothrow function current_exception()
205-
@ccall jl_current_exception(current_task()::Any)::Any
206-
end
207-
217+
#--------------------------------------------------
218+
# Docsystem integration
208219
function _bind_func_docs!(f, docstr, method_metadata::Core.SimpleVector)
209220
mod = parentmodule(f)
210221
bind = Base.Docs.Binding(mod, nameof(f))
@@ -255,6 +266,9 @@ function bind_docs!(type::Type, docstr, lineno::LineNumberNode; field_docs=Core.
255266
Docs.doc!(mod, bind, Base.Docs.docstr(docstr, metadata), Union{})
256267
end
257268

269+
#--------------------------------------------------
270+
# Runtime support infrastructure for `@generated`
271+
258272
# An alternative to Core.GeneratedFunctionStub which works on SyntaxTree rather
259273
# than Expr.
260274
struct GeneratedFunctionStub
@@ -340,8 +354,9 @@ function (g::GeneratedFunctionStub)(world::UInt, source::LineNumberNode, @nospec
340354
return ci
341355
end
342356

357+
343358
#-------------------------------------------------------------------------------
344-
# The following functions are used by lowering to inspect Julia's state.
359+
# The following functions are called directly by lowering to inspect Julia's state.
345360

346361
# Get the binding for `name` if one is already resolved in module `mod`. Note
347362
# that we cannot use `isdefined(::Module, ::Symbol)` here, because that causes
@@ -389,9 +404,9 @@ end
389404
#
390405
# TODO: Remove the use of this where possible. Currently this is used within
391406
# lowering to create unique global names for keyword function bodies and
392-
# closure types as an alternative to current-julia-module-counter. However, we
393-
# should defer the it to eval-time to make lowering itself completely
394-
# non-mutating.
407+
# closure types as a more local alternative to current-julia-module-counter.
408+
# However, we should ideally defer it to eval-time to make lowering itself
409+
# completely non-mutating.
395410
function reserve_module_binding_i(mod, basename)
396411
i = 0
397412
while true
@@ -403,181 +418,3 @@ function reserve_module_binding_i(mod, basename)
403418
end
404419
end
405420

406-
#-------------------------------------------------------------------------------
407-
# The following are versions of macros from Base which act as "standard syntax
408-
# extensions" with special semantics known to lowering.
409-
#
410-
# In order to implement these here without getting into bootstrapping
411-
# difficulties, we just write them as plain old macro-named functions and add
412-
# the required __context__ argument ourselves.
413-
#
414-
# TODO: @inline, @noinline, @inbounds, @simd, @ccall, @isdefined
415-
#
416-
# TODO: Eventually we should move these to proper `macro` definitions and use
417-
# JuliaLowering.include() or something, then we'll be in the fun little
418-
# world of bootstrapping but it shouldn't be too painful :)
419-
420-
function _apply_nospecialize(ctx, ex)
421-
k = kind(ex)
422-
if k == K"Identifier" || k == K"Placeholder" || k == K"tuple"
423-
setmeta(ex; nospecialize=true)
424-
elseif k == K"..." || k == K"::" || k == K"="
425-
if k == K"::" && numchildren(ex) == 1
426-
ex = @ast ctx ex [K"::" "_"::K"Placeholder" ex[1]]
427-
end
428-
mapchildren(c->_apply_nospecialize(ctx, c), ctx, ex, 1:1)
429-
else
430-
throw(LoweringError(ex, "Invalid function argument"))
431-
end
432-
end
433-
434-
function Base.var"@nospecialize"(__context__::MacroContext, ex)
435-
_apply_nospecialize(__context__, ex)
436-
end
437-
438-
function Base.GC.var"@preserve"(__context__::MacroContext, exs...)
439-
idents = exs[1:end-1]
440-
for e in idents
441-
if kind(e) != K"Identifier"
442-
throw(MacroExpansionError(e, "Preserved variable must be a symbol"))
443-
end
444-
end
445-
@ast __context__ __context__.macrocall [K"block"
446-
[K"="
447-
"s"::K"Identifier"
448-
[K"gc_preserve_begin"
449-
idents...
450-
]
451-
]
452-
[K"="
453-
"r"::K"Identifier"
454-
exs[end]
455-
]
456-
[K"gc_preserve_end" "s"::K"Identifier"]
457-
"r"::K"Identifier"
458-
]
459-
end
460-
461-
function Base.var"@atomic"(__context__::MacroContext, ex)
462-
@chk kind(ex) == K"Identifier" || kind(ex) == K"::" (ex, "Expected identifier or declaration")
463-
@ast __context__ __context__.macrocall [K"atomic" ex]
464-
end
465-
466-
function Base.var"@label"(__context__::MacroContext, ex)
467-
@chk kind(ex) == K"Identifier"
468-
@ast __context__ ex ex=>K"symbolic_label"
469-
end
470-
471-
function Base.var"@goto"(__context__::MacroContext, ex)
472-
@chk kind(ex) == K"Identifier"
473-
@ast __context__ ex ex=>K"symbolic_goto"
474-
end
475-
476-
function Base.var"@locals"(__context__::MacroContext)
477-
@ast __context__ __context__.macrocall [K"extension" "locals"::K"Symbol"]
478-
end
479-
480-
function Base.var"@isdefined"(__context__::MacroContext, ex)
481-
@ast __context__ __context__.macrocall [K"isdefined" ex]
482-
end
483-
484-
function Base.var"@generated"(__context__::MacroContext)
485-
@ast __context__ __context__.macrocall [K"generated"]
486-
end
487-
function Base.var"@generated"(__context__::MacroContext, ex)
488-
if kind(ex) != K"function"
489-
throw(LoweringError(ex, "Expected a function argument to `@generated`"))
490-
end
491-
@ast __context__ __context__.macrocall [K"function"
492-
ex[1]
493-
[K"if" [K"generated"]
494-
ex[2]
495-
[K"block"
496-
[K"meta" "generated_only"::K"Symbol"]
497-
[K"return"]
498-
]
499-
]
500-
]
501-
end
502-
503-
# The following `@islocal` and `@inert` are macros for special syntax known to
504-
# lowering which don't exist in Base but arguably should.
505-
#
506-
# For now we have our own versions
507-
function var"@islocal"(__context__::MacroContext, ex)
508-
@chk kind(ex) == K"Identifier"
509-
@ast __context__ __context__.macrocall [K"extension"
510-
"islocal"::K"Symbol"
511-
ex
512-
]
513-
end
514-
515-
function Base.Experimental.var"@opaque"(__context__::MacroContext, ex)
516-
@chk kind(ex) == K"->"
517-
@ast __context__ __context__.macrocall [K"opaque_closure"
518-
"nothing"::K"core"
519-
"nothing"::K"core"
520-
"nothing"::K"core"
521-
true::K"Bool"
522-
ex
523-
]
524-
end
525-
526-
"""
527-
A non-interpolating quoted expression.
528-
529-
For example,
530-
531-
```julia
532-
@inert quote
533-
\$x
534-
end
535-
```
536-
537-
does not take `x` from the surrounding scope - instead it leaves the
538-
interpolation `\$x` intact as part of the expression tree.
539-
540-
TODO: What is the correct way for `@inert` to work? ie which of the following
541-
should work?
542-
543-
```julia
544-
@inert quote
545-
body
546-
end
547-
548-
@inert begin
549-
body
550-
end
551-
552-
@inert x
553-
554-
@inert \$x
555-
```
556-
557-
The especially tricky cases involve nested interpolation ...
558-
```julia
559-
quote
560-
@inert \$x
561-
end
562-
563-
@inert quote
564-
quote
565-
\$x
566-
end
567-
end
568-
569-
@inert quote
570-
quote
571-
\$\$x
572-
end
573-
end
574-
```
575-
576-
etc. Needs careful thought - we should probably just copy what lisp does with
577-
quote+quasiquote 😅
578-
"""
579-
function var"@inert"(__context__::MacroContext, ex)
580-
@chk kind(ex) == K"quote"
581-
@ast __context__ __context__.macrocall [K"inert" ex]
582-
end
583-

0 commit comments

Comments
 (0)