From cb64de892cc1000236e0782f22ed0958b368e158 Mon Sep 17 00:00:00 2001 From: Hugo Levy-Falk Date: Tue, 19 Nov 2024 22:59:19 +0100 Subject: [PATCH] feat(examples): Add an example using the Julia type system. Building over #32, this provides an example implementation for a tree based on the Julia type system. --- Project.toml | 4 +++- docs/src/index.md | 1 + test/examples/juliatypes.jl | 42 +++++++++++++++++++++++++++++++++++++ test/runtests.jl | 2 +- test/trees.jl | 28 +++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 test/examples/juliatypes.jl diff --git a/Project.toml b/Project.toml index 3dc9cfb..aaa265e 100644 --- a/Project.toml +++ b/Project.toml @@ -5,12 +5,14 @@ version = "0.4.5" [compat] Aqua = "0.8" +InteractiveUtils = "1" Test = "1" julia = "1" [extras] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" +InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["Aqua", "Test"] +test = ["Aqua", "Test", "InteractiveUtils"] diff --git a/docs/src/index.md b/docs/src/index.md index a0b4855..6dae9b0 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -203,3 +203,4 @@ repr_node - [`OneTree`](https://github.com/JuliaCollections/AbstractTrees.jl/blob/master/test/examples/onetree.jl) - [`FSNode`](https://github.com/JuliaCollections/AbstractTrees.jl/blob/master/test/examples/fstree.jl) - [`BinaryNode`](https://github.com/JuliaCollections/AbstractTrees.jl/blob/master/test/examples/binarytree.jl) +- [`TypeTree`](https://github.com/JuliaCollections/AbstractTrees.jl/blob/master/test/examples/juliatypes.jl) diff --git a/test/examples/juliatypes.jl b/test/examples/juliatypes.jl new file mode 100644 index 0000000..6066c01 --- /dev/null +++ b/test/examples/juliatypes.jl @@ -0,0 +1,42 @@ +using AbstractTrees + +@static if Base.VERSION ≥ v"1.5" + using InteractiveUtils: subtypes, supertype, supertypes +else + using InteractiveUtils: subtypes, supertype + function supertypes(T::Type) + S = supertype(T) + if S === T + (T,) + else + (T, supertypes(S)...) + end + end +end + +""" + TypeTree + +The first thing you might think of is using Type{T} as a node directly. However, +this will create many difficulties with components of AbstractTrees.jl that rely +on the type system (in particular `childrentype`). A simple workaround is to +use a wrapper type. +""" +struct TypeTree + t::Type +end +function AbstractTrees.children(t::TypeTree) + t.t === Function ? Vector{TypeTree}() : map(x->TypeTree(x), filter(x -> x !== Any,subtypes(t.t))) +end +AbstractTrees.printnode(io::IO,t::TypeTree) = print(io,t.t) +AbstractTrees.nodevalue(t::TypeTree) = t.t +AbstractTrees.parent(t::TypeTree) = TypeTree(supertype(t.t)) +AbstractTrees.ParentLinks(::Type{TypeTree}) = StoredParents() + +module JuliaTypesExamples +abstract type AbstractSuperType end +struct DirectDescendant <: AbstractSuperType end +abstract type AbstractFooBar <: AbstractSuperType end +struct Foo <: AbstractFooBar end +struct Bar <: AbstractFooBar end +end diff --git a/test/runtests.jl b/test/runtests.jl index 37f96c5..948acc6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -8,4 +8,4 @@ if Base.VERSION >= v"1.6" @testset "Printing" begin include("printing.jl") end end -Aqua.test_all(AbstractTrees) \ No newline at end of file +Aqua.test_all(AbstractTrees) diff --git a/test/trees.jl b/test/trees.jl index 9dc629b..a411934 100644 --- a/test/trees.jl +++ b/test/trees.jl @@ -116,3 +116,31 @@ include(joinpath(@__DIR__, "examples", "binarytree.jl")) @test nodevalue.(sbfs) == [0, 1, 2, 3] end +include(joinpath(@__DIR__, "examples", "juliatypes.jl")) + +@testset "TypeTree" begin + t = TypeTree(JuliaTypesExamples.AbstractSuperType) + + ls = collect(Leaves(t)) + @test issetequal(nodevalue.(ls), [JuliaTypesExamples.DirectDescendant, JuliaTypesExamples.Foo, JuliaTypesExamples.Bar]) + + predfs = nodevalue.(collect(PreOrderDFS(t))) + for (i,T) in enumerate(predfs) + @test !any(map(x->T <: x, predfs[i+1:end])) + end + + postdfs = nodevalue.(collect(PostOrderDFS(t))) + for (i,T) in enumerate(postdfs) + @test !any(map(x->T <: x, postdfs[1:i-1])) + end + + sbfs = nodevalue.(collect(StatelessBFS(t))) + for (i,T) in enumerate(sbfs) + parents = collect(supertypes(T)[2:end]) + for j in (i+1):length(sbfs) + later_parents = collect(supertypes(sbfs[j])[2:end]) + @test (parents ∩ later_parents) == parents + end + end +end +