diff --git a/JuliaLowering/src/ast.jl b/JuliaLowering/src/ast.jl index 34aec5e686981..1c2ef2fe4c8ab 100644 --- a/JuliaLowering/src/ast.jl +++ b/JuliaLowering/src/ast.jl @@ -126,48 +126,49 @@ function _append_nodeids!(graph::SyntaxGraph, ids::Vector{NodeId}, vals::SyntaxL append!(ids, vals.ids) end -function makeleaf(graph::SyntaxGraph, srcref, proto; attrs...) +function makeleaf(graph::SyntaxGraph, srcref, proto::Union{Kind, SyntaxTree}) id = newnode!(graph) ex = SyntaxTree(graph, id) copy_attrs!(ex, proto, true) - setattr!(graph, id; source=_unpack_srcref(graph, srcref), attrs...) + ex.source = _unpack_srcref(graph, srcref) return ex end -function _makenode(graph::SyntaxGraph, srcref, proto, children; attrs...) - id = newnode!(graph) - setchildren!(graph, id, children) - ex = SyntaxTree(graph, id) - copy_attrs!(ex, proto, true) - setattr!(graph, id; source=_unpack_srcref(graph, srcref), attrs...) - return SyntaxTree(graph, id) -end -function _makenode(ctx, srcref, proto, children; attrs...) - _makenode(syntax_graph(ctx), srcref, proto, children; attrs...) +function makeleaf(ctx::AbstractLoweringContext, srcref, proto) + makeleaf(syntax_graph(ctx), srcref, proto) end -function makenode(ctx, srcref, proto, children...; attrs...) - _makenode(ctx, srcref, proto, _node_ids(syntax_graph(ctx), children...); attrs...) +function makeleaf(ctx, srcref, proto, @nospecialize(attrs::AbstractVector)) + graph = syntax_graph(ctx) + ex = makeleaf(graph, srcref, proto) + for (k, v) in attrs + setattr!(graph, ex._id, k, v) + end + return ex end -function makeleaf(ctx, srcref, proto; kws...) - makeleaf(syntax_graph(ctx), srcref, proto; kws...) +function makenode(ctx, srcref, proto, children, attrs=nothing) + graph = syntax_graph(ctx) + ex = isnothing(attrs) ? makeleaf(graph, srcref, proto) : + makeleaf(graph, srcref, proto, attrs) + setchildren!(graph, ex._id, children isa SyntaxList ? children.ids : children) + return ex end -function makeleaf(ctx, srcref, k::Kind, value; kws...) - graph = syntax_graph(ctx) +function newleaf(ctx, srcref, k::Kind, @nospecialize(value)) + leaf = makeleaf(ctx, srcref, k) if k == K"Identifier" || k == K"core" || k == K"top" || k == K"Symbol" || k == K"globalref" || k == K"Placeholder" || k == K"StrMacroName" || k == K"CmdMacroName" - makeleaf(graph, srcref, k; name_val=value, kws...) + setattr!(leaf._graph, leaf._id, :name_val, value) elseif k == K"BindingId" - makeleaf(graph, srcref, k; var_id=value, kws...) + setattr!(leaf._graph, leaf._id, :var_id, value) elseif k == K"label" - makeleaf(graph, srcref, k; id=value, kws...) + setattr!(leaf._graph, leaf._id, :id, value) elseif k == K"symbolic_label" - makeleaf(graph, srcref, k; name_val=value, kws...) + setattr!(leaf._graph, leaf._id, :name_val, value) elseif k in KSet"TOMBSTONE SourceLocation latestworld latestworld_if_toplevel" - makeleaf(graph, srcref, k; kws...) + # no attributes else val = k == K"Integer" ? convert(Int, value) : k == K"Float" ? convert(Float64, value) : @@ -176,8 +177,9 @@ function makeleaf(ctx, srcref, k::Kind, value; kws...) k == K"Value" ? value : k == K"Bool" ? value : error("Unexpected leaf kind `$k`") - makeleaf(graph, srcref, k; value=val, kws...) + setattr!(leaf._graph, leaf._id, :value, val) end + leaf end # TODO: Replace this with makeleaf variant? @@ -191,7 +193,7 @@ end # Convenience functions to create leaf nodes referring to identifiers within # the Core and Top modules. -core_ref(ctx, ex, name) = makeleaf(ctx, ex, K"core", name) +core_ref(ctx, ex, name) = newleaf(ctx, ex, K"core", name) svec_type(ctx, ex) = core_ref(ctx, ex, "svec") nothing_(ctx, ex) = core_ref(ctx, ex, "nothing") @@ -201,7 +203,7 @@ top_ref(ctx, ex, name) = makeleaf(ctx, ex, K"top", name) # Return (variable, assignment_node) function assign_tmp(ctx::AbstractLoweringContext, ex, name="tmp") var = ssavar(ctx, ex, name) - assign_var = makenode(ctx, ex, K"=", var, ex) + assign_var = makenode(ctx, ex, K"=", [var._id, ex._id]) var, assign_var end @@ -210,7 +212,7 @@ function emit_assign_tmp(stmts::SyntaxList, ctx, ex, name="tmp") return ex end var = ssavar(ctx, ex, name) - push!(stmts, makenode(ctx, ex, K"=", var, ex)) + push!(stmts, makenode(ctx, ex, K"=", [var._id, ex._id])) var end @@ -224,31 +226,38 @@ function _match_srcref(ex) end end -function _match_kind(f::Function, srcref, ex) +function _kw_to_pair(ex) + if ex isa Expr && ex.head === :kw && ex.args[1] isa Symbol + (QuoteNode(ex.args[1]), esc(ex.args[2])) + elseif ex isa Symbol + (QuoteNode(ex), esc(ex)) + else + @assert false "invalid keyword form in @ast $ex" + end +end + +function _match_kind(srcref, ex) kws = [] if Meta.isexpr(ex, :call) kind = esc(ex.args[1]) args = ex.args[2:end] if Meta.isexpr(args[1], :parameters) - kws = map(esc, args[1].args) + kws = map(_kw_to_pair, args[1].args) popfirst!(args) end while length(args) >= 1 && Meta.isexpr(args[end], :kw) - pushfirst!(kws, esc(pop!(args))) + pushfirst!(kws, _kw_to_pair(pop!(args))) end if length(args) == 1 srcref_tmp = gensym("srcref") - return quote - $srcref_tmp = $(_match_srcref(args[1])) - $(f(kind, srcref_tmp, kws)) - end + return (kind, _match_srcref(args[1]), kws) elseif length(args) > 1 error("Unexpected: extra srcref argument in `$ex`?") end else kind = esc(ex) end - f(kind, srcref, kws) + return (kind, srcref, kws) end function _expand_ast_tree(ctx, srcref, tree) @@ -261,8 +270,12 @@ function _expand_ast_tree(ctx, srcref, tree) val = nothing kindspec = tree.args[1] end - _match_kind(srcref, kindspec) do kind, srcref, kws - :(makeleaf($ctx, $srcref, $kind, $(val), $(kws...))) + let (kind, srcref, kws) = _match_kind(srcref, kindspec) + n = :(newleaf($ctx, $srcref, $kind, $val)) + for (attr, val) in kws + n = :(setattr!($n, $attr, $val)) + end + n end elseif Meta.isexpr(tree, :call) && tree.args[1] === :(=>) # Leaf node with copied attributes @@ -291,8 +304,12 @@ function _expand_ast_tree(ctx, srcref, tree) end end push!(child_stmts, :(child_ids)) - _match_kind(srcref, flatargs[1]) do kind, srcref, kws - :(_makenode($ctx, $srcref, $kind, $children_ex; $(kws...))) + let (kind, srcref, kws) = _match_kind(srcref, flatargs[1]) + n = :(makenode($ctx, $srcref, $kind, $children_ex)) + for (attr, val) in kws + n = :(setattr!($n, $attr, $val)) + end + n end elseif Meta.isexpr(tree, :(:=)) lhs = tree.args[1] @@ -388,17 +405,17 @@ end function copy_attrs!(dest, head::Union{Kind,JuliaSyntax.SyntaxHead}, all=false) if all - sethead!(dest._graph, dest._id, head) + setattr!(dest._graph, dest._id, :kind, kind(head)) + !(head isa Kind) && setattr!(dest._graph, dest._id, :syntax_flags, flags(head)) end end -function mapchildren(f::Function, ctx, ex::SyntaxTree, do_map_child::Function; - extra_attrs...) +function mapchildren(f::Function, ctx, ex::SyntaxTree, do_map_child::Function) if is_leaf(ex) return ex end orig_children = children(ex) - cs = isempty(extra_attrs) ? nothing : SyntaxList(ctx) + cs = nothing for (i,e) in enumerate(orig_children) newchild = do_map_child(i) ? f(e) : e if isnothing(cs) @@ -417,14 +434,12 @@ function mapchildren(f::Function, ctx, ex::SyntaxTree, do_map_child::Function; return ex end cs::SyntaxList - ex2 = makenode(ctx, ex, head(ex), cs) - copy_attrs!(ex2, ex) - setattr!(ex2; extra_attrs...) + ex2 = makenode(ctx, ex, ex, cs) return ex2 end -function mapchildren(f::Function, ctx, ex::SyntaxTree, mapped_children::AbstractVector{<:Integer}; - extra_attrs...) +function mapchildren(f::Function, ctx, ex::SyntaxTree, + mapped_children::AbstractVector{<:Integer}) j = Ref(firstindex(mapped_children)) function do_map_child(i) ind = j[] @@ -435,11 +450,11 @@ function mapchildren(f::Function, ctx, ex::SyntaxTree, mapped_children::Abstract false end end - mapchildren(f, ctx, ex, do_map_child; extra_attrs...) + mapchildren(f, ctx, ex, do_map_child) end -function mapchildren(f::Function, ctx, ex::SyntaxTree; extra_attrs...) - mapchildren(f, ctx, ex, i->true; extra_attrs...) +function mapchildren(f::Function, ctx, ex::SyntaxTree) + mapchildren(f, ctx, ex, i->true) end @@ -476,7 +491,7 @@ function _copy_ast(graph2::SyntaxGraph, graph1::SyntaxGraph, src1 end copy_attrs!(SyntaxTree(graph2, id2), SyntaxTree(graph1, id1), true) - setattr!(graph2, id2; source=src2) + setattr!(graph2, id2, :source, src2) if !is_leaf(graph1, id1) cs = NodeId[] for cid in children(graph1, id1) @@ -490,19 +505,16 @@ end #------------------------------------------------------------------------------- function set_scope_layer(ctx, ex, layer_id, force) k = kind(ex) - scope_layer = force ? layer_id : get(ex, :scope_layer, layer_id) + attrs = [:scope_layer=>(force ? layer_id : get(ex, :scope_layer, layer_id))] if k == K"module" || k == K"toplevel" || k == K"inert" - makenode(ctx, ex, ex, children(ex); - scope_layer=scope_layer) + makenode(ctx, ex, ex, children(ex), attrs) elseif k == K"." - makenode(ctx, ex, ex, set_scope_layer(ctx, ex[1], layer_id, force), ex[2], - scope_layer=scope_layer) + children = [set_scope_layer(ctx, ex[1], layer_id, force), ex[2]] + makenode(ctx, ex, ex, children, attrs) elseif !is_leaf(ex) - mapchildren(e->set_scope_layer(ctx, e, layer_id, force), ctx, ex; - scope_layer=scope_layer) + mapchildren(e->set_scope_layer(ctx, e, layer_id, force), ctx, ex, attrs) else - makeleaf(ctx, ex, ex; - scope_layer=scope_layer) + makeleaf(ctx, ex, ex, attrs) end end @@ -538,19 +550,17 @@ end # the middle of a pass. const CompileHints = Base.ImmutableDict{Symbol,Any} -function setmeta!(ex::SyntaxTree; kws...) - @assert length(kws) == 1 # todo relax later ? - key = first(keys(kws)) - value = first(values(kws)) +function setmeta!(ex::SyntaxTree, key::Symbol, @nospecialize(val)) meta = begin m = get(ex, :meta, nothing) - isnothing(m) ? CompileHints(key, value) : CompileHints(m, key, value) + isnothing(m) ? CompileHints(key, val) : CompileHints(m, key, val) end - setattr!(ex; meta=meta) + setattr!(ex, :meta, meta) ex end -setmeta(ex::SyntaxTree; kws...) = setmeta!(copy_node(ex); kws...) +setmeta(ex::SyntaxTree, k::Symbol, @nospecialize(v)) = + setmeta!(copy_node(ex), k, v) function getmeta(ex::SyntaxTree, name::Symbol, default) meta = get(ex, :meta, nothing) diff --git a/JuliaLowering/src/bindings.jl b/JuliaLowering/src/bindings.jl index 286e67ecbeb14..8e9ec499bb96b 100644 --- a/JuliaLowering/src/bindings.jl +++ b/JuliaLowering/src/bindings.jl @@ -151,14 +151,14 @@ end # Create a new SSA binding function ssavar(ctx::AbstractLoweringContext, srcref, name="tmp") - nameref = makeleaf(ctx, srcref, K"Identifier", name_val=name) + nameref = makeleaf(ctx, srcref, K"Identifier", [:name_val=>name]) new_binding(ctx, nameref, name, :local; is_ssa=true, is_internal=true) end # Create a new local mutable binding or lambda argument function new_local_binding(ctx::AbstractLoweringContext, srcref, name; kind=:local, kws...) @assert kind === :local || kind === :argument - nameref = makeleaf(ctx, srcref, K"Identifier", name_val=name) + nameref = makeleaf(ctx, srcref, K"Identifier", [:name_val=>name]) ex = new_binding(ctx, nameref, name, kind; is_internal=true, kws...) lbindings = current_lambda_bindings(ctx) if !isnothing(lbindings) @@ -168,7 +168,7 @@ function new_local_binding(ctx::AbstractLoweringContext, srcref, name; kind=:loc end function new_global_binding(ctx::AbstractLoweringContext, srcref, name, mod; kws...) - nameref = makeleaf(ctx, srcref, K"Identifier", name_val=name) + nameref = makeleaf(ctx, srcref, K"Identifier", [:name_val=>name]) new_binding(ctx, nameref, name, :global; is_internal=true, mod=mod, kws...) end diff --git a/JuliaLowering/src/closure_conversion.jl b/JuliaLowering/src/closure_conversion.jl index 1dc4ca2bc8d9d..1cf199066a370 100644 --- a/JuliaLowering/src/closure_conversion.jl +++ b/JuliaLowering/src/closure_conversion.jl @@ -593,7 +593,7 @@ function closure_convert_lambda(ctx, ex) push!(lambda_children, _convert_closures(ctx2, ex[4])) end - lam = makenode(ctx, ex, ex, lambda_children; lambda_bindings=lambda_bindings) + lam = makenode(ctx, ex, ex, lambda_children, [:lambda_bindings=>lambda_bindings]) if !isnothing(interpolations) && !isempty(interpolations) @ast ctx ex [K"call" replace_captured_locals!::K"Value" diff --git a/JuliaLowering/src/compat.jl b/JuliaLowering/src/compat.jl index 133fb55151bcb..cd7708d31fcbe 100644 --- a/JuliaLowering/src/compat.jl +++ b/JuliaLowering/src/compat.jl @@ -1,11 +1,14 @@ const JS = JuliaSyntax function _insert_tree_node(graph::SyntaxGraph, k::Kind, src::SourceAttrType, - flags::UInt16=0x0000; attrs...) + attrs=[], flags::UInt16=0x0000) id = newnode!(graph) - sethead!(graph, id, k) - flags !== 0 && setflags!(graph, id, flags) - setattr!(graph, id; source=src, attrs...) + setattr!(graph, id, :kind, k) + flags !== 0 && setattr!(graph, id, :syntax_flags, flags) + setattr!(graph, id, :source, src) + for (k,v) in attrs + setattr!(graph, id, k, v) + end return id end @@ -187,14 +190,14 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA #--------------------------------------------------------------------------- # Non-expr types if isnothing(e) - st_id = _insert_tree_node(graph, K"core", src; name_val="nothing") + st_id = _insert_tree_node(graph, K"core", src, [:name_val=>"nothing"]) return st_id, src elseif e isa LineNumberNode # A LineNumberNode in value position evaluates to nothing - st_id = _insert_tree_node(graph, K"core", src; name_val="nothing") + st_id = _insert_tree_node(graph, K"core", src, [:name_val=>"nothing"]) return st_id, e elseif e isa Symbol - st_id = _insert_tree_node(graph, K"Identifier", src; name_val=String(e)) + st_id = _insert_tree_node(graph, K"Identifier", src, [:name_val=>String(e)]) return st_id, src elseif e isa QuoteNode if e.value isa Symbol @@ -202,13 +205,13 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA elseif e.value isa Expr return _insert_convert_expr(Expr(:inert, e.value), graph, src) elseif e.value isa LineNumberNode - return _insert_tree_node(graph, K"Value", src; value=e.value), src + return _insert_tree_node(graph, K"Value", src, [:value=>e.value]), src else return _insert_convert_expr(e.value, graph, src) end elseif e isa String st_id = _insert_tree_node(graph, K"string", src) - id_inner = _insert_tree_node(graph, K"String", src; value=e) + id_inner = _insert_tree_node(graph, K"String", src, [:value=>e]) setchildren!(graph, st_id, [id_inner]) return st_id, src elseif !(e isa Expr) @@ -217,7 +220,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA st_k = e isa Bool ? K"Bool" : e isa Integer ? K"Integer" : find_kind(string(typeof(e))) - st_id = _insert_tree_node(graph, isnothing(st_k) ? K"Value" : st_k, src; value=e) + st_id = _insert_tree_node(graph, isnothing(st_k) ? K"Value" : st_k, src, [:value=>e]) return st_id, src end @@ -498,7 +501,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA @assert e.args[1] isa Symbol @assert e.args[2] isa LayerId st_id, src = _insert_convert_expr(e.args[1], graph, src) - setattr!(graph, st_id, scope_layer=e.args[2]) + setattr!(graph, st_id, :scope_layer, e.args[2]) return st_id, src elseif e.head === :symbolicgoto || e.head === :symboliclabel @assert nargs === 1 @@ -570,7 +573,7 @@ function _insert_convert_expr(@nospecialize(e), graph::SyntaxGraph, src::SourceA return nothing, src end - st_id = _insert_tree_node(graph, st_k, src, st_flags; st_attrs...) + st_id = _insert_tree_node(graph, st_k, src, collect(st_attrs), st_flags) # child_exprs === nothing means we want a leaf. Note that setchildren! with # an empty list makes a node non-leaf. diff --git a/JuliaLowering/src/desugaring.jl b/JuliaLowering/src/desugaring.jl index 6331271478abe..ffb520b99b064 100644 --- a/JuliaLowering/src/desugaring.jl +++ b/JuliaLowering/src/desugaring.jl @@ -2163,9 +2163,9 @@ function make_lhs_decls(ctx, stmts, declkind, declmeta, ex, type_decls=true) # other Exprs that cannot be produced by the parser (tested by # test/precompile.jl #50538). if !isnothing(declmeta) - push!(stmts, makenode(ctx, ex, declkind, ex; meta=declmeta)) + push!(stmts, makenode(ctx, ex, declkind, [ex._id], [:meta=>declmeta])) else - push!(stmts, makenode(ctx, ex, declkind, ex)) + push!(stmts, makenode(ctx, ex, declkind, [ex._id])) end elseif k == K"Placeholder" nothing @@ -2174,7 +2174,7 @@ function make_lhs_decls(ctx, stmts, declkind, declmeta, ex, type_decls=true) @chk numchildren(ex) == 2 name = ex[1] if kind(name) == K"Identifier" - push!(stmts, makenode(ctx, ex, K"decl", name, ex[2])) + push!(stmts, makenode(ctx, ex, K"decl", [name._id, ex[2]._id])) else # TODO: Currently, this ignores the LHS in `_::T = val`. # We should probably do one of the following: @@ -2513,7 +2513,7 @@ function expand_function_generator(ctx, srcref, callex_srcref, func_name, func_n # Apply nospecialize to all arguments to prevent so much codegen and add # Core.Any type for them for i in first_trailing_arg:length(gen_arg_names) - gen_arg_names[i] = setmeta(gen_arg_names[i]; nospecialize=true) + gen_arg_names[i] = setmeta(gen_arg_names[i], :nospecialize, true) push!(gen_arg_types, @ast ctx gen_arg_names[i] "Any"::K"core") end # Code generator definition diff --git a/JuliaLowering/src/eval.jl b/JuliaLowering/src/eval.jl index cef07133b2f5e..d7096e8de5d6d 100644 --- a/JuliaLowering/src/eval.jl +++ b/JuliaLowering/src/eval.jl @@ -566,3 +566,5 @@ function include_string(mod::Module, code::AbstractString, filename::AbstractStr expr_compat_mode=false) eval(mod, parseall(SyntaxTree, code; filename=filename); expr_compat_mode) end + +include(path::AbstractString) = include(JuliaLowering, path) diff --git a/JuliaLowering/src/linear_ir.jl b/JuliaLowering/src/linear_ir.jl index 974c51902caf5..a2448cb297107 100644 --- a/JuliaLowering/src/linear_ir.jl +++ b/JuliaLowering/src/linear_ir.jl @@ -173,10 +173,6 @@ function emit(ctx::LinearIRContext, ex) return ex end -function emit(ctx::LinearIRContext, srcref, k, args...) - emit(ctx, makenode(ctx, srcref, k, args...)) -end - # Emit computation of ex, assigning the result to an ssavar and returning that function emit_assign_tmp(ctx::LinearIRContext, ex, name="tmp") tmp = ssavar(ctx, ex, name) @@ -328,7 +324,7 @@ function emit_simple_assignment(ctx, srcref, lhs, rhs, op=K"=") rhs ]) else - emit(ctx, srcref, op, lhs, rhs) + emit(ctx, @ast ctx srcref [op lhs rhs]) end end @@ -351,7 +347,7 @@ end function make_label(ctx, srcref) id = ctx.next_label_id[] ctx.next_label_id[] += 1 - makeleaf(ctx, srcref, K"label", id=id) + makeleaf(ctx, srcref, K"label", [:id=>id]) end # flisp: make&mark-label @@ -773,7 +769,7 @@ function compile(ctx::LinearIRContext, ex, needs_value, in_tail_pos) else lam = emit_assign_tmp(ctx, compile(ctx, lam, true, false)) end - emit(ctx, ex, K"method", fname, sig, lam) + emit(ctx, @ast ctx ex [K"method" fname sig lam]) @assert !needs_value && !in_tail_pos nothing end @@ -970,7 +966,7 @@ function _renumber(ctx, ssa_rewrites, slot_rewrites, label_table, ex) if k == K"BindingId" id = ex.var_id if haskey(ssa_rewrites, id) - makeleaf(ctx, ex, K"SSAValue"; var_id=ssa_rewrites[id]) + makeleaf(ctx, ex, K"SSAValue", [:var_id=>ssa_rewrites[id]]) else new_id = get(slot_rewrites, id, nothing) binfo = lookup_binding(ctx, id) @@ -978,12 +974,13 @@ function _renumber(ctx, ssa_rewrites, slot_rewrites, label_table, ex) sk = binfo.kind == :local || binfo.kind == :argument ? K"slot" : binfo.kind == :static_parameter ? K"static_parameter" : throw(LoweringError(ex, "Found unexpected binding of kind $(binfo.kind)")) - makeleaf(ctx, ex, sk; var_id=new_id) + makeleaf(ctx, ex, sk, [:var_id=>new_id]) else if binfo.kind !== :global throw(LoweringError(ex, "Found unexpected binding of kind $(binfo.kind)")) end - makeleaf(ctx, ex, K"globalref", binfo.name, mod=binfo.mod) + makeleaf(ctx, ex, K"globalref", + [:name_val=>binfo.name, :mod=>binfo.mod]) end end elseif k == K"meta" || k == K"static_eval" diff --git a/JuliaLowering/src/macro_expansion.jl b/JuliaLowering/src/macro_expansion.jl index 097625ce7f2d6..0d43c77178baf 100644 --- a/JuliaLowering/src/macro_expansion.jl +++ b/JuliaLowering/src/macro_expansion.jl @@ -143,7 +143,8 @@ function fixup_macro_name(ctx::MacroExpansionContext, ex::SyntaxTree) if k == K"StrMacroName" || k == K"CmdMacroName" layerid = get(ex, :scope_layer, current_layer_id(ctx)) newname = JuliaSyntax.lower_identifier_name(ex.name_val, k) - makeleaf(ctx, ex, ex, kind=K"Identifier", scope_layer=layerid, name_val=newname) + makeleaf(ctx, ex, ex, [:kind=>K"Identifier", :scope_layer=>layerid, + :name_val=>newname]) elseif k == K"macro_name" @chk numchildren(ex) === 1 if kind(ex[1]) === K"." @@ -151,7 +152,7 @@ function fixup_macro_name(ctx::MacroExpansionContext, ex::SyntaxTree) else layerid = get(ex, :scope_layer, current_layer_id(ctx)) newname = JuliaSyntax.lower_identifier_name(ex[1].name_val, K"macro_name") - makeleaf(ctx, ex[1], ex[1], kind=kind(ex[1]), name_val=newname) + makeleaf(ctx, ex[1], ex[1], [:kind=>kind(ex[1]), :name_val=>newname]) end else mapchildren(e->fixup_macro_name(ctx,e), ctx, ex) @@ -191,7 +192,7 @@ function set_macro_arg_hygiene(ctx, ex, layer_ids, layer_idx) k = kind(ex) scope_layer = get(ex, :scope_layer, layer_ids[layer_idx]) if is_leaf(ex) - makeleaf(ctx, ex, ex; scope_layer=scope_layer) + makeleaf(ctx, ex, ex, [:scope_layer=>scope_layer]) else inner_layer_idx = layer_idx if k == K"escape" @@ -205,8 +206,9 @@ function set_macro_arg_hygiene(ctx, ex, layer_ids, layer_idx) throw(MacroExpansionError(ex, "`escape` node in outer context")) end end - mapchildren(e->set_macro_arg_hygiene(ctx, e, layer_ids, inner_layer_idx), - ctx, ex; scope_layer=scope_layer) + node = mapchildren(e->set_macro_arg_hygiene( + ctx, e, layer_ids, inner_layer_idx), ctx, ex) + setattr!(node, :scope_layer, scope_layer) end end @@ -349,10 +351,10 @@ function append_sourceref(ctx, ex, secondary_prov) srcref = (ex, secondary_prov) if !is_leaf(ex) if kind(ex) == K"macrocall" - makenode(ctx, srcref, ex, children(ex)...) + makenode(ctx, srcref, ex, children(ex)) else - makenode(ctx, srcref, ex, - map(e->append_sourceref(ctx, e, secondary_prov), children(ex))...) + cs = map(e->append_sourceref(ctx, e, secondary_prov)._id, children(ex)) + makenode(ctx, srcref, ex, cs) end else makeleaf(ctx, srcref, ex) @@ -398,7 +400,7 @@ function expand_forms_1(ctx::MacroExpansionContext, ex::SyntaxTree) else k = all(==('_'), name_str) ? K"Placeholder" : K"Identifier" scope_layer = get(ex, :scope_layer, current_layer_id(ctx)) - makeleaf(ctx, ex, ex; kind=k, scope_layer) + makeleaf(ctx, ex, ex, [:kind=>k, :scope_layer=>scope_layer]) end elseif k == K"StrMacroName" || k == K"CmdMacroName" || k == K"macro_name" # These can appear outside of a macrocall, e.g. in `import` @@ -535,7 +537,8 @@ function expand_forms_1(ctx::MacroExpansionContext, ex::SyntaxTree) # TODO: Should every form get layerid systematically? Or only the ones # which expand_forms_2 needs? layerid = get(ex, :scope_layer, current_layer_id(ctx)) - mapchildren(e->expand_forms_1(ctx,e), ctx, ex; scope_layer=layerid) + setattr(mapchildren(e->expand_forms_1(ctx,e), ctx, ex), + :scope_layer, layerid) else mapchildren(e->expand_forms_1(ctx,e), ctx, ex) end diff --git a/JuliaLowering/src/runtime.jl b/JuliaLowering/src/runtime.jl index 12000100025bd..c712bd6f20fb6 100644 --- a/JuliaLowering/src/runtime.jl +++ b/JuliaLowering/src/runtime.jl @@ -63,9 +63,9 @@ function _interpolated_value(ctx::InterpolationContext, srcref, ex) # Plain symbols become identifiers. This is an accommodation for # compatibility to allow `:x` (a Symbol) and `:(x)` (a SyntaxTree) to # be used interchangeably in macros. - makeleaf(ctx, srcref, K"Identifier", string(ex)) + newleaf(ctx, srcref, K"Identifier", string(ex)) else - makeleaf(ctx, srcref, K"Value", ex) + newleaf(ctx, srcref, K"Value", ex) end end diff --git a/JuliaLowering/src/syntax_graph.jl b/JuliaLowering/src/syntax_graph.jl index c8145aa1b93c3..85af7a9bccc9c 100644 --- a/JuliaLowering/src/syntax_graph.jl +++ b/JuliaLowering/src/syntax_graph.jl @@ -99,11 +99,8 @@ function newnode!(graph::SyntaxGraph) return length(graph.edge_ranges) end -function setchildren!(graph::SyntaxGraph, id, children::NodeId...) - setchildren!(graph, id, children) -end - -function setchildren!(graph::SyntaxGraph, id, children) +function setchildren!(graph::SyntaxGraph, id::NodeId, + children::AbstractVector{NodeId}) n = length(graph.edges) graph.edge_ranges[id] = n+1:(n+length(children)) # TODO: Reuse existing edges if possible @@ -147,12 +144,11 @@ function hasattr(graph::SyntaxGraph, name::Symbol) end # TODO: Probably terribly non-inferable? -function setattr!(graph::SyntaxGraph, id; attrs...) - for (k,v) in pairs(attrs) - if !isnothing(v) - getattr(graph, k)[id] = v - end +function setattr!(graph::SyntaxGraph, id, k::Symbol, @nospecialize(v)) + if !isnothing(v) + getattr(graph, k)[id] = v end + nothing end function deleteattr!(graph::SyntaxGraph, id::NodeId, name::Symbol) @@ -167,32 +163,20 @@ function Base.getproperty(graph::SyntaxGraph, name::Symbol) return getattr(graph, name) end -function sethead!(graph, id::NodeId, h::JuliaSyntax.SyntaxHead) - sethead!(graph, id, kind(h)) - setflags!(graph, id, flags(h)) -end - -function sethead!(graph, id::NodeId, k::Kind) - graph.kind[id] = k -end - -function setflags!(graph, id::NodeId, f::UInt16) - graph.syntax_flags[id] = f -end - function _convert_nodes(graph::SyntaxGraph, node::SyntaxNode) id = newnode!(graph) - sethead!(graph, id, head(node)) + setattr!(graph, id, :kind, kind(node)) + setattr!(graph, id, :syntax_flags, flags(node)) if !isnothing(node.val) v = node.val if v isa Symbol # TODO: Fixes in JuliaSyntax to avoid ever converting to Symbol - setattr!(graph, id, name_val=string(v)) + setattr!(graph, id, :name_val, string(v)) else - setattr!(graph, id, value=v) + setattr!(graph, id, :value, v) end end - setattr!(graph, id, source=SourceRef(node.source, node.position, node.raw)) + setattr!(graph, id, :source, SourceRef(node.source, node.position, node.raw)) if !is_leaf(node) cs = map(children(node)) do n _convert_nodes(graph, n) @@ -201,7 +185,7 @@ function _convert_nodes(graph::SyntaxGraph, node::SyntaxNode) end return id end - +# x """ syntax_graph(ctx) @@ -242,8 +226,9 @@ function Base.getproperty(ex::SyntaxTree, name::Symbol) end end -function Base.setproperty!(ex::SyntaxTree, name::Symbol, val) - return setattr!(ex._graph, ex._id; name=>val) +function Base.setproperty!(ex::SyntaxTree, name::Symbol, @nospecialize(val)) + setattr!(ex._graph, ex._id, name, val) + val end function Base.propertynames(ex::SyntaxTree) @@ -281,22 +266,19 @@ function copy_node(ex::SyntaxTree) graph = syntax_graph(ex) id = newnode!(graph) if !is_leaf(ex) - setchildren!(graph, id, _node_ids(graph, children(ex)...)) + setchildren!(graph, id, children(ex._graph, ex._id)) end ex2 = SyntaxTree(graph, id) copy_attrs!(ex2, ex, true) ex2 end -function setattr(ex::SyntaxTree; extra_attrs...) - ex2 = copy_node(ex) - setattr!(ex2; extra_attrs...) - ex2 -end - -function setattr!(ex::SyntaxTree; attrs...) - setattr!(ex._graph, ex._id; attrs...) +function setattr!(ex::SyntaxTree, name::Symbol, @nospecialize(val)) + setattr!(ex._graph, ex._id, name, val) + ex end +setattr(ex::SyntaxTree, name::Symbol, @nospecialize(val)) = + setattr!(copy_node(ex), name, val) function deleteattr!(ex::SyntaxTree, name::Symbol) deleteattr!(ex._graph, ex._id, name) @@ -725,9 +707,14 @@ end SyntaxList(graph::SyntaxGraph) = SyntaxList(graph, Vector{NodeId}()) SyntaxList(ctx) = SyntaxList(syntax_graph(ctx)) +SyntaxList(ctx, v::Vector{SyntaxTree}) = + SyntaxList(syntax_graph(ctx), NodeId[x._id for x in v]) syntax_graph(lst::SyntaxList) = lst.graph +setchildren!(graph::SyntaxGraph, id::NodeId, children::SyntaxList) = + setchildren!(graph, id, children.ids) + Base.size(v::SyntaxList) = size(v.ids) Base.IndexStyle(::Type{<:SyntaxList}) = IndexLinear() diff --git a/JuliaLowering/src/syntax_macros.jl b/JuliaLowering/src/syntax_macros.jl index 0621c528191ef..fa62b26c60372 100644 --- a/JuliaLowering/src/syntax_macros.jl +++ b/JuliaLowering/src/syntax_macros.jl @@ -18,7 +18,7 @@ function _apply_nospecialize(ctx, ex) k = kind(ex) if k == K"Identifier" || k == K"Placeholder" || k == K"tuple" - setmeta(ex; nospecialize=true) + setmeta(ex, :nospecialize, true) elseif k == K"..." || k == K"::" || k == K"=" if k == K"::" && numchildren(ex) == 1 ex = @ast ctx ex [K"::" "_"::K"Placeholder" ex[1]] diff --git a/JuliaLowering/test/compat.jl b/JuliaLowering/test/compat.jl index a7fce558e9f40..c41213ba6af4c 100644 --- a/JuliaLowering/test/compat.jl +++ b/JuliaLowering/test/compat.jl @@ -95,7 +95,7 @@ const JL = JuliaLowering end pre_st_flags = (JS.flags(st) & ~JS.INFIX_FLAG) | JS.PREFIX_CALL_FLAG JL.setchildren!(st._graph, st._id, pre_st_args) - JL.setflags!(st._graph, st._id, pre_st_flags) + JL.setattr!(st._graph, st._id, :syntax_flags, pre_st_flags) elseif JS.is_postfix_op_call(st) && (k === K"call" || k === K"dotcall") pre_st_args = JL.NodeId[st[end]._id] for c in st[1:end-1] @@ -103,23 +103,23 @@ const JL = JuliaLowering end pre_st_flags = (JS.flags(st) & ~JS.POSTFIX_OP_FLAG) | JS.PREFIX_CALL_FLAG JL.setchildren!(st._graph, st._id, pre_st_args) - JL.setflags!(st._graph, st._id, pre_st_flags) + JL.setattr!(st._graph, st._id, :syntax_flags, pre_st_flags) elseif k in JS.KSet"tuple block macrocall" - JL.setflags!(st._graph, st._id, JS.flags(st) & ~JS.PARENS_FLAG) + JL.setattr!(st._graph, st._id, :syntax_flags, JS.flags(st) & ~JS.PARENS_FLAG) elseif k === K"toplevel" - JL.setflags!(st._graph, st._id, JS.flags(st) & ~JS.TOPLEVEL_SEMICOLONS_FLAG) + JL.setattr!(st._graph, st._id, :syntax_flags, JS.flags(st) & ~JS.TOPLEVEL_SEMICOLONS_FLAG) end if k in JS.KSet"tuple call dotcall macrocall vect curly braces <: >:" - JL.setflags!(st._graph, st._id, JS.flags(st) & ~JS.TRAILING_COMMA_FLAG) + JL.setattr!(st._graph, st._id, :syntax_flags, JS.flags(st) & ~JS.TRAILING_COMMA_FLAG) end - k === K"quote" && JL.setflags!(st._graph, st._id, JS.flags(st) & ~JS.COLON_QUOTE) - k === K"wrapper" && JL.sethead!(st._graph, st._id, K"block") + k === K"quote" && JL.setattr!(st._graph, st._id, :syntax_flags, JS.flags(st) & ~JS.COLON_QUOTE) + k === K"wrapper" && JL.setattr!(st._graph, st._id, :kind, K"block") # All ops are prefix ops in an expr. # Ignore trivia (shows up on some K"error"s) - JL.setflags!(st._graph, st._id, JS.flags(st) & + JL.setattr!(st._graph, st._id, :syntax_flags, JS.flags(st) & ~JS.PREFIX_OP_FLAG & ~JS.INFIX_FLAG & ~JS.TRIVIA_FLAG & ~JS.NON_TERMINAL_FLAG) for c in JS.children(st) diff --git a/JuliaLowering/test/scopes.jl b/JuliaLowering/test/scopes.jl index e327343eb03e6..d781ff66ad3d6 100644 --- a/JuliaLowering/test/scopes.jl +++ b/JuliaLowering/test/scopes.jl @@ -62,7 +62,7 @@ end function wrapscope(ex, scope_type) g = JuliaLowering.ensure_attributes(ex._graph, scope_type=Symbol) ex = JuliaLowering.reparent(g, ex) - makenode(ex, ex, K"scope_block", ex; scope_type=scope_type) + makenode(g, ex, K"scope_block", [ex._id], [:scope_type=>scope_type]) end assign_z_2 = parsestmt(SyntaxTree, "begin z = 2 end", filename="foo.jl") diff --git a/JuliaLowering/test/utils.jl b/JuliaLowering/test/utils.jl index 16f2f30294ffe..e82e524e13342 100644 --- a/JuliaLowering/test/utils.jl +++ b/JuliaLowering/test/utils.jl @@ -17,7 +17,7 @@ using .JuliaSyntax: sourcetext, set_numeric_flags using .JuliaLowering: SyntaxGraph, newnode!, ensure_attributes!, Kind, SourceRef, SyntaxTree, NodeId, - makenode, makeleaf, setattr!, sethead!, + makenode, makeleaf, setattr!, is_leaf, numchildren, children, @ast, flattened_provenance, showprov, LoweringError, MacroExpansionError, syntax_graph, Bindings, ScopeLayer, mapchildren @@ -33,8 +33,8 @@ end function _source_node(graph, src) id = newnode!(graph) - sethead!(graph, id, K"None") - setattr!(graph, id, source=src) + setattr!(graph, id, :kind, K"None") + setattr!(graph, id, :source, src) SyntaxTree(graph, id) end