Sexpr.java
/*
* Copyright 2017 Michael Mackenzie High
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mackenziehigh.sexpr;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* Symbolic Expression.
*
* <p>
* The textual representations of symbolic expressions are case-sensitive.
* </p>
*
* <p>
* Symbolic expressions are naturally comparable
* based on their textual representations.
* </p>
*
* <p>
* Two symbolic expressions (X) and (Y) are equal,
* iff <code>X.toString()</code> equals <code>Y.toString()</code>.
* </p>
*
* <p>
* All instances of this interface are immutable.
* </p>
*
* @param <T> is the type of the implementing class.
*/
public interface Sexpr<T extends Sexpr<T>>
extends Comparable<Sexpr<?>>
{
/**
* This method counts the leaf nodes in the tree rooted at this node.
*
* <p>
* This is a constant-time operation.
* </p>
*
* @return the number of leaf nodes.
*/
public int treeLeafCount ();
/**
* This method determines the height of the tree rooted at this node.
*
* <p>
* This is a constant-time operation.
* </p>
*
* @return the height of this tree.
*/
public int treeHeight ();
/**
* This method counts the nodes in the tree rooted at this node.
*
* <p>
* This is a constant-time operation.
* </p>
*
* @return the number of nodes, including this node.
*/
public int treeSize ();
/**
* This method performs a breadth-first-search of the tree rooted at this node.
*
* @param condition will return true, when the sought after node is found.
* @return true, if the node was found.
*/
public boolean bfs (final Predicate<Sexpr<?>> condition);
/**
* This method performs a depth-first-search of the tree rooted at this node.
*
* @param condition will return true, when the sought after node is found.
* @return true, if the node was found.
*/
public boolean dfs (final Predicate<Sexpr<?>> condition);
/**
* This method performs a pre-order-search of the tree rooted at this node.
*
* @param condition will return true, when the sought after node is found.
* @return true, if the node was found.
*/
public boolean preorder (final Predicate<Sexpr<?>> condition);
/**
* This method performs a post-order-search of the tree rooted at this node.
*
* @param condition will return true, when the sought after node is found.
* @return true, if the node was found.
*/
public boolean postorder (final Predicate<Sexpr<?>> condition);
/**
* This method performs a traversal of the tree rooted at this node.
*
* @param before will be invoked upon entering each sub-tree.
* @param after will be invoked upon exiting each sub-tree.
*/
public void traverse (Consumer<Sexpr<?>> before,
Consumer<Sexpr<?>> after);
/**
* This method determines whether this object is a SAtom.
*
* @return true, iff this object is a SAtom.
*/
public boolean isAtom ();
/**
* This method determines whether this object is a SList.
*
* @return true, iff this object is a SAtom.
*/
public boolean isList ();
/**
* This method retrieves an object describing the source
* from which this object we obtained.
*
* @return the source-code location of this node.
*/
public SourceLocation location ();
/**
* {@inheritDoc}
*/
@Override
public default int compareTo (final Sexpr<?> other)
{
return other == null ? 1 : toString().compareTo(other.toString());
}
/**
* Cast this object to SAtom.
*
* <p>
* This method could be considered a bad API design choice.
* However, the inclusion of this method makes the use of
* fluent chained-methods calls clearer and easier to write;
* therefore, the benefits outweigh the down-sides here.
* </p>
*
* @return this.
* @throws ClassCastException if isAtom() is false.
*/
public default SAtom asAtom ()
{
if (this instanceof SAtom)
{
return (SAtom) this;
}
else
{
throw new ClassCastException(toString());
}
}
/**
* Cast this object to SList.
*
* <p>
* This method could be considered a bad API design choice.
* However, the inclusion of this method makes the use of
* fluent chained-methods calls clearer and easier to write;
* therefore, the benefits outweigh the down-sides here.
* </p>
*
* @return this.
* @throws ClassCastException if isList() is false.
*/
public default SList asList ()
{
if (this instanceof SList)
{
return (SList) this;
}
else
{
throw new ClassCastException(toString());
}
}
/**
* This method retrieves the textual representation of this symbolic expression.
*
* @return this object as a string.
*/
@Override
public String toString ();
}