diff --git a/Project.toml b/Project.toml index 2de42ff..a414a10 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 = "0.3.3" +version = "0.4" [compat] julia = "1" diff --git a/src/TermInterface.jl b/src/TermInterface.jl index 78b57ca..8c2d0ab 100644 --- a/src/TermInterface.jl +++ b/src/TermInterface.jl @@ -1,14 +1,27 @@ +""" +This module defines a contains definitions for common functions that are useful +for symbolic expression manipulation. Its purpose is to provide a shared +interface between various symbolic programming Julia packages. + +This is currently borrowed from TermInterface.jl. If you want to use +Metatheory.jl, please use this internal interface, as we are waiting that a +redesign proposal of the interface package will reach consensus. When this +happens, this module will be moved back into a separate package. + +See https://github.com/JuliaSymbolics/TermInterface.jl/pull/22 +""" module TermInterface """ istree(x) -Returns `true` if `x` is a term. If true, `operation`, `arguments` -must also be defined for `x` appropriately. +Returns `true` if `x` is a term. If true, `operation`, `arguments` and +`is_function_call` must also be defined for `x` appropriately. """ istree(x) = false export istree + """ symtype(x) @@ -22,6 +35,7 @@ function symtype(x) end export symtype + """ issym(x) @@ -31,44 +45,30 @@ on `x` and must return a Symbol. issym(x) = false export issym -""" - exprhead(x) - -If `x` is a term as defined by `istree(x)`, `exprhead(x)` must return a symbol, -corresponding to the head of the `Expr` most similar to the term `x`. -If `x` represents a function call, for example, the `exprhead` is `:call`. -If `x` represents an indexing operation, such as `arr[i]`, then `exprhead` is `:ref`. -Note that `exprhead` is different from `operation` and both functions should -be defined correctly in order to let other packages provide code generation -and pattern matching features. -""" -function exprhead end -export exprhead - """ operation(x) -If `x` is a term as defined by `istree(x)`, `operation(x)` returns the -head of the term if `x` represents a function call, for example, the head -is the function being called. +If `x` is a term as defined by `istree(x)`, `operation(x)` returns the operation of the +term. If `x` represents a function call term like `f(a,b)`, the operation +is the function being called, `f`. """ function operation end export operation + """ arguments(x) -Get the arguments of `x`, must be defined if `istree(x)` is `true`. +Get the arguments of a term `x`, must be defined if `istree(x)` is `true`. """ function arguments end export arguments - """ unsorted_arguments(x::T) -If x is a term satisfying `istree(x)` and your term type `T` orovides +If x is a term satisfying `istree(x)` and your term 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. @@ -83,7 +83,7 @@ export unsorted_arguments Returns the number of arguments of `x`. Implicitly defined if `arguments(x)` is defined. """ -arity(x) = length(arguments(x)) +arity(x)::Int = length(arguments(x)) export arity @@ -102,29 +102,29 @@ export metadata Returns a new term which has the structure of `x` but also has the metadata `md` attached to it. """ -function metadata(x, data) - error("Setting metadata on $x is not possible") -end +function metadata(x, data) end """ - similarterm(x, head, args, symtype=nothing; metadata=nothing, exprhead=:call) + maketerm(T::Type, operation, arguments; type=Any, metadata=nothing) -Returns a term that is in the same closure of types as `typeof(x)`, -with `head` as the head and `args` as the arguments, `type` as the symtype -and `metadata` as the metadata. By default this will execute `head(args...)`. -`x` parameter can also be a `Type`. The `exprhead` keyword argument is useful -when manipulating `Expr`s. +Has to be implemented by the provider of the expression type T. +Returns a term that is in the same closure of types as `T`, +with `operation` as the operation and `arguments` as the arguments, `type` as the symtype +and `metadata` as the metadata. """ -function similarterm(x, head, args, symtype = nothing; metadata = nothing, exprhead = nothing) - head(args...) -end +function maketerm end +export maketerm + -export similarterm -include("utils.jl") +""" + node_count(t) +Count the nodes in a symbolic expression tree satisfying `istree` and `arguments`. +""" +node_count(t) = istree(t) ? reduce(+, node_count(x) for x in arguments(t), init in 0) + 1 : 1 +export node_count -include("expr.jl") end # module diff --git a/src/expr.jl b/src/expr.jl deleted file mode 100644 index 4bc6788..0000000 --- a/src/expr.jl +++ /dev/null @@ -1,26 +0,0 @@ -# This file contains default definitions for TermInterface methods on Julia -# Builtin Expr type. - -istree(x::Expr) = true -exprhead(e::Expr) = e.head - -operation(e::Expr) = expr_operation(e, Val{exprhead(e)}()) -arguments(e::Expr) = expr_arguments(e, Val{exprhead(e)}()) - -# See https://docs.julialang.org/en/v1/devdocs/ast/ -expr_operation(e::Expr, ::Union{Val{:call},Val{:macrocall}}) = e.args[1] -expr_operation(e::Expr, ::Union{Val{:ref}}) = getindex -expr_operation(e::Expr, ::Val{T}) where {T} = T - -expr_arguments(e::Expr, ::Union{Val{:call},Val{:macrocall}}) = e.args[2:end] -expr_arguments(e::Expr, _) = e.args - - -function similarterm(x::Expr, head, args, symtype = nothing; metadata = nothing, exprhead = exprhead(x)) - expr_similarterm(head, args, Val{exprhead}()) -end - - -expr_similarterm(head, args, ::Val{:call}) = Expr(:call, head, args...) -expr_similarterm(head, args, ::Val{:macrocall}) = Expr(:macrocall, head, args...) # discard linenumbernodes? -expr_similarterm(head, args, ::Val{eh}) where {eh} = Expr(eh, args...) diff --git a/src/utils.jl b/src/utils.jl deleted file mode 100644 index b9c732f..0000000 --- a/src/utils.jl +++ /dev/null @@ -1,16 +0,0 @@ -""" - is_operation(f) - -Returns a single argument anonymous function predicate, that returns `true` if and only if -the argument to the predicate satisfies `istree` and `operation(x) == f` -""" -is_operation(f) = @nospecialize(x) -> istree(x) && (operation(x) == f) -export is_operation - - -""" - node_count(t) -Count the nodes in a symbolic expression tree satisfying `istree` and `arguments`. -""" -node_count(t) = istree(t) ? reduce(+, node_count(x) for x in arguments(t), init = 0) + 1 : 1 -export node_count \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index c344173..c1fc239 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,17 +1,3 @@ -using TermInterface -using Test +using TermInterface, Test -@testset "Expr" begin - ex = :(f(a, b)) - @test operation(ex) == :f - @test arguments(ex) == [:a, :b] - @test exprhead(ex) == :call - @test ex == similarterm(ex, :f, [:a, :b]) - - ex = :(arr[i, j]) - @test operation(ex) == getindex - @test arguments(ex) == [:arr, :i, :j] - @test exprhead(ex) == :ref - @test ex == similarterm(ex, :ref, [:arr, :i, :j]; exprhead = :ref) - @test ex == similarterm(ex, :ref, [:arr, :i, :j]) -end +@test true \ No newline at end of file