Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use unsorted arguments by default #44

Merged
merged 4 commits into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "TermInterface"
uuid = "8ea1fca8-c5ef-4a55-8b96-4e9afe9c9a3c"
authors = ["Shashi Gowda <[email protected]>", "Alessandro Cheli <[email protected]>"]
version = "1.0.1"
version = "2.0"

[compat]
julia = "1"
Expand Down
47 changes: 40 additions & 7 deletions src/TermInterface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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


"""
Expand Down
25 changes: 25 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading