@@ -176,34 +176,56 @@ function get_poison(n::AbstractNode)
176176 return n
177177end
178178
179+ @inline function get_children (node:: AbstractNode )
180+ return getfield (node, :children )
181+ end
182+ @inline function get_children (node:: AbstractNode , :: Val{n} ) where {n}
183+ cs = get_children (node)
184+ return ntuple (i -> cs[i], Val (Int (n)))
185+ end
186+ @inline function get_child (n:: AbstractNode{D} , i:: Int ) where {D}
187+ return get_children (n)[i]
188+ end
189+ @inline function set_child! (n:: AbstractNode{D} , child:: AbstractNode{D} , i:: Int ) where {D}
190+ set_children! (n, Base. setindex (get_children (n), child, i))
191+ return child
192+ end
193+ @inline function set_children! (n:: AbstractNode{D} , children:: NTuple{D2,AbstractNode{D}} ) where {D,D2}
194+ if D === D2
195+ n. children = children
196+ else
197+ poison = get_poison (n)
198+ # We insert poison at the end of the tuple so that
199+ # errors will appear loudly if accessed.
200+ # This poison should be efficient to insert. So
201+ # for simplicity, we can just use poison == n, which
202+ # will trigger infinite recursion errors if accessed.
203+ n. children = ntuple (i -> i <= D2 ? children[i] : poison, Val (D))
204+ end
205+ end
206+
179207macro make_accessors (node_type)
180208 esc (quote
181209 @inline function Base. getproperty (n:: $node_type , k:: Symbol )
182210 if k == :l
183211 # TODO : Should a depwarn be raised here? Or too slow?
184- return getfield ( n, :children )[ 1 ]
212+ return $ (get_child)( n, 1 )
185213 elseif k == :r
186- return getfield ( n, :children )[ 2 ]
214+ return $ (get_child)( n, 2 )
187215 else
188216 return getfield (n, k)
189217 end
190218 end
191219 @inline function Base. setproperty! (n:: $node_type , k:: Symbol , v)
192220 if k == :l
193221 if isdefined (n, :children )
194- old = getfield (n, :children )
195- setfield! (n, :children , (v, old[2 ]))
196- v
222+ $ (set_child!)(n, v, 1 )
197223 else
198- poison = $ (get_poison)(n)
199- setfield! (n, :children , (v, poison))
224+ $ (set_children!)(n, (v,))
200225 v
201226 end
202227 elseif k == :r
203- # TODO : Remove this assert once we know that this is safe
204- old = getfield (n, :children )
205- setfield! (n, :children , (old[1 ], v))
206- v
228+ $ (set_child!)(n, v, 2 )
207229 else
208230 T = fieldtype (typeof (n), k)
209231 if v isa T
222244@make_accessors GraphNode
223245# TODO : Disable the `.l` accessors eventually, once the codebase is fully generic
224246
225- @inline children (node:: AbstractNode ) = node. children
226- @inline function children (node:: AbstractNode , :: Val{n} ) where {n}
227- cs = children (node)
228- return ntuple (i -> cs[i], Val (Int (n)))
229- end
230-
231247# ###############################################################################
232248# ! format: on
233249
@@ -273,11 +289,11 @@ include("base.jl")
273289@inline function (:: Type{N} )(
274290 :: Type{T1} = Undefined; val= nothing , feature= nothing , op= nothing , l= nothing , r= nothing , children= nothing , allocator:: F = default_allocator,
275291) where {T1,N<: AbstractExpressionNode{T} where T,F}
276- _children = if l != = nothing && r === nothing
277- @assert children === nothing
292+ _children = if ! isnothing (l) && isnothing (r)
293+ @assert isnothing ( children)
278294 (l,)
279- elseif l != = nothing && r != = nothing
280- @assert children === nothing
295+ elseif ! isnothing (l) && ! isnothing (r)
296+ @assert isnothing ( children)
281297 (l, r)
282298 else
283299 children
328344 n = allocator (N, T)
329345 n. degree = D2
330346 n. op = op
331- poison = get_poison (n)
332- n. children = ntuple (i -> i <= D2 ? convert (NT, children[i]) : poison, Val (max_degree (N)))
347+ set_children! (n, children)
333348 return n
334349end
335350
@@ -398,7 +413,7 @@ function set_node!(tree::AbstractExpressionNode, new_tree::AbstractExpressionNod
398413 end
399414 else
400415 tree. op = new_tree. op
401- tree. children = new_tree. children
416+ set_children! ( tree, get_children ( new_tree))
402417 end
403418 return nothing
404419end
0 commit comments