diff --git a/Project.toml b/Project.toml index e27ce4d..eb4db5a 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "TermInterface" uuid = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c" authors = ["Shashi Gowda ", "Alessandro Cheli "] -version = "1.0.1" +version = "2.0" [compat] julia = "1" diff --git a/src/TermInterface.jl b/src/TermInterface.jl index ca28b68..78b22c0 100644 --- a/src/TermInterface.jl +++ b/src/TermInterface.jl @@ -51,10 +51,33 @@ export head """ children(x) Returns the children (aka tail) of the S-expression. + + +Depending on the type and internal representation of `x`, +`children(x)` may return an unsorted collection nondeterministically, +This is to make sure to retrieve the children of an AST node when the order of children does not matter, +but the speed of the operation does. +To ensure to retrieve children in a sorted manner, you can use +and implement the function `sorted_children`. """ function children end export children +""" + sorted_children(x::T) + +Returns the children of an AST node, in a **sorted fashion**. +`isexpr(x)` must be true as a precondition. Analogous to `children`, +but ensures that the operation is deterministic and always returns +the children in the order they are stored. + +By default, this redirects to `children`, therefore implementing +it is optional. +""" +sorted_children(x) = children(x) +export sorted_children + + """ operation(x) @@ -69,20 +92,30 @@ export operation Returns the arguments to the function call in a function call expression. `iscall(x)` must be true as a precondition. + +Depending on the type and internal representation of `x`, +`arguments(x)` may return an unsorted collection nondeterministically, +This is to make sure to retrieve the arguments of an expression when the order of arguments does not matter +but the speed of the operation does. +To ensure to retrieve arguments in a sorted manner, you can use +and implement the function `sorted_arguments`. """ function arguments end export arguments """ - unsorted_arguments(x::T) + sorted_arguments(x::T) -If x is a expression satisfying `iscall(x)` and your expression type `T` provides -and optimized implementation for storing the arguments, this function can -be used to retrieve the arguments when the order of arguments does not matter -but the speed of the operation does. +Returns the arguments to the function call in a function call expression, in a **sorted fashion**. +`iscall(x)` must be true as a precondition. Analogous to `arguments`, +but ensures that the operation is deterministic and always returns +the arguments in the order they are stored. + +By default, this redirects to `arguments`, therefore implementing +it is optional. """ -unsorted_arguments(x) = arguments(x) -export unsorted_arguments +sorted_arguments(x) = arguments(x) +export sorted_arguments """ diff --git a/test/runtests.jl b/test/runtests.jl index 3ddd549..ef48422 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -20,3 +20,28 @@ using Test @test !iscall(ex) @test ex == maketerm(Expr, :ref, [:arr, :i, :j], nothing) end + +@testset "Unsorted arguments" begin + struct Sum + d::Dict{Int,Any} + Sum(xs...) = new(Dict{Int,Any}(xs...)) + end + + TermInterface.isexpr(s::Sum) = true + TermInterface.head(::Sum) = (+) + TermInterface.operation(s::Sum) = head(s) + TermInterface.children(s::Sum) = [:($coeff * $val) for (coeff, val) in s.d] + TermInterface.sorted_children(s::Sum) = [:($coeff * $val) for (coeff, val) in sort!(collect(pairs(s.d)))] + TermInterface.arguments(s::Sum) = children(s) + TermInterface.sorted_arguments(s::Sum) = sorted_children(s) + + s = Sum(1 => :A, 2 => :B, 3 => :C) + @test operation(s) == head(s) == (+) + args = arguments(s) + @test :(1A) in args + @test :(2B) in args + @test :(3C) in args + + @test sorted_arguments(s) == [:(1A), :(2B), :(3C)] + @test sorted_children(s) == sorted_arguments(s) +end \ No newline at end of file