@@ -428,33 +428,47 @@ end
428428
429429
430430"""
431- Recursively copy AST `ex` into `ctx`. The resulting tree contains new nodes
432- only, and does not contain nodes with multiple parents.
431+ Recursively copy AST `ex` into `ctx`.
433432
434433Special provenance handling: If `copy_source` is true, treat the `.source`
435434attribute as a reference and recurse on its contents. Otherwise, treat it like
436435any other attribute.
437436"""
438- function copy_ast (ctx, ex; copy_source= true )
439- # TODO : Do we need to keep a mapping of node IDs to ensure we don't
440- # double-copy here in the case when some tree nodes are pointed to by
441- # multiple parents? (How much does this actually happen in practice?)
442- s = get (ex, :source , nothing )
443- # TODO : Figure out how to use provenance() here?
444- srcref = ! copy_source ? s :
445- s isa NodeId ? copy_ast (ctx, SyntaxTree (ex. _graph, s)) :
446- s isa Tuple ? map (i-> copy_ast (ctx, SyntaxTree (ex. _graph, i)), s) :
447- s
448- if ! is_leaf (ex)
449- cs = SyntaxList (ctx)
450- for e in children (ex)
451- push! (cs, copy_ast (ctx, e))
452- end
453- ex2 = makenode (ctx, srcref, ex, cs)
437+ function copy_ast (ctx, ex:: SyntaxTree ; copy_source= true )
438+ graph1 = syntax_graph (ex)
439+ graph2 = syntax_graph (ctx)
440+ ! copy_source && check_same_graph (graph1, graph2)
441+ id2 = _copy_ast (graph2, graph1, ex. _id, Dict {NodeId, NodeId} (), copy_source)
442+ return SyntaxTree (graph2, id2)
443+ end
444+
445+ function _copy_ast (graph2:: SyntaxGraph , graph1:: SyntaxGraph ,
446+ id1:: NodeId , seen, copy_source)
447+ let copied = get (seen, id1, nothing )
448+ isnothing (copied) || return copied
449+ end
450+ id2 = newnode! (graph2)
451+ seen[id1] = id2
452+ src1 = get (SyntaxTree (graph1, id1), :source , nothing )
453+ src2 = if ! copy_source
454+ src1
455+ elseif src1 isa NodeId
456+ _copy_ast (graph2, graph1, src1, seen, copy_source)
457+ elseif src1 isa Tuple
458+ map (i-> _copy_ast (graph2, graph1, i, seen, copy_source), src1)
454459 else
455- ex2 = makeleaf (ctx, srcref, ex)
460+ src1
456461 end
457- return ex2
462+ copy_attrs! (SyntaxTree (graph2, id2), SyntaxTree (graph1, id1), true )
463+ setattr! (graph2, id2; source= src2)
464+ if ! is_leaf (graph1, id1)
465+ cs = NodeId[]
466+ for cid in children (graph1, id1)
467+ push! (cs, _copy_ast (graph2, graph1, cid, seen, copy_source))
468+ end
469+ setchildren! (graph2, id2, cs)
470+ end
471+ return id2
458472end
459473
460474# -------------------------------------------------------------------------------
0 commit comments