Skip to content

Commit

Permalink
shashi's update
Browse files Browse the repository at this point in the history
  • Loading branch information
shashi committed Feb 10, 2024
1 parent 9e9af75 commit e6ae7a9
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 38 deletions.
114 changes: 82 additions & 32 deletions src/TermInterface.jl
Original file line number Diff line number Diff line change
@@ -1,18 +1,31 @@
module TermInterface

"""
istree(x)
iscall(x)
Returns `true` if `x` is a function call expression. If true, `operation`, `arguments`
must also be defined for `x`.
"""
iscall(x) = false
export iscall

"""
istree(x)
Returns `true` if `x` is a term. If true, `operation`, `arguments`
must also be defined for `x` appropriately.
Alias of `iscall`
"""
istree(x) = false
export istree
@depricate_binding istree iscall

"""
symtype(x)
isexpr(x)
Returns `true` if `x` is an expression tree (an S-expression). If true, `head` and `children` methods must be defined for `x`.
"""
isexpr(x) = false
export isexpr

Returns the symbolic type of `x`. By default this is just `typeof(x)`.
"""
symtype(expr)
Returns the symbolic type of `expr`. By default this is just `typeof(expr)`.
Define this for your symbolic types if you want `SymbolicUtils.simplify` to apply rules
specific to numbers (such as commutativity of multiplication). Or such
rules that may be implemented in the future.
Expand All @@ -23,36 +36,49 @@ end
export symtype

"""
issym(x)
issym(x)
Returns `true` if `x` is a symbol. If true, `nameof` must be defined
on `x` and must return a Symbol.
"""
issym(x) = false
export issym

"""
head(x)
Returns the head of the S-expression.
"""
function head end

"""
children(x)
Returns the children (aka tail) of the S-expression.
"""
function children end

"""
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.
Returns the function a function call expression is calling.
`iscall(x)` must be true as a precondition.
"""
function operation end
operation(x) = iscall(x) ? first(children(x)) : error("operation called on a non-function call expression")
export operation

"""
arguments(x)
Get the arguments of `x`, must be defined if `istree(x)` is `true`.
Returns the arguments to the function call in a function call expression.
`iscall(x)` must be true as a precondition.
"""
function arguments end
arguments(x) = iscall(x) ? Iterators.drop(children(x), 1) : error("arguments called on a non-function call expression")
export arguments

"""
unsorted_arguments(x::T)
If x is a term satisfying `istree(x)` and your term type `T` orovides
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.
Expand All @@ -64,8 +90,8 @@ export unsorted_arguments
"""
arity(x)
Returns the number of arguments of `x`. Implicitly defined
if `arguments(x)` is defined.
When `x` satisfies `iscall`, returns the number of arguments of `x`.
Implicitly defined if `arguments(x)` is defined.
"""
arity(x) = length(arguments(x))
export arity
Expand All @@ -74,41 +100,65 @@ export arity
"""
metadata(x)
Return the metadata attached to `x`.
Returns the metadata attached to `x`.
"""
metadata(x) = nothing
export metadata


"""
metadata(x, md)
metadata(expr, md)
Returns a new term which has the structure of `x` but also has
the metadata `md` attached to it.
Returns a `expr` with metadata `md` attached to it.
"""
function metadata(x, data)
error("Setting metadata on $x is not possible")
error("Setting metadata on $x is not implemented")
end

"""
similarterm(x, head, args, symtype=nothing; metadata=nothing)
similarterm(x, op, args, symtype=nothing; 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`. Implementers should define similarterm on the
type of `x` and not on `x` itself.
"""
function similarterm(x, head, args, symtype = nothing; metadata = nothing)
similarterm(typeof(x), head, args, symtype = symtype, metadata = metadata)
function similarterm(x, op, args, symtype = nothing; metadata = nothing)
maketerm(typeof(x), callhead(x), [op, args...], symtype, metadata)
end

function similarterm(T::Type, head, args, symtype = nothing; metadata = nothing)
head(args...)
# Old fallback
function similarterm(T::Type, op, args, symtype = nothing; metadata = nothing)
op(args...)
end

export similarterm


"""
callhead(x)
Used in this deprecation cycle of `similarterm` to find the `head` argument to
`makterm`. Do not implement this, or use `similarterm` if you're using this package.
"""
callhead(x) = typeof(x)
callhead(x::Expr) = Expr

"""
maketerm(T, head, children, type, metadata)
Constructs an expression. `T` is a constructor type, `head` and `children` are
the head and tail of the S-expression, `type` is the `type` of the S-expression.
`metadata` is any metadata attached to this expression.
Note that `maketerm` may not necessarily return an object of type `T`. For example,
it may return a representation which is more efficient.
This function is used by term-manipulation routines to construct terms generically.
Packages providing expression types must implement this method for each expression type.
If your types do not support type information or metadata, you still need to accept
these arguments and may choose to not use them.
"""

function maketerm(T::Type, head, children, type, metadata)
error("maketerm for $T is not impmlemented")
end

include("utils.jl")

include("expr.jl")
Expand Down
14 changes: 8 additions & 6 deletions src/expr.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# This file contains default definitions for TermInterface methods on Julia
# Builtin Expr type.

istree(x::Expr) = true
iscall(x::Expr) = x.head == :call

operation(e::Expr) = e.head
arguments(e::Expr) = e.args
head(e::Expr) = e.head
children(e::Expr) = e.args

function similarterm(x::Expr, head, args, symtype = nothing; metadata = nothing)
Expr(head, args...)
end
# ^ this will implicitly define operation and arguments

function maketerm(::Type{Expr}, head, args, symtype, metadata)
Expr(head, args...)
end

0 comments on commit e6ae7a9

Please sign in to comment.