", 2, Associativity.LEFT, precedence);
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Group.java 0000664 0000000 0000000 00000006732 13103137730 0026001 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
/**
* A group is a special N-ary operator delineated by a left-hand symbol and a
* right-hand symbol, with comma-separated arguments.
*
* Typically, these are various forms of parentheses, although in principle any
* pair of two distinct symbols is allowed.
*
*
* @author Curtis Rueden
*/
public class Group extends Operator {
private final String terminator;
private int arity;
public Group(final String initiator, final String terminator,
final double precedence)
{
super(initiator, 0, Associativity.NONE, precedence);
this.terminator = terminator;
}
// -- Group methods --
public String getTerminator() {
return terminator;
}
public void incArity() {
arity++;
}
/**
* Returns true iff the given group is the same as this one, in terms of token
* (lefthand symbol), terminator (righthand symbol) and precedence.
*
* Note that this method intentionally does not compare arity; the idea is
* that if you have a {@link Group} and call {@link #instance} to duplicate
* it, that copy will match this one, even though the copy initially starts at
* arity 0.
*
*/
public boolean matches(final Group g) {
return getToken().equals(g.getToken()) &&
getTerminator().equals(g.getTerminator()) &&
getPrecedence() == g.getPrecedence();
}
// -- Operator methods --
@Override
public int getArity() {
return arity;
}
@Override
public boolean isInfix() {
return true;
}
@Override
public boolean isPrefix() {
return true;
}
/**
* Creates an instance of a group operator, using this one as a template.
*
* The created group will have the same initiator and terminator symbols, as
* well as the same precedence. But it will begin as a nullary group until
* {@link #incArity} is called.
*
*/
@Override
public Group instance() {
return new Group(getToken(), getTerminator(), getPrecedence());
}
// -- Object methods --
@Override
public String toString() {
return getToken() + getArity() + getTerminator();
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Literals.java 0000664 0000000 0000000 00000050030 13103137730 0026452 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Utility methods for parsing literals from strings. These methods largely
* conform to the Java specification's ideas of what constitutes a numeric or
* string literal.
*
* @author Curtis Rueden
*/
public final class Literals {
private static final Pattern HEX = Pattern
.compile("(([-+]?)0[Xx]([0-9a-fA-F]+)([Ll]?)).*");
private static final Pattern BINARY = Pattern
.compile("(([-+]?)0[Bb]([01]+)([Ll]?)).*");
private static final Pattern OCTAL = Pattern
.compile("(([-+]?)0([0-7]+)([Ll]?)).*");
private static final Pattern DECIMAL = Pattern
.compile("(([-+]?[0-9]+(\\.[0-9]*)?([Ee][0-9]+)?)([Dd]|[Ff]|[Ll])?).*");
private Literals() {
// NB: Prevent instantiation of utility class.
}
/**
* Parses a boolean literal (i.e., true and false).
*
* @param s The string from which the boolean literal should be parsed.
* @return The parsed boolean value—either {@link Boolean#TRUE} or
* {@link Boolean#FALSE}— or null if the string does not begin
* with a boolean literal.
*/
public static Boolean parseBoolean(final CharSequence s) {
return parseBoolean(s, new Position());
}
/**
* Parses a string literal which is enclosed in single or double quotes.
*
* For literals in double quotes, this parsing mechanism is intended to be as
* close as possible to the numeric literals supported by the Java programming
* language itself. Literals in single quotes are completely verbatim, with no
* escaping performed.
*
*
* @param s The string from which the string literal should be parsed.
* @return The parsed string value, unescaped according to Java conventions.
* Returns null if the string does not begin with a single or double
* quote.
*/
public static String parseString(final CharSequence s) {
return parseString(s, new Position());
}
/**
* Parses a hexidecimal literal (e.g., {@code 0xfedcba9876543210}).
*
* @param s The string from which the numeric literal should be parsed.
* @return The parsed numeric value—an {@link Integer} if sufficiently
* small, or a {@link Long} if needed or if the {@code L} suffix is
* given; or a {@link BigInteger} if the value is too large even for
* {@code long}.
*/
public static Number parseHex(final CharSequence s) {
return parseHex(s, new Position());
}
/**
* Parses a binary literal (e.g., {@code 0b010101000011}).
*
* @param s The string from which the numeric literal should be parsed.
* @return The parsed numeric value—an {@link Integer} if sufficiently
* small, or a {@link Long} if needed or if the {@code L} suffix is
* given; or a {@link BigInteger} if the value is too large even for
* {@code long}.
*/
public static Number parseBinary(final CharSequence s) {
return parseBinary(s, new Position());
}
/**
* Parses an octal literal (e.g., {@code 01234567}).
*
* @param s The string from which the numeric literal should be parsed.
* @return The parsed numeric value—an {@link Integer} if sufficiently
* small, or a {@link Long} if needed or if the {@code L} suffix is
* given; or a {@link BigInteger} if the value is too large even for
* {@code long}.
*/
public static Number parseOctal(final CharSequence s) {
return parseOctal(s, new Position());
}
/**
* Parses a decimal literal (integer or otherwise; e.g., {@code 1234567890},
* {@code 1234.0987} or {@code 1.2e34}).
*
* @param s The string from which the numeric literal should be parsed.
* @return The parsed numeric value, of a type consistent with Java's support
* for numeric primitives—or for values outside the normal range
* of Java primitives, {@link BigInteger} or {@link BigDecimal} as
* appropriate. Returns null if the string does not begin with the
* numeric literal telltale of a 0-9 digit with optional minus.
*/
public static Number parseDecimal(final CharSequence s) {
return parseDecimal(s, new Position());
}
/**
* Parses a numeric literal of any known type.
*
* This parsing mechanism is intended to be as close as possible to the
* numeric literals supported by the Java programming language itself.
*
*
* @param s The string from which the numeric literal should be parsed.
* @return The parsed numeric value, of a type consistent with Java's support
* for numeric primitives—or for values outside the normal range
* of Java primitives, {@link BigInteger} or {@link BigDecimal} as
* appropriate. Returns null if the string does not begin with the
* numeric literal telltale of a 0-9 digit with optional minus.
*/
public static Number parseNumber(final CharSequence s) {
return parseNumber(s, new Position());
}
/**
* Parses a literal of any known type (booleans, strings and numbers).
*
* @param s The string from which the literal should be parsed.
* @return The parsed value, of a type consistent with Java's support for
* literals: either {@link Boolean}, {@link String} or a concrete
* {@link Number} subclass. Returns null if the string does
* not match the syntax of a known literal.
* @see #parseBoolean(CharSequence)
* @see #parseString(CharSequence)
* @see #parseNumber(CharSequence)
*/
public static Object parseLiteral(final CharSequence s) {
return parseLiteral(s, new Position());
}
/**
* Parses a boolean literal (i.e., true and false).
*
* @param s The string from which the boolean literal should be parsed.
* @param pos The offset from which the literal should be parsed. If parsing
* is successful, the position will be advanced to the next index
* after the parsed literal.
* @return The parsed boolean value—either {@link Boolean#TRUE} or
* {@link Boolean#FALSE}— or null if the string does not begin
* with a boolean literal.
*/
public static Boolean parseBoolean(final CharSequence s, final Position pos) {
if (isWord(s, pos, "true")) {
pos.inc(4);
return Boolean.TRUE;
}
if (isWord(s, pos, "false")) {
pos.inc(5);
return Boolean.FALSE;
}
return null;
}
/**
* Parses a string literal which is enclosed in single or double quotes.
*
* For literals in double quotes, this parsing mechanism is intended to be as
* close as possible to the numeric literals supported by the Java programming
* language itself. Literals in single quotes are completely verbatim, with no
* escaping performed.
*
*
* @param s The string from which the string literal should be parsed.
* @param pos The offset from which the literal should be parsed. If parsing
* is successful, the position will be advanced to the next index
* after the parsed literal.
* @return The parsed string value, unescaped according to Java conventions.
* Returns null if the string does not begin with a single or double
* quote.
*/
public static String parseString(final CharSequence s, final Position pos) {
final char quote = pos.ch(s);
if (quote != '"' && quote != '\'') return null;
int index = pos.get() + 1;
boolean escaped = false;
final StringBuilder sb = new StringBuilder();
while (true) {
if (index >= s.length()) pos.die("Unclosed string literal");
final char c = s.charAt(index);
if (escaped) {
escaped = false;
if (isOctal(c)) { // octal sequence
String octal = "" + c;
final char c1 = pos.ch(s, index + 1);
if (isOctal(c1)) {
octal += c1;
if (c >= '0' && c <= '3') {
final char c2 = pos.ch(s, index + 2);
if (isOctal(c2)) octal += c2;
}
}
sb.append((char) Integer.parseInt(octal, 8));
index += octal.length();
continue;
}
switch (c) {
case 'b': // backspace
sb.append('\b');
break;
case 't': // tab
sb.append('\t');
break;
case 'n': // linefeed
sb.append('\n');
break;
case 'f': // form feed
sb.append('\f');
break;
case 'r': // carriage return
sb.append('\r');
break;
case '"': // double quote
sb.append('"');
break;
case '\\': // backslash
sb.append('\\');
break;
case 'u': // unicode sequence
final char u1 = hex(s, pos, index + 1);
final char u2 = hex(s, pos, index + 2);
final char u3 = hex(s, pos, index + 3);
final char u4 = hex(s, pos, index + 4);
sb.append((char) Integer.parseInt("" + u1 + u2 + u3 + u4, 16));
index += 4;
break;
default: // invalid escape
pos.die("Invalid escape sequence");
}
}
else if (c == '\\' && quote == '"') escaped = true;
else if (c == quote) break;
else sb.append(c);
index++;
}
pos.set(index + 1);
return sb.toString();
}
/**
* Parses a hexidecimal literal (e.g., {@code 0xfedcba9876543210}).
*
* @param s The string from which the numeric literal should be parsed.
* @param pos The offset from which the literal should be parsed. If parsing
* is successful, the position will be advanced to the next index
* after the parsed literal.
* @return The parsed numeric value—an {@link Integer} if sufficiently
* small, or a {@link Long} if needed or if the {@code L} suffix is
* given; or a {@link BigInteger} if the value is too large even for
* {@code long}; or {@code null} if the string does not begin with the
* numeric literal telltale of a 0-9 digit with optional minus.
*/
public static Number parseHex(final CharSequence s, final Position pos) {
return parseInteger(HEX, s, pos, 16);
}
/**
* Parses a binary literal (e.g., {@code 0b010101000011}).
*
* @param s The string from which the numeric literal should be parsed.
* @param pos The offset from which the literal should be parsed. If parsing
* is successful, the position will be advanced to the next index
* after the parsed literal.
* @return The parsed numeric value—an {@link Integer} if sufficiently
* small, or a {@link Long} if needed or if the {@code L} suffix is
* given; or a {@link BigInteger} if the value is too large even for
* {@code long}; or {@code null} if the string does not begin with the
* numeric literal telltale of a 0-9 digit with optional minus.
*/
public static Number parseBinary(final CharSequence s, final Position pos) {
return parseInteger(BINARY, s, pos, 2);
}
/**
* Parses an octal literal (e.g., {@code 01234567}).
*
* @param s The string from which the numeric literal should be parsed.
* @param pos The offset from which the literal should be parsed. If parsing
* is successful, the position will be advanced to the next index
* after the parsed literal.
* @return The parsed numeric value—an {@link Integer} if sufficiently
* small, or a {@link Long} if needed or if the {@code L} suffix is
* given; or a {@link BigInteger} if the value is too large even for
* {@code long}; or {@code null} if the string does not begin with the
* numeric literal telltale of a 0-9 digit with optional minus.
*/
public static Number parseOctal(final CharSequence s, final Position pos) {
return parseInteger(OCTAL, s, pos, 8);
}
/**
* Parses a decimal literal (e.g., {@code 1234.0987} or {@code 1.2e34}).
*
* @param s The string from which the numeric literal should be parsed.
* @param pos The offset from which the literal should be parsed. If parsing
* is successful, the position will be advanced to the next index
* after the parsed literal.
* @return The parsed numeric value, of a type consistent with Java's support
* for numeric primitives—or for values outside the normal range
* of Java primitives, {@link BigInteger} or {@link BigDecimal} as
* appropriate. Returns null if the string does not begin with the
* numeric literal telltale of a 0-9 digit with optional minus.
*/
public static Number parseDecimal(final CharSequence s, final Position pos) {
if (!isNumberSyntax(s, pos)) return null;
final Matcher m = matcher(DECIMAL, s, pos);
if (!m.matches()) return null;
final String number = m.group(2);
final String force = m.group(5);
final boolean forceLong = "l".equalsIgnoreCase(force);
final boolean forceFloat = "f".equalsIgnoreCase(force);
final boolean forceDouble = "d".equalsIgnoreCase(force);
Number result = null;
if (!forceFloat && !forceDouble) {
result = parseInteger(number, forceLong, 10);
}
if (result == null && !forceLong) {
result = parseDecimal(number, forceFloat, forceDouble);
}
return verifyResult(result, m, pos);
}
/**
* Parses a numeric literal of any known type.
*
* This parsing mechanism is intended to be as close as possible to the
* numeric literals supported by the Java programming language itself.
*
*
* @param s The string from which the numeric literal should be parsed.
* @param pos The offset from which the literal should be parsed. If parsing
* is successful, the position will be advanced to the next index
* after the parsed literal.
* @return The parsed numeric value, of a type consistent with Java's support
* for numeric primitives—or for values outside the normal range
* of Java primitives, {@link BigInteger} or {@link BigDecimal} as
* appropriate. Returns null if the string does not begin with the
* numeric literal telltale of a 0-9 digit with optional minus.
*/
public static Number parseNumber(final CharSequence s, final Position pos) {
final Number hex = parseHex(s, pos);
if (hex != null) return hex;
final Number binary = parseBinary(s, pos);
if (binary != null) return binary;
final Number octal = parseOctal(s, pos);
if (octal != null) return octal;
final Number decimal = parseDecimal(s, pos);
if (decimal != null) return decimal;
return null;
}
/**
* Parses a literal of any known type (booleans, strings and numbers).
*
* @param s The string from which the literal should be parsed.
* @param pos The offset from which the literal should be parsed. If parsing
* is successful, the position will be advanced to the next index
* after the parsed literal.
* @return The parsed value, of a type consistent with Java's support for
* literals: either {@link Boolean}, {@link String} or a concrete
* {@link Number} subclass. Returns null if the string does
* not match the syntax of a known literal.
* @see #parseBoolean(CharSequence, Position)
* @see #parseString(CharSequence, Position)
* @see #parseNumber(CharSequence, Position)
*/
public static Object parseLiteral(final CharSequence s, final Position pos) {
final Boolean bool = parseBoolean(s, pos);
if (bool != null) return bool;
final String str = parseString(s, pos);
if (str != null) return str;
final Number num = parseNumber(s, pos);
if (num != null) return num;
return null;
}
// -- Helper methods --
private static boolean isOctal(final char c) {
return c >= '0' && c <= '7';
}
private static char hex(final CharSequence s, final Position pos,
final int index)
{
final char c = pos.ch(s, index);
if (c >= '0' && c <= '9') return c;
if (c >= 'a' && c <= 'f') return c;
if (c >= 'A' && c <= 'F') return c;
pos.die("Invalid unicode sequence");
return '\0'; // NB: Unreachable.
}
private static boolean
isNumberSyntax(final CharSequence s, final Position pos)
{
final int i = pos.get();
final boolean sign = s.charAt(i) == '-' || s.charAt(i) == '+';
final char digit = s.charAt(sign ? i + 1 : i);
return digit >= '0' && digit <= '9';
}
private static Number parseInteger(final Pattern p, final CharSequence s,
final Position pos, final int base)
{
if (!isNumberSyntax(s, pos)) return null;
final Matcher m = matcher(p, s, pos);
if (!m.matches()) return null;
String sign = m.group(2);
if (sign == null) sign = "";
final String number = sign + m.group(3);
final boolean forceLong = !m.group(4).isEmpty();
final Number result = parseInteger(number, forceLong, base);
return verifyResult(result, m, pos);
}
private static Number parseInteger(final String number,
final boolean forceLong, final int base)
{
if (!forceLong) {
// Try to fit it into an int.
try {
return Integer.parseInt(number, base);
}
catch (final NumberFormatException exc) {
// NB: No action needed.
}
}
// Try to fit it into a long.
try {
return Long.parseLong(number, base);
}
catch (final NumberFormatException exc) {
// NB: No action needed.
}
if (!forceLong) {
// Try to treat it as a BigInteger.
try {
return new BigInteger(number, base);
}
catch (final NumberFormatException exc) {
// NB: No action needed.
}
}
return null;
}
private static Number parseDecimal(final String number,
final boolean forceFloat, final boolean forceDouble)
{
if (forceFloat) {
// Try to fit it into a flaot.
try {
return Float.parseFloat(number);
}
catch (final NumberFormatException exc) {
// NB: No action needed.
}
}
else {
// Try to fit it into a double.
try {
return Double.parseDouble(number);
}
catch (final NumberFormatException exc) {
// NB: No action needed.
}
}
if (!forceDouble && !forceFloat) {
// Try to treat it as a BigDecimal.
try {
return new BigDecimal(number);
}
catch (final NumberFormatException exc) {
// NB: No action needed.
}
}
return null;
}
private static Matcher matcher(final Pattern p, final CharSequence s,
final Position pos)
{
return p.matcher(sub(s, pos));
}
private static CharSequence sub(final CharSequence s, final Position pos) {
return pos.get() == 0 ? s : new SubSequence(s, pos.get());
}
private static Number verifyResult(final Number result, final Matcher m,
final Position pos)
{
if (result == null) pos.die("Illegal numeric literal");
pos.inc(m.group(1).length());
return result;
}
private static boolean isWord(final CharSequence s, final Position pos,
final String word)
{
if (s.length() - pos.get() < word.length()) return false;
for (int i=0; i= 'a' && next <= 'z') return false;
if (next >= 'A' && next <= 'Z') return false;
if (next >= '0' && next <= '9') return false;
if (next == '_') return false;
return true;
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Main.java 0000664 0000000 0000000 00000003621 13103137730 0025563 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import java.io.IOException;
import org.scijava.parse.eval.EvaluatorConsole;
/**
* Launches the console-driven expression evaluator.
*
* @author Curtis Rueden
* @see EvaluatorConsole
*/
public final class Main {
private Main() {
// Prevent instantiation of utility class.
}
// -- Main method --
public static void main(final String[] args) throws IOException {
new EvaluatorConsole().showConsole();
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Operator.java 0000664 0000000 0000000 00000006766 13103137730 0026507 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
/**
* A mathematical operator is a "verb": a special infix (in the case of binary
* or greater arity) or prefix (in the case of unary) symbol which defines a
* relation between "nouns" (i.e.: literals and variables).
*
* @author Curtis Rueden
*/
public class Operator extends Token implements Comparable {
public enum Associativity {
EITHER, LEFT, RIGHT, NONE
}
private final int arity;
private final Associativity associativity;
private final double precedence;
public Operator(final String symbol, final int arity,
final Associativity associativity, final double precedence)
{
super(symbol);
this.arity = arity;
this.associativity = associativity;
this.precedence = precedence;
}
// -- Operator methods --
/** 1 for unary, 2 for binary, etc. */
public int getArity() {
return arity;
}
public Associativity getAssociativity() {
return associativity;
}
public boolean isLeftAssociative() {
final Associativity a = getAssociativity();
return a == Associativity.LEFT || a == Associativity.EITHER;
}
public boolean isRightAssociative() {
final Associativity a = getAssociativity();
return a == Associativity.RIGHT || a == Associativity.EITHER;
}
/** True iff the operator is an infix operator (e.g., {@code a-b}). */
public boolean isInfix() {
return getArity() > 1;
}
/** True iff the operator is a prefix operator (e.g., {@code -a}). */
public boolean isPrefix() {
return getArity() == 1 && isRightAssociative();
}
/** True iff the operator is a postfix operator (e.g., {@code a'}). */
public boolean isPostfix() {
return getArity() == 1 && isLeftAssociative();
}
public double getPrecedence() {
return precedence;
}
public Operator instance() {
// NB: Properties are immutable, so instance can be reused.
return this;
}
// -- Comparable methods --
@Override
public int compareTo(final Operator that) {
final double thisP = getPrecedence();
final double thatP = that.getPrecedence();
if (thisP == thatP) return 0;
return thisP < thatP ? -1 : 1;
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Operators.java 0000664 0000000 0000000 00000016771 13103137730 0026667 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import static org.scijava.parse.Operator.Associativity.LEFT;
import static org.scijava.parse.Operator.Associativity.RIGHT;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import org.scijava.parse.Operator.Associativity;
/**
* A collection of standard {@link Operator}s. This set of operators was
* synthesized by combining Java standard operators and MATLAB standard operators .
*
* @author Curtis Rueden
*/
public final class Operators {
// -- dot --
public static final Operator DOT = op(".", 2, LEFT, 16);
// -- groups --
public static final Group PARENS = group("(", ")", 16);
public static final Group BRACKETS = group("[", "]", 16);
public static final Group BRACES = group("{", "}", 16);
// -- transpose, power --
public static final Operator TRANSPOSE = op("'", 1, LEFT, 15);
public static final Operator DOT_TRANSPOSE = op(".'", 1, LEFT, 15);
public static final Operator POW = op("^", 2, RIGHT, 15);
public static final Operator DOT_POW = op(".^", 2, RIGHT, 15);
// -- postfix --
public static final Operator POST_INC = op("++", 1, LEFT, 14);
public static final Operator POST_DEC = op("--", 1, LEFT, 14);
// -- unary --
public static final Operator PRE_INC = op("++", 1, RIGHT, 13);
public static final Operator PRE_DEC = op("--", 1, RIGHT, 13);
public static final Operator POS = op("+", 1, RIGHT, 13);
public static final Operator NEG = op("-", 1, RIGHT, 13);
public static final Operator COMPLEMENT = op("~", 1, RIGHT, 13);
public static final Operator NOT = op("!", 1, RIGHT, 13);
// -- multiplicative --
public static final Operator MUL = op("*", 2, LEFT, 12);
public static final Operator DIV = op("/", 2, LEFT, 12);
public static final Operator MOD = op("%", 2, LEFT, 12);
public static final Operator RIGHT_DIV = op("\\", 2, LEFT, 12);
public static final Operator DOT_MUL = op(".*", 2, LEFT, 12);
public static final Operator DOT_DIV = op("./", 2, LEFT, 12);
public static final Operator DOT_RIGHT_DIV = op(".\\", 2, LEFT, 12);
// -- additive --
public static final Operator ADD = op("+", 2, LEFT, 11);
public static final Operator SUB = op("-", 2, LEFT, 11);
// -- shift --
public static final Operator LEFT_SHIFT = op("<<", 2, LEFT, 10);
public static final Operator RIGHT_SHIFT = op(">>", 2, LEFT, 10);
public static final Operator UNSIGNED_RIGHT_SHIFT = op(">>>", 2, LEFT, 10);
// -- colon --
public static final Operator COLON = op(":", 2, LEFT, 9);
// -- relational --
public static final Operator LESS_THAN = op("<", 2, LEFT, 8);
public static final Operator GREATER_THAN = op(">", 2, LEFT, 8);
public static final Operator LESS_THAN_OR_EQUAL = op("<=", 2, LEFT, 8);
public static final Operator GREATER_THAN_OR_EQUAL = op(">=", 2, LEFT, 8);
public static final Operator INSTANCEOF = op("instanceof", 2, LEFT, 8);
// -- equality --
public static final Operator EQUAL = op("==", 2, LEFT, 7);
public static final Operator NOT_EQUAL = op("!=", 2, LEFT, 7);
// -- bitwise AND --
public static final Operator BITWISE_AND = op("&", 2, LEFT, 6);
// -- bitwise exclusive OR --
// NB: No bitwise XOR operator, because '^' is reserved for POW above.
//public static final Operator BITWISE_XOR = op("^", 2, LEFT, 5);
// -- bitwise inclusive OR --
public static final Operator BITWISE_OR = op("|", 2, LEFT, 4);
// -- logical AND --
public static final Operator LOGICAL_AND = op("&&", 2, LEFT, 3);
// -- logical OR --
public static final Operator LOGICAL_OR = op("||", 2, LEFT, 2);
// -- ternary --
// NB: Ternary (? :) operator is not currently supported.
// -- assignment --
public static final Operator ASSIGN = op("=", 2, RIGHT, 0);
public static final Operator POW_ASSIGN = op("^=", 2, RIGHT, 0);
public static final Operator DOT_POW_ASSIGN = op(".^=", 2, RIGHT, 0);
public static final Operator MUL_ASSIGN = op("*=", 2, RIGHT, 0);
public static final Operator DIV_ASSIGN = op("/=", 2, RIGHT, 0);
public static final Operator MOD_ASSIGN = op("%=", 2, RIGHT, 0);
public static final Operator RIGHT_DIV_ASSIGN = op("\\=", 2, RIGHT, 0);
public static final Operator DOT_DIV_ASSIGN = op("./=", 2, RIGHT, 0);
public static final Operator DOT_RIGHT_DIV_ASSIGN = op(".\\=", 2, RIGHT, 0);
public static final Operator ADD_ASSIGN = op("+=", 2, RIGHT, 0);
public static final Operator SUB_ASSIGN = op("-=", 2, RIGHT, 0);
public static final Operator AND_ASSIGN = op("&=", 2, RIGHT, 0);
public static final Operator OR_ASSIGN = op("|=", 2, RIGHT, 0);
public static final Operator LEFT_SHIFT_ASSIGN = op("<<=", 2, RIGHT, 0);
public static final Operator RIGHT_SHIFT_ASSIGN = op(">>=", 2, RIGHT, 0);
public static final Operator UNSIGNED_RIGHT_SHIFT_ASSIGN = op(">>>=", 2,
RIGHT, 0);
private Operators() {
// NB: Prevent instantiation of utility class.
}
/** Gets the standard list of operators. */
public static List standardList() {
// Build the standard list from all available Operator constants.
final ArrayList ops = new ArrayList();
for (final Field f : Operators.class.getFields()) {
if (!isOperator(f)) continue;
try {
ops.add((Operator) f.get(null));
}
catch (final IllegalAccessException exc) {
// This should never happen.
throw new IllegalStateException(exc);
}
}
return ops;
}
// -- Helper methods --
private static Operator op(final String symbol, final int arity,
final Associativity associativity, final double precedence)
{
return new Operator(symbol, arity, associativity, precedence);
}
private static Group group(final String leftSymbol,
final String rightSymbol, final double precedence)
{
return new Group(leftSymbol, rightSymbol, precedence);
}
private static boolean isOperator(final Field f) {
final int mods = f.getModifiers();
return Modifier.isStatic(mods) && Modifier.isFinal(mods) &&
Operator.class.isAssignableFrom(f.getType());
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Position.java 0000664 0000000 0000000 00000005462 13103137730 0026510 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
/**
* A mutable parse position. Similar to {@link java.text.ParsePosition}, but
* less complex.
*
* @author Curtis Rueden
*/
public class Position {
private int index;
public int get() {
return index;
}
public void set(final int index) {
this.index = index;
}
public void inc() {
inc(1);
}
public void inc(final int count) {
index += count;
}
public char ch(final CharSequence s) {
return ch(s, 0);
}
public char ch(final CharSequence s, final int offset) {
final int i = get() + offset;
return i < s.length() ? s.charAt(i) : '\0';
}
/** Throws {@link IllegalArgumentException} when syntax is incorrect. */
public void die(final String message) {
throw new IllegalArgumentException(messageWithDetails(message));
}
/** Throws {@link IllegalStateException} if something goes wrong. */
public void assertThat(final boolean condition, final String message) {
if (condition) return;
fail(message);
}
/** Throws {@link IllegalStateException} when something is wrong. */
public void fail(final String message) {
throw new IllegalStateException(messageWithDetails(message));
}
// -- Object methods --
@Override
public String toString() {
return "" + get();
}
// -- Helper methods --
private String messageWithDetails(final String message) {
return message + " at index " + get();
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/SubSequence.java 0000664 0000000 0000000 00000006526 13103137730 0027130 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
/**
* A {@link CharSequence} which is a by-reference subsequence of another
* {@link CharSequence}. This is particularly useful for
* {@link java.util.regex.Pattern regex} matching without excessive string
* copying.
*
* Surprisingly, core Java does not seem to have this capability (apart from
* {@link javax.swing.text.Segment}, which seems misplaced in the Swing
* library); all of {@link String#subSequence}, {@link StringBuffer#subSequence}
* and {@link StringBuilder#subSequence} internally copy the requested string
* segment.
*
*
* @author Curtis Rueden
*/
public class SubSequence implements CharSequence {
private final CharSequence seq;
private final int offset;
private final int length;
public SubSequence(final CharSequence seq, final int offset) {
this(seq, offset, seq.length() - offset);
}
private static void outOfBounds(final String message) {
throw new IndexOutOfBoundsException(message);
}
public SubSequence(final CharSequence seq, final int offset, final int length)
{
if (offset < 0) outOfBounds("Offset " + offset + " < 0");
if (offset > seq.length()) {
outOfBounds("Offset " + offset + " > " + seq.length());
}
if (length < 0) outOfBounds("Length " + length + " < 0");
if (offset + length > seq.length()) {
outOfBounds("Offset " + offset + " + length " + length + " > " +
seq.length());
}
this.seq = seq;
this.offset = offset;
this.length = length;
}
// -- CharSequence methods --
@Override
public int length() {
return length;
}
@Override
public char charAt(final int index) {
return seq.charAt(offset + index);
}
@Override
public SubSequence subSequence(final int start, final int end) {
return new SubSequence(seq, offset + start, end - start);
}
// -- Object methods --
@Override
public String toString() {
return seq.subSequence(offset, offset + length).toString();
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/SyntaxTree.java 0000664 0000000 0000000 00000010122 13103137730 0026777 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
/**
* A syntax
* tree corresponding to an expression.
*
* @author Curtis Rueden
*/
public class SyntaxTree implements Iterable {
private final Object token;
private SyntaxTree[] children;
/**
* Creates a syntax tree built from the given postfix
* token queue. This process will consume the entire queue.
*
* @param tokens The token queue, in postfix order.
*/
public SyntaxTree(final LinkedList tokens) {
token = tokens.removeLast();
if (Tokens.isOperator(token)) {
final Operator op = (Operator) token;
final int arity = op.getArity();
if (arity > 0) children = new SyntaxTree[arity];
for (int i = children.length - 1; i >= 0; i--) {
children[i] = new SyntaxTree(tokens);
}
}
}
public Object token() {
return token;
}
public SyntaxTree child(final int index) {
return children[index];
}
public int count() {
return children == null ? 0 : children.length;
}
/** Converts the syntax tree into a token queue in postfix order. */
public LinkedList postfix() {
final LinkedList queue = new LinkedList();
postfix(queue);
return queue;
}
// -- Object methods --
@Override
public String toString() {
return toString("");
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof SyntaxTree)) return false;
final SyntaxTree tree = (SyntaxTree) o;
return token.equals(tree.token) && Arrays.equals(children, tree.children);
}
@Override
public int hashCode() {
return token.hashCode() ^ children.hashCode();
}
// -- Iterable methods --
@Override
public Iterator iterator() {
return new Iterator() {
private int index;
@Override
public boolean hasNext() {
return index < count();
}
@Override
public SyntaxTree next() {
return child(index++);
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
// -- Helper methods --
private void postfix(final LinkedList queue) {
for (final SyntaxTree child : this) {
child.postfix(queue);
}
queue.add(token());
}
private String toString(final String prefix) {
final StringBuilder sb = new StringBuilder();
sb.append(prefix + " '" + token + "'\n");
final String deeperPrefix = " " + prefix + "-";
for (int i = 0; i < count(); i++) {
sb.append(child(i).toString(deeperPrefix));
}
return sb.toString();
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Token.java 0000664 0000000 0000000 00000004155 13103137730 0025762 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
/**
* Base class for various types of tokens: operators, groups, functions and
* variables.
*
* The only exception are literals, which use the standard Java types of
* {@link String}, {@link Boolean} and {@link Number} rather than extending this
* class.
*
*
* @author Curtis Rueden
*/
public abstract class Token {
private final String token;
public Token(final String token) {
this.token = token;
}
// -- Token methods --
/** Gets the token's sequence of characters. */
public String getToken() {
return token;
}
// -- Object methods --
@Override
public String toString() {
return getToken();
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Tokens.java 0000664 0000000 0000000 00000004520 13103137730 0026141 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
/**
* Utility methods for working with tokens.
*
* @author Curtis Rueden
*/
public final class Tokens {
private Tokens() {
// NB: Prevent instantiation of utility class.
}
public static boolean isNumber(final Object o) {
return o instanceof Number;
}
public static boolean isGroup(final Object o) {
return o instanceof Group;
}
public static boolean isVariable(final Object o) {
return o instanceof Variable;
}
public static boolean isOperator(final Object o) {
return o instanceof Operator;
}
public static boolean isComma(final Object o) {
return isCharacter(o, ',');
}
public static boolean isCharacter(final Object o, final Character c) {
return o instanceof Character && ((Character) o).equals(c);
}
public static boolean isMatchingGroup(final Object o, final Group g) {
return isGroup(o) && ((Group) o).matches(g);
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/Variable.java 0000664 0000000 0000000 00000003236 13103137730 0026426 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
/**
* A "noun" token representing a variable.
*
* @author Curtis Rueden
*/
public class Variable extends Token {
public Variable(final String token) {
super(token);
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/ 0000775 0000000 0000000 00000000000 13103137730 0024761 5 ustar 00root root 0000000 0000000 parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/AbstractEvaluator.java 0000664 0000000 0000000 00000006375 13103137730 0031265 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import java.util.HashMap;
import java.util.Map;
import org.scijava.parse.ExpressionParser;
import org.scijava.parse.SyntaxTree;
import org.scijava.parse.Tokens;
import org.scijava.parse.Variable;
/**
* Base class for {@link Evaluator} implementations.
*
* @author Curtis Rueden
*/
public abstract class AbstractEvaluator implements Evaluator {
private final HashMap vars = new HashMap();
private final ExpressionParser parser;
private boolean strict = true;
public AbstractEvaluator() {
this(new ExpressionParser());
}
public AbstractEvaluator(final ExpressionParser parser) {
this.parser = parser;
}
// -- Evaluator methods --
@Override
public ExpressionParser getParser() {
return parser;
}
@Override
public boolean isStrict() {
return strict;
}
@Override
public void setStrict(final boolean strict) {
this.strict = strict;
}
@Override
public Object evaluate(final SyntaxTree syntaxTree) {
// Convert the syntax tree to postfix.
return evaluate(syntaxTree.postfix());
}
@Override
public Object evaluate(final String expression) {
// Convert the expression to postfix.
return evaluate(parser.parsePostfix(expression));
}
@Override
public Object value(final Object token) {
return Tokens.isVariable(token) ? get((Variable) token) : token;
}
@Override
public Object get(final Variable v) {
final String name = v.getToken();
if (vars.containsKey(name)) return vars.get(name);
if (strict) throw new IllegalArgumentException("Unknown variable: " + name);
return new Unresolved(name);
}
@Override
public void set(final Variable v, final Object value) {
vars.put(v.getToken(), value);
}
@Override
public void setAll(final Map extends String, ? extends Object> map) {
vars.putAll(map);
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/AbstractStackEvaluator.java 0000664 0000000 0000000 00000007273 13103137730 0032251 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedList;
import org.scijava.parse.ExpressionParser;
import org.scijava.parse.Function;
import org.scijava.parse.Group;
import org.scijava.parse.Operator;
import org.scijava.parse.Tokens;
/**
* Base class for {@link StackEvaluator} implementations.
*
* @author Curtis Rueden
*/
public abstract class AbstractStackEvaluator extends AbstractEvaluator
implements StackEvaluator
{
public AbstractStackEvaluator() {
super();
}
public AbstractStackEvaluator(final ExpressionParser parser) {
super(parser);
}
// -- Evaluator methods --
@Override
public Object evaluate(final LinkedList queue) {
// Process the postfix token queue.
final Deque stack = new ArrayDeque();
while (!queue.isEmpty()) {
final Object token = queue.removeFirst();
final Object result;
if (Tokens.isOperator(token)) {
result = execute((Operator) token, stack);
}
else {
// Token is a variable or a literal.
result = token;
}
if (result == null) die(token);
stack.push(result);
}
if (stack.isEmpty()) return null;
if (stack.size() == 1) return stack.pop();
final LinkedList resultList = new LinkedList();
while (!stack.isEmpty()) {
resultList.addFirst(stack.pop());
}
return resultList;
}
// -- Helper methods --
private static final String[] ARY = { "nullary", "unary", "binary",
"ternary", "quaternary", "quinary", "senary", "septenary", "octary",
"nonary" };
private static String ary(final int arity) {
return arity < ARY.length ? ARY[arity] : arity + "-ary";
}
private static String ary(final Operator op) {
return ary(op.getArity());
}
private static void die(final Object token) {
final StringBuilder message = new StringBuilder("Unsupported");
if (token instanceof Operator) message.append(" " + ary((Operator) token));
message.append(" " + type(token) + ": " + token);
throw new IllegalArgumentException(message.toString());
}
private static String type(final Object token) {
if (token instanceof Function) return "function";
if (token instanceof Group) return "group";
if (token instanceof Operator) return "operator";
return "token";
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/AbstractStandardStackEvaluator.java0000664 0000000 0000000 00000021065 13103137730 0033725 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import java.util.Deque;
import org.scijava.parse.ExpressionParser;
import org.scijava.parse.Function;
import org.scijava.parse.Operator;
import org.scijava.parse.Operators;
import org.scijava.parse.Tokens;
import org.scijava.parse.Variable;
/**
* Base class for stack-based evaluators which support the standard operators.
*
* @author Curtis Rueden
*/
public abstract class AbstractStandardStackEvaluator extends
AbstractStackEvaluator implements StandardEvaluator
{
public AbstractStandardStackEvaluator() {
super();
}
public AbstractStandardStackEvaluator(final ExpressionParser parser) {
super(parser);
}
// -- StandardEvaluator methods --
// -- postfix --
@Override
public Object postInc(final Object a) {
final Variable v = var(a);
final Object value = value(v);
if (value == null) return null;
set(v, add(a, 1));
return value;
}
@Override
public Object postDec(final Object a) {
final Variable v = var(a);
final Object value = value(v);
if (value == null) return null;
set(v, sub(a, 1));
return value;
}
// -- unary --
@Override
public Object preInc(final Object a) {
final Variable v = var(a);
final Object result = add(a, 1);
set(v, result);
return result;
}
@Override
public Object preDec(final Object a) {
final Variable v = var(a);
final Object result = sub(a, 1);
set(v, result);
return result;
}
// -- assignment --
@Override
public Object assign(final Object a, final Object b) {
final Variable v = var(a);
set(v, value(b));
return v;
}
@Override
public Object powAssign(final Object a, final Object b) {
return assign(a, pow(a, b));
}
@Override
public Object dotPowAssign(final Object a, final Object b) {
return assign(a, dotPow(a, b));
}
@Override
public Object mulAssign(final Object a, final Object b) {
return assign(a, mul(a, b));
}
@Override
public Object divAssign(final Object a, final Object b) {
return assign(a, div(a, b));
}
@Override
public Object modAssign(final Object a, final Object b) {
return assign(a, mod(a, b));
}
@Override
public Object rightDivAssign(final Object a, final Object b) {
return assign(a, rightDiv(a, b));
}
@Override
public Object dotDivAssign(final Object a, final Object b) {
return assign(a, dotDiv(a, b));
}
@Override
public Object dotRightDivAssign(final Object a, final Object b) {
return assign(a, dotRightDiv(a, b));
}
@Override
public Object addAssign(final Object a, final Object b) {
return assign(a, add(a, b));
}
@Override
public Object subAssign(final Object a, final Object b) {
return assign(a, sub(a, b));
}
@Override
public Object andAssign(final Object a, final Object b) {
return assign(a, bitwiseAnd(a, b));
}
@Override
public Object orAssign(final Object a, final Object b) {
return assign(a, bitwiseOr(a, b));
}
@Override
public Object leftShiftAssign(final Object a, final Object b) {
return assign(a, leftShift(a, b));
}
@Override
public Object rightShiftAssign(final Object a, final Object b) {
return assign(a, rightShift(a, b));
}
@Override
public Object unsignedRightShiftAssign(final Object a, final Object b) {
return assign(a, unsignedRightShift(a, b));
}
// -- StackEvaluator methods --
@Override
public Object execute(final Operator op, final Deque stack) {
// Pop the arguments.
final int arity = op.getArity();
final Object[] args = new Object[arity];
for (int i = args.length - 1; i >= 0; i--) {
args[i] = stack.pop();
}
final Object a = args.length > 0 ? args[0] : null;
final Object b = args.length > 1 ? args[1] : null;
// Let the case logic begin!
if (op instanceof Function) return function(a, b);
if (op == Operators.DOT) return dot(a, b);
if (Tokens.isMatchingGroup(op, Operators.PARENS)) return parens(args);
if (Tokens.isMatchingGroup(op, Operators.BRACKETS)) return brackets(args);
if (Tokens.isMatchingGroup(op, Operators.BRACES)) return braces(args);
if (op == Operators.TRANSPOSE) return transpose(a);
if (op == Operators.DOT_TRANSPOSE) return dotTranspose(a);
if (op == Operators.POW) return pow(a, b);
if (op == Operators.DOT_POW) return dotPow(a, b);
if (op == Operators.POST_INC) return postInc(a);
if (op == Operators.POST_DEC) return postDec(a);
if (op == Operators.PRE_INC) return preInc(a);
if (op == Operators.PRE_DEC) return preDec(a);
if (op == Operators.POS) return pos(a);
if (op == Operators.NEG) return neg(a);
if (op == Operators.COMPLEMENT) return complement(a);
if (op == Operators.NOT) return not(a);
if (op == Operators.MUL) return mul(a, b);
if (op == Operators.DIV) return div(a, b);
if (op == Operators.MOD) return mod(a, b);
if (op == Operators.RIGHT_DIV) return rightDiv(a, b);
if (op == Operators.DOT_MUL) return dotMul(a, b);
if (op == Operators.DOT_DIV) return dotDiv(a, b);
if (op == Operators.DOT_RIGHT_DIV) return dotRightDiv(a, b);
if (op == Operators.ADD) return add(a, b);
if (op == Operators.SUB) return sub(a, b);
if (op == Operators.LEFT_SHIFT) return leftShift(a, b);
if (op == Operators.RIGHT_SHIFT) return rightShift(a, b);
if (op == Operators.UNSIGNED_RIGHT_SHIFT) return unsignedRightShift(a, b);
if (op == Operators.COLON) return colon(a, b);
if (op == Operators.LESS_THAN) return lessThan(a, b);
if (op == Operators.GREATER_THAN) return greaterThan(a, b);
if (op == Operators.LESS_THAN_OR_EQUAL) return lessThanOrEqual(a, b);
if (op == Operators.GREATER_THAN_OR_EQUAL) return greaterThanOrEqual(a, b);
if (op == Operators.INSTANCEOF) return instanceOf(a, b);
if (op == Operators.EQUAL) return equal(a, b);
if (op == Operators.NOT_EQUAL) return notEqual(a, b);
if (op == Operators.BITWISE_AND) return bitwiseAnd(a, b);
if (op == Operators.BITWISE_OR) return bitwiseOr(a, b);
if (op == Operators.LOGICAL_AND) return logicalAnd(a, b);
if (op == Operators.LOGICAL_OR) return logicalOr(a, b);
if (op == Operators.ASSIGN) return assign(a, b);
if (op == Operators.POW_ASSIGN) return powAssign(a, b);
if (op == Operators.DOT_POW_ASSIGN) return dotPowAssign(a, b);
if (op == Operators.MUL_ASSIGN) return mulAssign(a, b);
if (op == Operators.DIV_ASSIGN) return divAssign(a, b);
if (op == Operators.MOD_ASSIGN) return modAssign(a, b);
if (op == Operators.RIGHT_DIV_ASSIGN) return rightDivAssign(a, b);
if (op == Operators.DOT_DIV_ASSIGN) return dotDivAssign(a, b);
if (op == Operators.DOT_RIGHT_DIV_ASSIGN) return dotRightDivAssign(a, b);
if (op == Operators.ADD_ASSIGN) return addAssign(a, b);
if (op == Operators.SUB_ASSIGN) return subAssign(a, b);
if (op == Operators.AND_ASSIGN) return andAssign(a, b);
if (op == Operators.OR_ASSIGN) return orAssign(a, b);
if (op == Operators.LEFT_SHIFT_ASSIGN) return leftShiftAssign(a, b);
if (op == Operators.RIGHT_SHIFT_ASSIGN) return rightShiftAssign(a, b);
if (op == Operators.UNSIGNED_RIGHT_SHIFT_ASSIGN) return unsignedRightShiftAssign(a, b);
// Unknown operator.
return null;
}
// -- Helper methods --
/** Casts the given token to a variable. */
private Variable var(final Object token) {
if (Tokens.isVariable(token)) return (Variable) token;
throw new IllegalArgumentException("Not a variable: " + token);
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/DefaultEvaluator.java 0000664 0000000 0000000 00000050135 13103137730 0031077 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import org.scijava.parse.ExpressionParser;
import org.scijava.parse.Literals;
import org.scijava.parse.Operators;
import org.scijava.parse.Tokens;
import org.scijava.parse.Variable;
/**
* An expression evaluator for most {@link Operators standard operators} with
* common built-in types (i.e.: {@link Boolean}s, {@link String}s and
* {@link Number}s). Caveats
*
* This class is a big bag of case logic for various operators and types.
* Looking at it, you might think: "It sure would be nice to modularize this,
* with each operation in its own class, with properly declared types, and
* called dynamically at runtime as appropriate."
*
*
* "Great idea!" I would reply. Then I would suggest you have a look at the SciJava Ops and ImageJ Ops projects, which do
* exactly that in an extensible way.
*
*
* Or maybe you are thinking: "This can't possibly work as well as awesome
* JVM-based scripting languages like Jython
* and Groovy ..."
*
*
* To which I would reply: "You are absolutely right! This class is mostly just
* a demonstration of an extensible, working evaluator built using the
* {@link org.scijava.parse.eval} package. If your use case is only concerned
* with feature-rich evaluation of standard types, then building on top of a
* scripting language might make more sense."
*
*
* @author Curtis Rueden
* @see org.scijava.parse.Main The main class, to give it a spin.
*/
public class DefaultEvaluator extends AbstractStandardStackEvaluator {
public DefaultEvaluator() {
super();
}
public DefaultEvaluator(final ExpressionParser parser) {
super(parser);
}
// -- function --
@Override
public Object function(final Object a, final Object b) {
final Object element = listElement(a, b);
if (element != null) return element;
if (Tokens.isVariable(a)) {
final String name = ((Variable) a).getToken();
final Object result = callFunction(name, b);
if (result != null) return result;
}
// NB: Unknown function type.
return null;
}
// -- dot --
@Override
public Object dot(final Object a, final Object b) {
// NB: Unimplemented.
return null;
}
// -- groups --
@Override
public Object parens(final Object[] args) {
if (args.length == 1) return args[0];
return Arrays.asList(args);
}
@Override
public Object brackets(final Object[] args) {
return Arrays.asList(args);
}
@Override
public Object braces(final Object[] args) {
return Arrays.asList(args);
}
// -- transpose, power --
@Override
public Object transpose(final Object a) {
// NB: Unimplemented.
return null;
}
@Override
public Object dotTranspose(final Object a) {
// NB: Unimplemented.
return null;
}
@Override
public Object pow(final Object a, final Object b) {
if (isD(a) && isD(b)) return pow(d(a), d(b));
if (isBI(a) && isI(b)) return pow(bi(a), i(b));
if (isBD(a) && isI(b)) return pow(bd(a), i(b));
return null;
}
public double pow(final double a, final double b) { return Math.pow(a, b); }
public BigInteger pow(final BigInteger a, final int b) { return a.pow(b); }
public BigDecimal pow(final BigDecimal a, final int b) { return a.pow(b); }
@Override
public Object dotPow(final Object a, final Object b) {
// NB: Unimplemented.
return null;
}
// -- unary --
@Override
public Object pos(final Object a) {
if (isI(a)) return pos(i(a));
if (isL(a)) return pos(l(a));
if (isF(a)) return pos(f(a));
if (isD(a)) return pos(d(a));
return value(a);
}
public int pos(final int num) { return +num; }
public long pos(final long num) { return +num; }
public float pos(final float num) { return +num; }
public double pos(final double num) { return +num; }
@Override
public Object neg(final Object a) {
if (isI(a)) return neg(i(a));
if (isL(a)) return neg(l(a));
if (isF(a)) return neg(f(a));
if (isD(a)) return neg(d(a));
if (isBI(a)) return neg(bi(a));
if (isBD(a)) return neg(bd(a));
return sub(0, a);
}
public int neg(final int num) { return -num; }
public long neg(final long num) { return -num; }
public float neg(final float num) { return -num; }
public double neg(final double num) { return -num; }
public BigInteger neg(final BigInteger num) { return num.negate(); }
public BigDecimal neg(final BigDecimal num) { return num.negate(); }
@Override
public Object complement(final Object a) {
if (isI(a)) return complement(i(a));
if (isL(a)) return complement(l(a));
return null;
}
public int complement(final int a) { return ~a; }
public long complement(final long a) { return ~a; }
@Override
public Object not(final Object a) { return not(bool(a)); }
public boolean not(final boolean a) { return !a; }
// -- multiplicative --
@Override
public Object mul(final Object a, final Object b) {
if (isI(a) && isI(b)) return mul(i(a), i(b));
if (isL(a) && isL(b)) return mul(l(a), l(b));
if (isF(a) && isF(b)) return mul(f(a), f(b));
if (isD(a) && isD(b)) return mul(d(a), d(b));
if (isBI(a) && isBI(b)) return mul(bi(a), bi(b));
if (isBD(a) && isBD(b)) return mul(bd(a), bd(b));
return null;
}
public int mul(final int a, final int b) { return a * b; }
public long mul(final long a, final long b) { return a * b; }
public float mul(final float a, final float b) { return a * b; }
public double mul(final double a, final double b) { return a * b; }
public BigInteger mul(final BigInteger a, final BigInteger b) {
return a.multiply(b);
}
public BigDecimal mul(final BigDecimal a, final BigDecimal b) {
return a.multiply(b);
}
@Override
public Object div(final Object a, final Object b) {
if (isI(a) && isI(b)) return div(i(a), i(b));
if (isL(a) && isL(b)) return div(l(a), l(b));
if (isF(a) && isF(b)) return div(f(a), f(b));
if (isD(a) && isD(b)) return div(d(a), d(b));
if (isBI(a) && isBI(b)) return div(bi(a), bi(b));
if (isBD(a) && isBD(b)) return div(bd(a), bd(b));
return null;
}
public int div(final int a, final int b) { return a / b; }
public long div(final long a, final long b) { return a / b; }
public float div(final float a, final float b) { return a / b; }
public double div(final double a, final double b) { return a / b; }
public BigInteger div(final BigInteger a, final BigInteger b) {
return a.divide(b);
}
public BigDecimal div(final BigDecimal a, final BigDecimal b) {
return a.divide(b);
}
@Override
public Object mod(final Object a, final Object b) {
if (isI(a) && isI(b)) return mod(i(a), i(b));
if (isL(a) && isL(b)) return mod(l(a), l(b));
if (isF(a) && isF(b)) return mod(f(a), f(b));
if (isD(a) && isD(b)) return mod(d(a), d(b));
if (isBI(a) && isBI(b)) return mod(bi(a), bi(b));
if (isBD(a) && isBD(b)) return mod(bd(a), bd(b));
return null;
}
public int mod(final int a, final int b) { return a % b; }
public long mod(final long a, final long b) { return a % b; }
public float mod(final float a, final float b) { return a % b; }
public double mod(final double a, final double b) { return a % b; }
public BigInteger mod(final BigInteger a, final BigInteger b) {
return a.remainder(b);
}
public BigDecimal mod(final BigDecimal a, final BigDecimal b) {
return a.remainder(b);
}
@Override
public Object rightDiv(final Object a, final Object b) {
// NB: Unimplemented.
return null;
}
@Override
public Object dotMul(Object a, Object b) {
// NB: Unimplemented.
return null;
}
@Override
public Object dotDiv(final Object a, final Object b) {
// NB: Unimplemented.
return null;
}
@Override
public Object dotRightDiv(final Object a, final Object b) {
// NB: Unimplemented.
return null;
}
// -- additive --
@Override
public Object add(final Object a, final Object b) {
if (isStr(a)) return add(str(a), str(b));
if (isI(a) && isI(b)) return add(i(a), i(b));
if (isL(a) && isL(b)) return add(l(a), l(b));
if (isF(a) && isF(b)) return add(f(a), f(b));
if (isD(a) && isD(b)) return add(d(a), d(b));
if (isBI(a) && isBI(b)) return add(bi(a), bi(b));
if (isBD(a) && isBD(b)) return add(bd(a), bd(b));
return null;
}
public String add(final String a, final String b) { return a + b; }
public int add(final int a, final int b) { return a + b; }
public long add(final long a, final long b) { return a + b; }
public float add(final float a, final float b) { return a + b; }
public double add(final double a, final double b) { return a + b; }
public BigInteger add(final BigInteger a, final BigInteger b) {
return a.add(b);
}
public BigDecimal add(final BigDecimal a, final BigDecimal b) {
return a.add(b);
}
@Override
public Object sub(final Object a, final Object b) {
if (isI(a) && isI(b)) return sub(i(a), i(b));
if (isL(a) && isL(b)) return sub(l(a), l(b));
if (isF(a) && isF(b)) return sub(f(a), f(b));
if (isD(a) && isD(b)) return sub(d(a), d(b));
if (isBI(a) && isBI(b)) return sub(bi(a), bi(b));
if (isBD(a) && isBD(b)) return sub(bd(a), bd(b));
return null;
}
public int sub(final int a, final int b) { return a - b; }
public long sub(final long a, final long b) { return a - b; }
public float sub(final float a, final float b) { return a - b; }
public double sub(final double a, final double b) { return a - b; }
public BigInteger sub(final BigInteger a, final BigInteger b) {
return a.subtract(b);
}
public BigDecimal sub(final BigDecimal a, final BigDecimal b) {
return a.subtract(b);
}
// -- shift --
@Override
public Object leftShift(final Object a, final Object b) {
if (isI(a) && isI(b)) return leftShift(i(a), i(b));
if (isL(a) && isL(b)) return leftShift(l(a), l(b));
if (isBI(a) && isI(b)) return leftShift(bi(a), i(b));
return null;
}
public int leftShift(final int a, final int b) { return a << b; }
public long leftShift(final long a, final long b) { return a << b; }
public BigInteger leftShift(final BigInteger a, final int b) {
return a.shiftLeft(b);
}
@Override
public Object rightShift(final Object a, final Object b) {
if (isI(a) && isI(b)) return rightShift(i(a), i(b));
if (isL(a) && isL(b)) return rightShift(l(a), l(b));
if (isBI(a) && isI(b)) return rightShift(bi(a), i(b));
return null;
}
public int rightShift(final int a, final int b) { return a >> b; }
public long rightShift(final long a, final long b) { return a >> b; }
public BigInteger rightShift(final BigInteger a, final int b) {
return a.shiftRight(b);
}
@Override
public Object unsignedRightShift(final Object a, final Object b) {
if (isI(a) && isI(b)) return unsignedRightShift(i(a), i(b));
if (isL(a) && isL(b)) return unsignedRightShift(l(a), l(b));
return null;
}
public int unsignedRightShift(final int a, final int b) { return a >>> b; }
public long unsignedRightShift(final long a, final long b) { return a >>> b; }
// -- colon --
@Override
public Object colon(final Object a, final Object b) {
// NB: Unimplemented.
return null;
}
// -- relational --
@Override
public Object lessThan(final Object a, final Object b) {
if (isBool(a) && isBool(b)) return lessThan(bool(a), bool(b));
if (isStr(a) && isStr(b)) return lessThan(str(a), str(b));
if (isI(a) && isI(b)) return lessThan(i(a), i(b));
if (isL(a) && isL(b)) return lessThan(l(a), l(b));
if (isF(a) && isF(b)) return lessThan(f(a), f(b));
if (isD(a) && isD(b)) return lessThan(d(a), d(b));
if (isBI(a) && isBI(b)) return lessThan(bi(a), bi(b));
if (isBD(a) && isBD(b)) return lessThan(bd(a), bd(b));
return null;
}
public boolean lessThan(final Comparable a, final T b) {
return a.compareTo(b) < 0;
}
@Override
public Object greaterThan(final Object a, final Object b) {
if (isBool(a) && isBool(b)) return greaterThan(bool(a), bool(b));
if (isStr(a) && isStr(b)) return greaterThan(str(a), str(b));
if (isI(a) && isI(b)) return greaterThan(i(a), i(b));
if (isL(a) && isL(b)) return greaterThan(l(a), l(b));
if (isF(a) && isF(b)) return greaterThan(f(a), f(b));
if (isD(a) && isD(b)) return greaterThan(d(a), d(b));
if (isBI(a) && isBI(b)) return greaterThan(bi(a), bi(b));
if (isBD(a) && isBD(b)) return greaterThan(bd(a), bd(b));
return null;
}
public boolean greaterThan(final Comparable a, final T b) {
return a.compareTo(b) > 0;
}
@Override
public Object lessThanOrEqual(final Object a, final Object b) {
if (isBool(a) && isBool(b)) return lessThanOrEqual(bool(a), bool(b));
if (isStr(a) && isStr(b)) return lessThanOrEqual(str(a), str(b));
if (isI(a) && isI(b)) return lessThanOrEqual(i(a), i(b));
if (isL(a) && isL(b)) return lessThanOrEqual(l(a), l(b));
if (isF(a) && isF(b)) return lessThanOrEqual(f(a), f(b));
if (isD(a) && isD(b)) return lessThanOrEqual(d(a), d(b));
if (isBI(a) && isBI(b)) return lessThanOrEqual(bi(a), bi(b));
if (isBD(a) && isBD(b)) return lessThanOrEqual(bd(a), bd(b));
return null;
}
public boolean lessThanOrEqual(final Comparable a, final T b) {
return a.compareTo(b) <= 0;
}
@Override
public Object greaterThanOrEqual(final Object a, final Object b) {
if (isBool(a) && isBool(b)) return greaterThanOrEqual(bool(a), bool(b));
if (isStr(a) && isStr(b)) return greaterThanOrEqual(str(a), str(b));
if (isI(a) && isI(b)) return greaterThanOrEqual(i(a), i(b));
if (isL(a) && isL(b)) return greaterThanOrEqual(l(a), l(b));
if (isF(a) && isF(b)) return greaterThanOrEqual(f(a), f(b));
if (isD(a) && isD(b)) return greaterThanOrEqual(d(a), d(b));
if (isBI(a) && isBI(b)) return greaterThanOrEqual(bi(a), bi(b));
if (isBD(a) && isBD(b)) return greaterThanOrEqual(bd(a), bd(b));
return null;
}
public boolean greaterThanOrEqual(final Comparable a, final T b) {
return a.compareTo(b) >= 0;
}
@Override
public Object instanceOf(final Object a, final Object b) {
// NB: Unimplemented.
return null;
}
// -- equality --
@Override
public Object equal(final Object a, final Object b) {
return value(a).equals(value(b));
}
@Override
public Object notEqual(final Object a, final Object b) {
return !value(a).equals(value(b));
}
// -- bitwise --
@Override
public Object bitwiseAnd(final Object a, final Object b) {
if (isI(a) && isI(b)) return bitwiseAnd(i(a), i(b));
if (isL(a) && isL(b)) return bitwiseAnd(l(a), l(b));
if (isBI(a) && isBI(b)) return bitwiseAnd(bi(a), bi(b));
return null;
}
public int bitwiseAnd(final int a, final int b) { return a & b; }
public long bitwiseAnd(final long a, final long b) { return a & b; }
public BigInteger bitwiseAnd(final BigInteger a, final BigInteger b) {
return a.and(b);
}
@Override
public Object bitwiseOr(final Object a, final Object b) {
if (isI(a) && isI(b)) return bitwiseOr(i(a), i(b));
if (isL(a) && isL(b)) return bitwiseOr(l(a), l(b));
if (isBI(a) && isBI(b)) return bitwiseOr(bi(a), bi(b));
return null;
}
public int bitwiseOr(final int a, final int b) { return a | b; }
public long bitwiseOr(final long a, final long b) { return a | b; }
public BigInteger bitwiseOr(final BigInteger a, final BigInteger b) {
return a.or(b);
}
// -- logical --
@Override
public Object logicalAnd(final Object a, final Object b) {
if (isBool(a) && isBool(b)) return logicalAnd(bool(a), bool(b));
return null;
}
public boolean logicalAnd(final boolean a, final boolean b) { return a && b; }
@Override
public Object logicalOr(final Object a, final Object b) {
if (isBool(a) && isBool(b)) return logicalOr(bool(a), bool(b));
return null;
}
public boolean logicalOr(final boolean a, final boolean b) { return a || b; }
// -- Helper methods - type matching --
private boolean is(final Object o, final Class> c) {
return c.isInstance(value(o));
}
private boolean isBool(final Object o) { return is(o, Boolean.class); }
private boolean isStr(final Object o) { return is(o, String.class); }
private boolean isB(final Object o) { return is(o, Byte.class); }
private boolean isS(final Object o) { return is(o, Short.class) || isB(o); }
private boolean isI(final Object o) { return is(o, Integer.class) || isS(o); }
private boolean isL(final Object o) { return is(o, Long.class) || isI(o); }
// NB: Java allows assignment of all integer primitive types to float!
private boolean isF(final Object o) { return is(o, Float.class) || isL(o); }
private boolean isD(final Object o) { return is(o, Double.class) || isF(o); }
private boolean isBI(final Object o) { return is(o, BigInteger.class) || isL(o); }
private boolean isBD(final Object o) { return is(o, BigDecimal.class) || isBI(o) || isD(o); }
// -- Helper methods - type coercion --
/** Casts the given token to the specified class, or null if incompatible. */
private T cast(final Object token, final Class type) {
if (type.isInstance(token)) {
@SuppressWarnings("unchecked")
final T result = (T) token;
return result;
}
return null;
}
/** Coerces the given token to a boolean. */
private boolean bool(final Object token) {
final Boolean b = cast(value(token), Boolean.class);
return b != null ? b : Boolean.valueOf(token.toString());
}
/** Coerces the given token to a string. */
private String str(final Object token) {
final String s = cast(value(token), String.class);
return s != null ? s : token.toString();
}
/** Coerces the given token to a number. */
private Number num(final Object token) {
final Number n = cast(value(token), Number.class);
return n != null ? n : Literals.parseNumber(token.toString());
}
private int i(final Object o) { return num(o).intValue(); }
private long l(final Object o) { return num(o).longValue(); }
private float f(final Object o) { return num(o).floatValue(); }
private double d(final Object o) { return num(o).doubleValue(); }
private BigInteger bi(final Object o) {
final BigInteger bi = cast(o, BigInteger.class);
return bi != null ? bi : new BigInteger("" + value(o));
}
private BigDecimal bd(final Object o) {
final BigDecimal bd = cast(o, BigDecimal.class);
return bd != null ? bd : new BigDecimal("" + value(o));
}
private Object listElement(final Object a, final Object b) {
final Object value;
try {
value = value(a);
}
catch (final IllegalArgumentException exc) {
return null;
}
if (!(value instanceof List)) return null;
final List> list = (List>) value;
if (!(b instanceof List)) return null;
final List> indices = (List>) b;
if (indices.size() != 1) return null; // not a 1-D access
return list.get(i(indices.get(0)));
}
/** Executes built-in functions. */
private Object callFunction(final String name, final Object b) {
if (name.equals("postfix") && b instanceof String) {
return getParser().parsePostfix((String) b);
}
if (name.equals("tree") && b instanceof String) {
return getParser().parseTree((String) b);
}
return null;
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/Evaluator.java 0000664 0000000 0000000 00000010074 13103137730 0027570 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import java.util.LinkedList;
import java.util.Map;
import org.scijava.parse.ExpressionParser;
import org.scijava.parse.SyntaxTree;
import org.scijava.parse.Variable;
/**
* Interface for expression evaluators.
*
* @author Curtis Rueden
*/
public interface Evaluator {
/** Gets the parser used when evaluating expressions. */
ExpressionParser getParser();
/**
* Gets whether the evaluator is operating in strict mode.
*
* @see #setStrict(boolean)
*/
boolean isStrict();
/**
* Sets whether the evaluator is operating in strict mode. Evaluators operate
* in strict mode by default.
*
* When evaluating strictly, usage of an unassigned variable token in a place
* where its value is needed will generate an {@link IllegalArgumentException}
* with an "Unknown variable" message; in non-strict mode, such a variable
* will instead be resolved to an object of type {@link Unresolved} with the
* same name as the original variable.
*
*
* In cases such as assignment, this may be sufficient to complete the
* evaluation; for example, the expression {@code foo=bar} will complete
* successfully in non-strict mode, with the variable {@code foo} containing
* an object of type {@link Unresolved} and token value {@code "bar"}. But in
* cases where the unresolved value is needed as an input for additional
* operations, the evaluation may still ultimately fail of the operation in
* question is not defined for unresolved values. For example, the
* {@link DefaultEvaluator} will fail with an "Unsupported binary operator"
* exception when given the expression {@code foo+bar}, since {@code foo} and
* {@code bar} are unresolved variables, and the {@code +} operator cannot
* handle such objects.
*
*/
void setStrict(boolean strict);
/** Evaluates the given infix expression, returning the result. */
Object evaluate(final String expression);
/** Evaluates the given postfix token queue, returning the result. */
Object evaluate(final LinkedList queue);
/** Evaluates the given syntax tree, returning the result. */
Object evaluate(final SyntaxTree syntaxTree);
/**
* Gets the value of the given token. For variables, returns the value of the
* variable, throwing an exception if the variable is not set. For literals,
* returns the token itself.
*/
Object value(Object token);
/** Gets the value of the given variable. */
Object get(Variable v);
/** Sets the value of the given variable. */
void set(Variable v, Object value);
/** Assigns variables en masse. */
void setAll(Map extends String, ? extends Object> map);
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/EvaluatorConsole.java 0000664 0000000 0000000 00000007042 13103137730 0031114 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.scijava.parse.Tokens;
/**
* A simple console-driven expression evaluator.
*
* @author Curtis Rueden
*/
public class EvaluatorConsole {
private static final String PROMPT = "> ";
private final Evaluator evaluator;
public EvaluatorConsole() {
this(new DefaultEvaluator());
}
public EvaluatorConsole(final Evaluator evaluator) {
this.evaluator = evaluator;
}
// -- EvaluatorConsole methods --
public void showConsole() throws IOException {
showConsole(new BufferedReader(new InputStreamReader(System.in)));
}
public void showConsole(final BufferedReader in) throws IOException {
while (true) {
print(PROMPT);
final String line = in.readLine();
if (line == null) break;
try {
final Object result = evaluator.evaluate(line);
if (result != null) printResult(result);
}
catch (final IllegalArgumentException exc) {
final String msg = exc.getMessage();
if (msg == null) throw exc; // Probably a serious exception.
final Matcher m = Pattern.compile(".* at index (\\d+)").matcher(msg);
if (m.matches()) {
// Show a helpful caret to indicate where the problem is.
final int index = Integer.parseInt(m.group(1));
println(caret(index));
}
println(msg);
}
}
}
private void printResult(final Object o) {
if (o instanceof List) {
for (final Object item : (List>) o) {
printResult(item);
}
}
else if (Tokens.isVariable(o)) {
println(o + " = " + evaluator.value(o));
}
else println(o);
}
public void print(final Object o) {
System.out.print(o);
}
public void println(final Object o) {
System.out.println(o);
}
// -- Helper methods --
private static String caret(final int index) {
final StringBuilder sb = new StringBuilder();
final int count = PROMPT.length() + index;
for (int i = 0; i < count; i++) {
sb.append(" ");
}
sb.append("^");
return sb.toString();
}
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/StackEvaluator.java 0000664 0000000 0000000 00000003534 13103137730 0030561 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import java.util.Deque;
import org.scijava.parse.Operator;
/**
* Interface for stack-based expression evaluators.
*
* @author Curtis Rueden
*/
public interface StackEvaluator extends Evaluator {
/**
* Executes the given {@link Operator operation} with the specified value
* stack.
*/
Object execute(final Operator op, final Deque stack);
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/StandardEvaluator.java 0000664 0000000 0000000 00000016606 13103137730 0031260 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import org.scijava.parse.Function;
import org.scijava.parse.Operators;
/**
* Interface for expression evaluators which support the {@link Operators
* standard operators}.
*
* @author Curtis Rueden
*/
public interface StandardEvaluator extends Evaluator {
// -- function --
/** Applies the {@link Function} operator. */
Object function(Object a, Object b);
// -- dot --
/** Applies the {@link Operators#DOT} operator. */
Object dot(Object a, Object b);
// -- groups --
/** Applies the {@link Operators#PARENS} operator. */
Object parens(Object[] args);
/** Applies the {@link Operators#BRACKETS} operator. */
Object brackets(Object[] args);
/** Applies the {@link Operators#BRACES} operator. */
Object braces(Object[] args);
// -- transpose, power --
/** Applies the {@link Operators#TRANSPOSE} operator. */
Object transpose(Object a);
/** Applies the {@link Operators#DOT_TRANSPOSE} operator. */
Object dotTranspose(Object a);
/** Applies the {@link Operators#POW} operator. */
Object pow(Object a, Object b);
/** Applies the {@link Operators#DOT_POW} operator. */
Object dotPow(Object a, Object b);
// -- postfix --
/** Applies the {@link Operators#POST_INC} operator. */
Object postInc(Object a);
/** Applies the {@link Operators#POST_DEC} operator. */
Object postDec(Object a);
// -- unary --
/** Applies the {@link Operators#PRE_INC} operator. */
Object preInc(Object a);
/** Applies the {@link Operators#PRE_DEC} operator. */
Object preDec(Object a);
/** Applies the {@link Operators#POS} operator. */
Object pos(Object a);
/** Applies the {@link Operators#NEG} operator. */
Object neg(Object a);
/** Applies the {@link Operators#COMPLEMENT} operator. */
Object complement(Object a);
/** Applies the {@link Operators#NOT} operator. */
Object not(Object a);
// -- multiplicative --
/** Applies the {@link Operators#MUL} operator. */
Object mul(Object a, Object b);
/** Applies the {@link Operators#DIV} operator. */
Object div(Object a, Object b);
/** Applies the {@link Operators#MOD} operator. */
Object mod(Object a, Object b);
/** Applies the {@link Operators#RIGHT_DIV} operator. */
Object rightDiv(Object a, Object b);
/** Applies the {@link Operators#DOT_MUL} operator. */
Object dotMul(Object a, Object b);
/** Applies the {@link Operators#DOT_DIV} operator. */
Object dotDiv(Object a, Object b);
/** Applies the {@link Operators#DOT_RIGHT_DIV} operator. */
Object dotRightDiv(Object a, Object b);
// -- additive --
/** Applies the {@link Operators#ADD} operator. */
Object add(Object a, Object b);
/** Applies the {@link Operators#SUB} operator. */
Object sub(Object a, Object b);
// -- shift --
/** Applies the {@link Operators#LEFT_SHIFT} operator. */
Object leftShift(Object a, Object b);
/** Applies the {@link Operators#RIGHT_SHIFT} operator. */
Object rightShift(Object a, Object b);
/** Applies the {@link Operators#UNSIGNED_RIGHT_SHIFT} operator. */
Object unsignedRightShift(Object a, Object b);
// -- colon --
/** Applies the {@link Operators#COLON} operator. */
Object colon(Object a, Object b);
// -- relational --
/** Applies the {@link Operators#LESS_THAN} operator. */
Object lessThan(Object a, Object b);
/** Applies the {@link Operators#GREATER_THAN} operator. */
Object greaterThan(Object a, Object b);
/** Applies the {@link Operators#LESS_THAN_OR_EQUAL} operator. */
Object lessThanOrEqual(Object a, Object b);
/** Applies the {@link Operators#GREATER_THAN_OR_EQUAL} operator. */
Object greaterThanOrEqual(Object a, Object b);
/** Applies the {@link Operators#INSTANCEOF} operator. */
Object instanceOf(Object a, Object b);
// -- equality --
/** Applies the {@link Operators#EQUAL} operator. */
Object equal(Object a, Object b);
/** Applies the {@link Operators#NOT_EQUAL} operator. */
Object notEqual(Object a, Object b);
// -- bitwise --
/** Applies the {@link Operators#BITWISE_AND} operator. */
Object bitwiseAnd(Object a, Object b);
/** Applies the {@link Operators#BITWISE_OR} operator. */
Object bitwiseOr(Object a, Object b);
// -- logical --
/** Applies the {@link Operators#LOGICAL_AND} operator. */
Object logicalAnd(Object a, Object b);
/** Applies the {@link Operators#LOGICAL_OR} operator. */
Object logicalOr(Object a, Object b);
// -- assignment --
/** Applies the {@link Operators#ASSIGN} operator. */
Object assign(Object a, Object b);
/** Applies the {@link Operators#POW_ASSIGN} operator. */
Object powAssign(Object a, Object b);
/** Applies the {@link Operators#DOT_POW_ASSIGN} operator. */
Object dotPowAssign(Object a, Object b);
/** Applies the {@link Operators#MUL_ASSIGN} operator. */
Object mulAssign(Object a, Object b);
/** Applies the {@link Operators#DIV_ASSIGN} operator. */
Object divAssign(Object a, Object b);
/** Applies the {@link Operators#MOD_ASSIGN} operator. */
Object modAssign(Object a, Object b);
/** Applies the {@link Operators#RIGHT_DIV_ASSIGN} operator. */
Object rightDivAssign(Object a, Object b);
/** Applies the {@link Operators#DOT_DIV_ASSIGN} operator. */
Object dotDivAssign(Object a, Object b);
/** Applies the {@link Operators#DOT_RIGHT_DIV_ASSIGN} operator. */
Object dotRightDivAssign(Object a, Object b);
/** Applies the {@link Operators#ADD_ASSIGN} operator. */
Object addAssign(Object a, Object b);
/** Applies the {@link Operators#SUB_ASSIGN} operator. */
Object subAssign(Object a, Object b);
/** Applies the {@link Operators#AND_ASSIGN} operator. */
Object andAssign(Object a, Object b);
/** Applies the {@link Operators#OR_ASSIGN} operator. */
Object orAssign(Object a, Object b);
/** Applies the {@link Operators#LEFT_SHIFT_ASSIGN} operator. */
Object leftShiftAssign(Object a, Object b);
/** Applies the {@link Operators#RIGHT_SHIFT_ASSIGN} operator. */
Object rightShiftAssign(Object a, Object b);
/** Applies the {@link Operators#UNSIGNED_RIGHT_SHIFT_ASSIGN} operator. */
Object unsignedRightShiftAssign(Object a, Object b);
}
parsington-parsington-1.0.1/src/main/java/org/scijava/parse/eval/Unresolved.java 0000664 0000000 0000000 00000003352 13103137730 0027755 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import org.scijava.parse.Token;
/**
* An unresolved/unknown variable value.
*
* @author Curtis Rueden
* @see Evaluator#setStrict(boolean)
*/
public class Unresolved extends Token {
public Unresolved(final String token) {
super(token);
}
}
parsington-parsington-1.0.1/src/test/ 0000775 0000000 0000000 00000000000 13103137730 0017623 5 ustar 00root root 0000000 0000000 parsington-parsington-1.0.1/src/test/java/ 0000775 0000000 0000000 00000000000 13103137730 0020544 5 ustar 00root root 0000000 0000000 parsington-parsington-1.0.1/src/test/java/org/ 0000775 0000000 0000000 00000000000 13103137730 0021333 5 ustar 00root root 0000000 0000000 parsington-parsington-1.0.1/src/test/java/org/scijava/ 0000775 0000000 0000000 00000000000 13103137730 0022753 5 ustar 00root root 0000000 0000000 parsington-parsington-1.0.1/src/test/java/org/scijava/parse/ 0000775 0000000 0000000 00000000000 13103137730 0024065 5 ustar 00root root 0000000 0000000 parsington-parsington-1.0.1/src/test/java/org/scijava/parse/AbstractTest.java 0000664 0000000 0000000 00000006637 13103137730 0027347 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.List;
/**
* Base class for unit test classes.
*
* @author Curtis Rueden
*/
public class AbstractTest {
// -- Helper methods --
protected void assertString(final String expected, final Object actual) {
assertNotNull(actual);
assertSame(expected.getClass(), actual.getClass());
assertEquals(expected, actual);
}
protected void assertNumber(final Number expected, final Object actual) {
assertNotNull(actual);
assertSame(expected.getClass(), actual.getClass());
assertEquals(expected, actual);
}
protected void assertGroup(final Group expected, final int arity,
final Object token)
{
assertInstance(token, Group.class);
final Group group = (Group) token;
assertEquals(arity, group.getArity());
assertTrue(expected.matches(group));
}
protected void assertFunction(final Object token) {
assertInstance(token, Function.class);
}
protected void assertVariable(final String expected, final Object token) {
assertInstance(token, Variable.class);
assertEquals(expected, ((Variable) token).getToken());
}
protected void assertInstance(final Object token, final Class> c) {
assertNotNull(token);
assertTrue(token.getClass().getName(), c.isInstance(token));
}
protected void assertCount(final int expected, final SyntaxTree tree) {
assertNotNull(tree);
assertEquals(expected, tree.count());
}
protected void assertToken(final String expected, final Object token) {
assertNotNull(token);
assertEquals(expected, token.toString());
}
protected void assertSameLists(final List> expected, final List> actual) {
assertNotNull(actual);
assertEquals(expected.size(), actual.size());
for (int i = 0; i < expected.size(); i++) {
assertSame("Non-matching index: " + i, expected.get(i), actual.get(i));
}
}
}
parsington-parsington-1.0.1/src/test/java/org/scijava/parse/ExpressionParserTest.java 0000664 0000000 0000000 00000075747 13103137730 0031130 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.util.LinkedList;
import java.util.List;
import org.junit.Test;
import org.scijava.parse.Operator.Associativity;
/**
* Tests {@link ExpressionParser}.
*
* @author Curtis Rueden
*/
public class ExpressionParserTest extends AbstractTest {
@Test
public void testStrings() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("'hello'*\"world\"");
// "hello" "world" *
assertNotNull(queue);
assertEquals(3, queue.size());
assertString("hello", queue.pop());
assertString("world", queue.pop());
assertSame(Operators.MUL, queue.pop());
}
@Test
public void testNumbers() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("1.1+2L+3f+4-+5d-6");
// 1.1 2L + 3f + 4 + +5d - 6 -
assertNotNull(queue);
assertEquals(11, queue.size());
assertNumber(1.1, queue.pop());
assertNumber(2L, queue.pop());
assertSame(Operators.ADD, queue.pop());
assertNumber(3f, queue.pop());
assertSame(Operators.ADD, queue.pop());
assertNumber(4, queue.pop());
assertSame(Operators.ADD, queue.pop());
assertNumber(+5d, queue.pop());
assertSame(Operators.SUB, queue.pop());
assertNumber(6, queue.pop());
assertSame(Operators.SUB, queue.pop());
}
/** Tests each individual standard operator. */
@Test
public void testOperatorsIndividual() {
final ExpressionParser p = new ExpressionParser();
assertBinary(p, "a", Operators.DOT, "b", "a.b");
assertUnary(p, "a", Operators.TRANSPOSE, "a'");
assertUnary(p, "a", Operators.DOT_TRANSPOSE, "a.'");
assertBinary(p, "a", Operators.POW, "b", "a^b");
assertBinary(p, "a", Operators.DOT_POW, "b", "a.^b");
assertUnary(p, "a", Operators.PRE_INC, "++a");
assertUnary(p, "a", Operators.POST_INC, "a++");
assertUnary(p, "a", Operators.PRE_DEC, "--a");
assertUnary(p, "a", Operators.POST_DEC, "a--");
assertUnary(p, "a", Operators.POS, "+a");
assertUnary(p, "a", Operators.NEG, "-a");
assertUnary(p, "a", Operators.COMPLEMENT, "~a");
assertUnary(p, "a", Operators.NOT, "!a");
assertBinary(p, "a", Operators.MUL, "b", "a*b");
assertBinary(p, "a", Operators.DIV, "b", "a/b");
assertBinary(p, "a", Operators.MOD, "b", "a%b");
assertBinary(p, "a", Operators.ADD, "b", "a+b");
assertBinary(p, "a", Operators.SUB, "b", "a-b");
assertBinary(p, "a", Operators.LEFT_SHIFT, "b", "a<>b");
assertBinary(p, "a", Operators.UNSIGNED_RIGHT_SHIFT, "b", "a>>>b");
assertBinary(p, "a", Operators.COLON, "b", "a:b");
assertBinary(p, "a", Operators.LESS_THAN, "b", "ab");
assertBinary(p, "a", Operators.LESS_THAN_OR_EQUAL, "b", "a<=b");
assertBinary(p, "a", Operators.GREATER_THAN_OR_EQUAL, "b", "a>=b");
assertBinary(p, "a", Operators.INSTANCEOF, "b", "a instanceof b");
assertBinary(p, "a", Operators.EQUAL, "b", "a==b");
assertBinary(p, "a", Operators.NOT_EQUAL, "b", "a!=b");
assertBinary(p, "a", Operators.BITWISE_AND, "b", "a&b");
assertBinary(p, "a", Operators.BITWISE_OR, "b", "a|b");
assertBinary(p, "a", Operators.LOGICAL_AND, "b", "a&&b");
assertBinary(p, "a", Operators.LOGICAL_OR, "b", "a||b");
assertBinary(p, "a", Operators.ASSIGN, "b", "a=b");
assertBinary(p, "a", Operators.POW_ASSIGN, "b", "a^=b");
assertBinary(p, "a", Operators.DOT_POW_ASSIGN, "b", "a.^=b");
assertBinary(p, "a", Operators.MUL_ASSIGN, "b", "a*=b");
assertBinary(p, "a", Operators.DIV_ASSIGN, "b", "a/=b");
assertBinary(p, "a", Operators.MOD_ASSIGN, "b", "a%=b");
assertBinary(p, "a", Operators.RIGHT_DIV_ASSIGN, "b", "a\\=b");
assertBinary(p, "a", Operators.DOT_DIV_ASSIGN, "b", "a./=b");
assertBinary(p, "a", Operators.DOT_RIGHT_DIV_ASSIGN, "b", "a.\\=b");
assertBinary(p, "a", Operators.ADD_ASSIGN, "b", "a+=b");
assertBinary(p, "a", Operators.SUB_ASSIGN, "b", "a-=b");
assertBinary(p, "a", Operators.AND_ASSIGN, "b", "a&=b");
assertBinary(p, "a", Operators.OR_ASSIGN, "b", "a|=b");
assertBinary(p, "a", Operators.LEFT_SHIFT_ASSIGN, "b", "a<<=b");
assertBinary(p, "a", Operators.RIGHT_SHIFT_ASSIGN, "b", "a>>=b");
assertBinary(p, "a", Operators.UNSIGNED_RIGHT_SHIFT_ASSIGN, "b", "a>>>=b");
}
/** Tests all the numeric operators in a single expression. */
@Test
public void testMathOperators() {
final String expression =
"(a|=b)|(c&=d)&(e>>>=f)>>>(g>>=h)>>(i<<=j)<<(k-=l)-(m+=n)"
+ "+(o.\\=p).\\(q./=r)./(s\\=t)\\(u%=v)%(w/=x)/(y*=z)"
+ "*(aa.^=bb).^(cc^=dd)^f(~ee--,-ff++,+--gg',++hh.')";
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix(expression);
// a b |= (1) c d &= (1) e f >>>= (1) g h >>= (1) >>> i j <<= (1) >> k l
// -= (1) m n += (1) - o p .\= (1) q r ./= (1) .\ s t \= (1) ./ u v %=
// (1) \ w x /= (1) % y z *= (1) / aa bb .^= (1) cc dd ^= (1) f ee -- ~
// ff ++ - gg ' -- + hh .' ++ (4) ^ .^ * + << & |
assertNotNull(queue);
assertEquals(91, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.OR_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("c", queue.pop());
assertVariable("d", queue.pop());
assertSame(Operators.AND_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("e", queue.pop());
assertVariable("f", queue.pop());
assertSame(Operators.UNSIGNED_RIGHT_SHIFT_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("g", queue.pop());
assertVariable("h", queue.pop());
assertSame(Operators.RIGHT_SHIFT_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.UNSIGNED_RIGHT_SHIFT, queue.pop());
assertVariable("i", queue.pop());
assertVariable("j", queue.pop());
assertSame(Operators.LEFT_SHIFT_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.RIGHT_SHIFT, queue.pop());
assertVariable("k", queue.pop());
assertVariable("l", queue.pop());
assertSame(Operators.SUB_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("m", queue.pop());
assertVariable("n", queue.pop());
assertSame(Operators.ADD_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.SUB, queue.pop());
assertVariable("o", queue.pop());
assertVariable("p", queue.pop());
assertSame(Operators.DOT_RIGHT_DIV_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("q", queue.pop());
assertVariable("r", queue.pop());
assertSame(Operators.DOT_DIV_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.DOT_RIGHT_DIV, queue.pop());
assertVariable("s", queue.pop());
assertVariable("t", queue.pop());
assertSame(Operators.RIGHT_DIV_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.DOT_DIV, queue.pop());
assertVariable("u", queue.pop());
assertVariable("v", queue.pop());
assertSame(Operators.MOD_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.RIGHT_DIV, queue.pop());
assertVariable("w", queue.pop());
assertVariable("x", queue.pop());
assertSame(Operators.DIV_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.MOD, queue.pop());
assertVariable("y", queue.pop());
assertVariable("z", queue.pop());
assertSame(Operators.MUL_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.DIV, queue.pop());
assertVariable("aa", queue.pop());
assertVariable("bb", queue.pop());
assertSame(Operators.DOT_POW_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("cc", queue.pop());
assertVariable("dd", queue.pop());
assertSame(Operators.POW_ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("f", queue.pop());
assertVariable("ee", queue.pop());
assertSame(Operators.POST_DEC, queue.pop());
assertSame(Operators.COMPLEMENT, queue.pop());
assertVariable("ff", queue.pop());
assertSame(Operators.POST_INC, queue.pop());
assertSame(Operators.NEG, queue.pop());
assertVariable("gg", queue.pop());
assertSame(Operators.TRANSPOSE, queue.pop());
assertSame(Operators.PRE_DEC, queue.pop());
assertSame(Operators.POS, queue.pop());
assertVariable("hh", queue.pop());
assertSame(Operators.DOT_TRANSPOSE, queue.pop());
assertSame(Operators.PRE_INC, queue.pop());
assertGroup(Operators.PARENS, 4, queue.pop());
assertFunction(queue.pop());
assertSame(Operators.POW, queue.pop());
assertSame(Operators.DOT_POW, queue.pop());
assertSame(Operators.MUL, queue.pop());
assertSame(Operators.ADD, queue.pop());
assertSame(Operators.LEFT_SHIFT, queue.pop());
assertSame(Operators.BITWISE_AND, queue.pop());
assertSame(Operators.BITWISE_OR, queue.pop());
}
/** Tests all the boolean operators in a single expression. */
public void testLogicOperators() {
final String expression =
"ad && e<=f || g>=h && i==j || k!=l && m instanceof n || !o";
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix(expression);
// a b |= c d &= e f >>>= g h >>= >>> i j <<= >> k l -= m n += - o p .\=
// q r ./= .\ s t \= ./ u v %= \ w x /= % y z *= / aa bb .^= cc dd ^= ee
// -- ~ ff ++ - gg ' -- + hh .' ++ f ^ .^ * + << & |
assertNotNull(queue);
assertEquals(30, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.LESS_THAN, queue.pop());
assertVariable("c", queue.pop());
assertVariable("d", queue.pop());
assertSame(Operators.GREATER_THAN, queue.pop());
assertVariable("e", queue.pop());
assertVariable("f", queue.pop());
assertSame(Operators.LESS_THAN_OR_EQUAL, queue.pop());
assertSame(Operators.LOGICAL_AND, queue.pop());
assertSame(Operators.LOGICAL_OR, queue.pop());
assertVariable("g", queue.pop());
assertVariable("h", queue.pop());
assertSame(Operators.GREATER_THAN_OR_EQUAL, queue.pop());
assertVariable("i", queue.pop());
assertVariable("j", queue.pop());
assertSame(Operators.EQUAL, queue.pop());
assertSame(Operators.LOGICAL_AND, queue.pop());
assertSame(Operators.LOGICAL_OR, queue.pop());
assertVariable("k", queue.pop());
assertVariable("l", queue.pop());
assertSame(Operators.NOT_EQUAL, queue.pop());
assertVariable("m", queue.pop());
assertVariable("n", queue.pop());
assertSame(Operators.INSTANCEOF, queue.pop());
assertSame(Operators.LOGICAL_AND, queue.pop());
assertSame(Operators.LOGICAL_OR, queue.pop());
assertVariable("0", queue.pop());
assertSame(Operators.NOT, queue.pop());
assertSame(Operators.LOGICAL_OR, queue.pop());
}
@Test
public void testUnaryOperators1() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("-+a");
// a + -
assertNotNull(queue);
assertEquals(3, queue.size());
assertVariable("a", queue.pop());
assertSame(Operators.POS, queue.pop());
assertSame(Operators.NEG, queue.pop());
}
@Test
public void testUnaryOperators2() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a+-b");
// a b - +
assertNotNull(queue);
assertEquals(4, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.NEG, queue.pop());
assertSame(Operators.ADD, queue.pop());
}
@Test
public void testUnaryOperators3() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a-+-b");
// a b - + -
assertNotNull(queue);
assertEquals(5, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.NEG, queue.pop());
assertSame(Operators.POS, queue.pop());
assertSame(Operators.SUB, queue.pop());
}
@Test
public void testUnaryOperators4() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("-+a-+-b");
// a + - b - + -
assertNotNull(queue);
assertEquals(7, queue.size());
assertVariable("a", queue.pop());
assertSame(Operators.POS, queue.pop());
assertSame(Operators.NEG, queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.NEG, queue.pop());
assertSame(Operators.POS, queue.pop());
assertSame(Operators.SUB, queue.pop());
}
@Test
public void testNullaryGroup() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("()");
// (0)
assertNotNull(queue);
assertEquals(1, queue.size());
assertGroup(Operators.PARENS, 0, queue.pop());
}
@Test
public void testUnaryGroup() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("(a)");
// a (1)
assertNotNull(queue);
assertEquals(2, queue.size());
assertVariable("a", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
}
@Test
public void testNestedGroups() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("(())");
// (0) (1)
assertNotNull(queue);
assertEquals(2, queue.size());
assertGroup(Operators.PARENS, 0, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
}
@Test
public void testNullaryFunction() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("f()");
// f (0)
assertNotNull(queue);
assertEquals(3, queue.size());
assertVariable("f", queue.pop());
assertGroup(Operators.PARENS, 0, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testUnaryFunction() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("f(a)");
// f a (1)
assertNotNull(queue);
assertVariable("f", queue.pop());
assertVariable("a", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testBinaryFunction() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("f(a,b)");
// f a b (2)
assertNotNull(queue);
assertEquals(5, queue.size());
assertVariable("f", queue.pop());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertGroup(Operators.PARENS, 2, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testTernaryFunction() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("f(a,b,c)");
// f a b c (3)
assertNotNull(queue);
assertEquals(6, queue.size());
assertVariable("f", queue.pop());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.PARENS, 3, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testNestedFunctions() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue =
parser.parsePostfix("f(g(),a,h(b),i(c,d))");
// f g (0) a h b (1) i c d (2) (4)
assertNotNull(queue);
assertEquals(16, queue.size());
assertVariable("f", queue.pop());
assertVariable("g", queue.pop());
assertGroup(Operators.PARENS, 0, queue.pop());
assertFunction(queue.pop());
assertVariable("a", queue.pop());
assertVariable("h", queue.pop());
assertVariable("b", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertFunction(queue.pop());
assertVariable("i", queue.pop());
assertVariable("c", queue.pop());
assertVariable("d", queue.pop());
assertGroup(Operators.PARENS, 2, queue.pop());
assertFunction(queue.pop());
assertGroup(Operators.PARENS, 4, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testFunctionParens1() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a.b(c)");
// a b . c (1)
assertNotNull(queue);
assertEquals(6, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.DOT, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testFunctionParens2() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a(b).c");
// a b (1) c .
assertNotNull(queue);
assertEquals(6, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertFunction(queue.pop());
assertVariable("c", queue.pop());
assertSame(Operators.DOT, queue.pop());
}
@Test
public void testFunctionParens3() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a.b(c).d");
// a b . c (1) d .
assertNotNull(queue);
assertEquals(8, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.DOT, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertFunction(queue.pop());
assertVariable("d", queue.pop());
assertSame(Operators.DOT, queue.pop());
}
@Test
public void testFunctionParens4() {
final List operators = Operators.standardList();
final Operator atOp = new Operator("@", 2, Associativity.LEFT, 100);
operators.add(atOp);
final ExpressionParser parser = new ExpressionParser(operators);
final LinkedList queue = parser.parsePostfix("a@b(c)@d");
// a b @ c (1) d @
assertNotNull(queue);
assertEquals(8, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(atOp, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("d", queue.pop());
assertSame(atOp, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testFunctionBrackets1() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a.b[c]");
// a b . c [1]
assertNotNull(queue);
assertEquals(6, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.DOT, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.BRACKETS, 1, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testFunctionBrackets2() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a[b].c");
// a b [1] c .
assertNotNull(queue);
assertEquals(6, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertGroup(Operators.BRACKETS, 1, queue.pop());
assertFunction(queue.pop());
assertVariable("c", queue.pop());
assertSame(Operators.DOT, queue.pop());
}
@Test
public void testFunctionBrackets3() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a.b[c].d");
// a b . c [1] d .
assertNotNull(queue);
assertEquals(8, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.DOT, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.BRACKETS, 1, queue.pop());
assertFunction(queue.pop());
assertVariable("d", queue.pop());
assertSame(Operators.DOT, queue.pop());
}
@Test
public void testFunctionBrackets4() {
final List operators = Operators.standardList();
final Operator atOp = new Operator("@", 2, Associativity.LEFT, 100);
operators.add(atOp);
final ExpressionParser parser = new ExpressionParser(operators);
final LinkedList queue = parser.parsePostfix("a@b[c]@d");
// a b @ c [1] d @
assertNotNull(queue);
assertEquals(8, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(atOp, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.BRACKETS, 1, queue.pop());
assertVariable("d", queue.pop());
assertSame(atOp, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testFunctionBraces1() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a.b{c}");
// a b . c {1}
assertNotNull(queue);
assertEquals(6, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.DOT, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.BRACES, 1, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testFunctionBraces2() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a{b}.c");
// a b {1} c .
assertNotNull(queue);
assertEquals(6, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertGroup(Operators.BRACES, 1, queue.pop());
assertFunction(queue.pop());
assertVariable("c", queue.pop());
assertSame(Operators.DOT, queue.pop());
}
@Test
public void testFunctionBraces3() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a.b{c}.d");
// a b . c {1} d .
assertNotNull(queue);
assertEquals(8, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.DOT, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.BRACES, 1, queue.pop());
assertFunction(queue.pop());
assertVariable("d", queue.pop());
assertSame(Operators.DOT, queue.pop());
}
@Test
public void testFunctionBraces4() {
final List operators = Operators.standardList();
final Operator atOp = new Operator("@", 2, Associativity.LEFT, 100);
operators.add(atOp);
final ExpressionParser parser = new ExpressionParser(operators);
final LinkedList queue = parser.parsePostfix("a@b{c}@d");
// a b @ c {1} d @
assertNotNull(queue);
assertEquals(8, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(atOp, queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.BRACES, 1, queue.pop());
assertVariable("d", queue.pop());
assertSame(atOp, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testMixedFunctions() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a[b(c), d{3:4}, 2]");
// a b c (1) d 3 4 : {1} 2 [3]
assertNotNull(queue);
assertEquals(14, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertVariable("c", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertFunction(queue.pop());
assertVariable("d", queue.pop());
assertNumber(3, queue.pop());
assertNumber(4, queue.pop());
assertSame(Operators.COLON, queue.pop());
assertGroup(Operators.BRACES, 1, queue.pop());
assertFunction(queue.pop());
assertNumber(2, queue.pop());
assertGroup(Operators.BRACKETS, 3, queue.pop());
assertFunction(queue.pop());
}
@Test
public void testParameterSyntax() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix(
"(choices={'quick brown fox', 'lazy dog'}, persist=false, value=5)");
// choices 'quick brown fox' 'lazy dog' {2} = persist false = value 5 = (3)
assertNotNull(queue);
assertVariable("choices", queue.pop());
assertString("quick brown fox", queue.pop());
assertString("lazy dog", queue.pop());
assertGroup(Operators.BRACES, 2, queue.pop());
assertSame(Operators.ASSIGN, queue.pop());
assertVariable("persist", queue.pop());
assertSame(false, queue.pop());
assertSame(Operators.ASSIGN, queue.pop());
assertVariable("value", queue.pop());
assertNumber(5, queue.pop());
assertSame(Operators.ASSIGN, queue.pop());
assertGroup(Operators.PARENS, 3, queue.pop());
}
@Test
public void testNonFunctionGroup() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("f+(g)");
// f g (1) +
assertNotNull(queue);
assertEquals(4, queue.size());
assertVariable("f", queue.pop());
assertVariable("g", queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.ADD, queue.pop());
}
@Test
public void testOperatorPrecedence() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("a+b*c^d.^e'");
// a b c d e .^ ^ ' * +
assertNotNull(queue);
assertEquals(10, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertVariable("c", queue.pop());
assertVariable("d", queue.pop());
assertVariable("e", queue.pop());
assertSame(Operators.DOT_POW, queue.pop());
assertSame(Operators.POW, queue.pop());
assertSame(Operators.TRANSPOSE, queue.pop());
assertSame(Operators.MUL, queue.pop());
assertSame(Operators.ADD, queue.pop());
}
@Test
public void testOperatorAssociativity() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue = parser.parsePostfix("(a/b/c)+(a^b^c)");
// a b / c / (1) a b c ^ ^ (1) +
assertNotNull(queue);
assertEquals(13, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.DIV, queue.pop());
assertVariable("c", queue.pop());
assertSame(Operators.DIV, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertVariable("c", queue.pop());
assertSame(Operators.POW, queue.pop());
assertSame(Operators.POW, queue.pop());
assertGroup(Operators.PARENS, 1, queue.pop());
assertSame(Operators.ADD, queue.pop());
}
/** Tests multiple semicolon-separated statements. */
@Test
public void testMultipleStatements() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue =
parser.parsePostfix("a=1 ; b=2 ; c=3");
// a 1 = b 2 = c 3 =
assertNotNull(queue);
assertEquals(9, queue.size());
assertVariable("a", queue.pop());
assertNumber(1, queue.pop());
assertSame(Operators.ASSIGN, queue.pop());
assertVariable("b", queue.pop());
assertNumber(2, queue.pop());
assertSame(Operators.ASSIGN, queue.pop());
assertVariable("c", queue.pop());
assertNumber(3, queue.pop());
assertSame(Operators.ASSIGN, queue.pop());
}
/** A more complex test of {@link ExpressionParser#parsePostfix}. */
@Test
public void testParsePostfix() {
final ExpressionParser parser = new ExpressionParser();
final LinkedList queue =
parser.parsePostfix("a*b-c*a/func(quick,brown,fox)^foo^bar");
// a b * c a * func quick brown fox (3) foo bar ^ ^ / -
assertNotNull(queue);
assertEquals(18, queue.size());
assertVariable("a", queue.pop());
assertVariable("b", queue.pop());
assertSame(Operators.MUL, queue.pop());
assertVariable("c", queue.pop());
assertVariable("a", queue.pop());
assertSame(Operators.MUL, queue.pop());
assertVariable("func", queue.pop());
assertVariable("quick", queue.pop());
assertVariable("brown", queue.pop());
assertVariable("fox", queue.pop());
assertGroup(Operators.PARENS, 3, queue.pop());
assertFunction(queue.pop());
assertVariable("foo", queue.pop());
assertVariable("bar", queue.pop());
assertSame(Operators.POW, queue.pop());
assertSame(Operators.POW, queue.pop());
assertSame(Operators.DIV, queue.pop());
assertSame(Operators.SUB, queue.pop());
}
/** Tests empty expressions. */
@Test
public void testEmpty() {
final ExpressionParser parser = new ExpressionParser();
assertEquals(0, parser.parsePostfix("").size());
}
/** Tests that parsing an invalid expression fails appropriately. */
@Test
public void testInvalid() {
final ExpressionParser parser = new ExpressionParser();
assertInvalid(parser, "a a", "Invalid character at index 2");
assertInvalid(parser, "func(,)", "Invalid character at index 5");
assertInvalid(parser, "foo,bar",
"Misplaced separator or mismatched groups at index 4");
assertInvalid(parser, "(", "Mismatched groups at index 1");
assertInvalid(parser, ")", "Mismatched group terminator ')' at index 1");
assertInvalid(parser, ")(", "Mismatched group terminator ')' at index 1");
assertInvalid(parser, "(()", "Mismatched groups at index 3");
}
// -- Helper
private void assertUnary(final ExpressionParser parser, final String var,
final Operator op, final String expression)
{
final LinkedList queue = parser.parsePostfix(expression);
assertNotNull(queue);
assertEquals(2, queue.size());
assertVariable(var, queue.pop());
assertSame(op, queue.pop());
}
private void assertBinary(final ExpressionParser parser, final String var1,
final Operator op, final String var2, final String expression)
{
final LinkedList queue = parser.parsePostfix(expression);
assertNotNull(queue);
assertEquals(3, queue.size());
assertVariable(var1, queue.pop());
assertVariable(var2, queue.pop());
assertSame(op, queue.pop());
}
private void assertInvalid(final ExpressionParser parser,
final String expression, final String message)
{
try {
parser.parsePostfix(expression);
fail("Expected IllegalArgumentException");
}
catch (final IllegalArgumentException exc) {
assertEquals(message, exc.getMessage());
}
}
}
parsington-parsington-1.0.1/src/test/java/org/scijava/parse/LiteralsTest.java 0000664 0000000 0000000 00000023311 13103137730 0027347 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
import java.math.BigInteger;
import org.junit.Test;
/**
* Tests {@link Literals}.
*
* @author Curtis Rueden
*/
public class LiteralsTest extends AbstractTest {
@Test
public void testParseBoolean() {
assertSame(Boolean.FALSE, Literals.parseBoolean("false"));
assertSame(Boolean.TRUE, Literals.parseBoolean("true"));
assertNull(Literals.parseBoolean("zfalse"));
assertNull(Literals.parseBoolean("zfalsez"));
assertNull(Literals.parseBoolean("ztrue"));
assertNull(Literals.parseBoolean("ztruez"));
final Position pos = new Position();
pos.set(0);
assertSame(Boolean.FALSE, Literals.parseBoolean("false-", pos));
assertEquals(5, pos.get());
pos.set(0);
assertSame(Boolean.TRUE, Literals.parseBoolean("true-", pos));
assertEquals(4, pos.get());
}
@Test
public void testParseString() {
assertEquals("hello world", Literals.parseString("'hello world'"));
// Test escape sequences.
assertEquals("a\b\t\n\f\r\"\\z", Literals
.parseString("\"a\\b\\t\\n\\f\\r\\\"\\\\z\""));
assertEquals("\t\\\t\\\\\t", Literals
.parseString("\"\\t\\\\\\t\\\\\\\\\\t\""));
// Test Unicode escape sequences.
assertEquals("\u9654", Literals.parseString("\"\u9654\""));
assertEquals("xyz\u9654abc", Literals.parseString("\"xyz\\u9654abc\""));
// Test octal escape sequences.
assertEquals("\0", Literals.parseString("\"\\0\""));
assertEquals("\00", Literals.parseString("\"\\00\""));
assertEquals("\000", Literals.parseString("\"\\000\""));
assertEquals("\12", Literals.parseString("\"\\12\""));
assertEquals("\123", Literals.parseString("\"\\123\""));
assertEquals("\377", Literals.parseString("\"\\377\""));
assertEquals("\1234", Literals.parseString("\"\\1234\""));
// Test position
final Position pos = new Position();
pos.set(2);
assertEquals("cde", Literals.parseString("ab'cde'fg", pos));
assertEquals(7, pos.get());
}
@Test
public void testParseStringInvalid() {
// Test non-string tokens.
assertNull(Literals.parseString(""));
assertNull(Literals.parseString("1234"));
assertNull(Literals.parseString("foo"));
assertNull(Literals.parseString("a'b'c"));
// Test malformed string literals.
try {
Literals.parseString("'");
fail("IllegalArgumentException expected");
}
catch (final IllegalArgumentException exc) {
assertEquals("Unclosed string literal at index 0", exc.getMessage());
}
}
@Test
public void testParseHex() {
assertNumber(0x123, Literals.parseHex("0x123"));
// Test explicit long.
assertNumber(0x123L, Literals.parseHex("0x123L"));
// Test implicit long.
assertNumber(0x123456789abcdefL, Literals.parseHex("0x123456789abcdef"));
// Test BigInteger.
final String big = "123456789abcdeffedcba987654321";
final Number bigNum = Literals.parseHex("0x" + big);
assertNumber(new BigInteger(big, 16), bigNum);
}
@Test
public void testParseHexNegative() {
assertNumber(-0x123, Literals.parseHex("-0x123"));
// Test explicit long.
assertNumber(-0x123L, Literals.parseHex("-0x123L"));
// Test implicit long.
assertNumber(-0x123456789abcdefL, Literals.parseHex("-0x123456789abcdef"));
// Test BigInteger.
final String big = "123456789abcdeffedcba987654321";
final Number bigNum = Literals.parseHex("-0x" + big);
assertNumber(new BigInteger("-" + big, 16), bigNum);
}
@Test
public void testParseBinary() {
// NB: "0b..." syntax is only supported starting with Java 7.
assertNumber(33, Literals.parseBinary("0b100001"));
// Test explicit long.
assertNumber(33L, Literals.parseBinary("0b100001L"));
// Test implicit long.
assertNumber(194588677707L, Literals.parseBinary(
"0b10110101001110011000111001011001001011"));
// Test BigInteger.
final String big =
"10110011100011110000111110000011111100000011111110000000"
+ "111111110000000011111111100000000011111111110000000000";
final Number bigNum = Literals.parseBinary("0b" + big);
assertNumber(new BigInteger(big, 2), bigNum);
}
@Test
public void testParseBinaryNegative() {
// NB: "0b..." syntax is only supported starting with Java 7.
assertNumber(-33, Literals.parseBinary("-0b100001"));
// Test explicit long.
assertNumber(-33L, Literals.parseBinary("-0b100001L"));
// Test implicit long.
assertNumber(-194588677707L, Literals.parseBinary(
"-0b10110101001110011000111001011001001011"));
// Test BigInteger.
final String big =
"10110011100011110000111110000011111100000011111110000000"
+ "111111110000000011111111100000000011111111110000000000";
final Number bigNum = Literals.parseBinary("-0b" + big);
assertNumber(new BigInteger("-" + big, 2), bigNum);
}
@Test
public void testParseOctal() {
assertNumber(01234567, Literals.parseOctal("01234567"));
// Test explicit long.
assertNumber(01234567L, Literals.parseOctal("01234567L"));
// Test implicit long.
assertNumber(012345677654321L, Literals.parseOctal("012345677654321"));
// Test BigInteger.
final String big = "1234567765432112345677654321";
final Number bigNum = Literals.parseOctal("0" + big);
assertNumber(new BigInteger(big, 8), bigNum);
}
@Test
public void testParseOctalNegative() {
assertNumber(-01234567, Literals.parseOctal("-01234567"));
// Test explicit long.
assertNumber(-01234567L, Literals.parseOctal("-01234567L"));
// Test implicit long.
assertNumber(-012345677654321L, Literals.parseOctal("-012345677654321"));
// Test BigInteger.
final String big = "1234567765432112345677654321";
final Number bigNum = Literals.parseOctal("-0" + big);
assertNumber(new BigInteger("-" + big, 8), bigNum);
}
@Test
public void testParseDecimal() {
assertNumber(123456789, Literals.parseDecimal("123456789"));
// Test explicit long.
assertNumber(123456789L, Literals.parseDecimal("123456789L"));
// Test implicit long.
assertNumber(123456787654321L, Literals.parseDecimal("123456787654321"));
// Test BigInteger.
final String bigI = "1234567898765432123456789";
final Number bigInt = Literals.parseDecimal(bigI);
assertNumber(new BigInteger(bigI), bigInt);
// Test explicit float.
assertNumber(1f, Literals.parseDecimal("1f"));
// Test explicit double.
assertNumber(1d, Literals.parseDecimal("1d"));
// Test implicit double.
assertNumber(1.0, Literals.parseDecimal("1.0"));
assertNumber(1., Literals.parseDecimal("1."));
// Test scientific notation.
assertNumber(1e2, Literals.parseDecimal("1e2"));
assertNumber(1.2e3, Literals.parseDecimal("1.2e3"));
assertNumber(1.2e3f, Literals.parseDecimal("1.2e3f"));
}
@Test
public void testParseDecimalNegative() {
assertNumber(-123456789, Literals.parseDecimal("-123456789"));
// Test explicit long.
assertNumber(-123456789L, Literals.parseDecimal("-123456789L"));
// Test implicit long.
assertNumber(-123456787654321L, Literals.parseDecimal("-123456787654321"));
// Test BigInteger.
final String bigI = "-1234567898765432123456789";
final Number bigInt = Literals.parseDecimal(bigI);
assertNumber(new BigInteger(bigI), bigInt);
// Test explicit float.
assertNumber(-1f, Literals.parseDecimal("-1f"));
// Test explicit double.
assertNumber(-1d, Literals.parseDecimal("-1d"));
// Test implicit double.
assertNumber(-1.0, Literals.parseDecimal("-1.0"));
assertNumber(-1., Literals.parseDecimal("-1."));
// Test scientific notation.
assertNumber(-1e2, Literals.parseDecimal("-1e2"));
assertNumber(-1.2e3, Literals.parseDecimal("-1.2e3"));
assertNumber(-1.2e3f, Literals.parseDecimal("-1.2e3f"));
}
@Test
public void testParseNumber() {
final Position pos = new Position();
assertNumber(0, Literals.parseNumber("0", pos));
assertEquals(1, pos.get());
pos.set(1);
assertNumber(5.7, Literals.parseNumber("a5.7a", pos));
assertEquals(4, pos.get());
pos.set(2);
assertNumber(-11, Literals.parseNumber("bb-11bb", pos));
assertEquals(5, pos.get());
pos.set(3);
assertNumber(0x123L, Literals.parseNumber("ccc0x123Lccc", pos));
assertEquals(9, pos.get());
}
@Test
public void testParseLiteral() {
assertSame(Boolean.FALSE, Literals.parseLiteral("false"));
assertSame(Boolean.TRUE, Literals.parseLiteral("true"));
assertEquals("fubar", Literals.parseLiteral("'fubar'"));
assertNumber(0, Literals.parseLiteral("0"));
}
}
parsington-parsington-1.0.1/src/test/java/org/scijava/parse/SubSequenceTest.java 0000664 0000000 0000000 00000007634 13103137730 0030024 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
/**
* Test {@link SubSequence}.
*
* @author Curtis Rueden
*/
public class SubSequenceTest {
private static String PHRASE =
"The quick brown fox jumped over the lazy dogs.";
@Test
public void testLength() {
for (int off = 0; off < PHRASE.length(); off++) {
for (int len = 0; len < PHRASE.length() - off; len++) {
assertEquals(len, sub(off, len).length());
}
}
}
@Test
public void testCharAt() {
for (int off = 0; off < PHRASE.length(); off++) {
for (int len = 0; len < PHRASE.length() - off; len++) {
final SubSequence sub = sub(off, len);
for (int c = 0; c < sub.length(); c++) {
assertEquals(PHRASE.charAt(off + c), sub.charAt(c));
}
}
}
}
@Test
public void testSubSequence() {
final SubSequence sub = sub(4, 15); // quick brown fox
final SubSequence subSub = sub.subSequence(6, 11); // brown
assertEquals(5, subSub.length());
assertEquals('b', subSub.charAt(0));
assertEquals('r', subSub.charAt(1));
assertEquals('o', subSub.charAt(2));
assertEquals('w', subSub.charAt(3));
assertEquals('n', subSub.charAt(4));
}
@Test
public void testToString() {
assertEquals("quick brown fox", sub(4, 15).toString());
}
@Test
public void testNegativeOffset() {
try {
sub(-1, 1);
fail("Expected IndexOutOfBoundsException");
}
catch (final IndexOutOfBoundsException exc) {
assertEquals("Offset -1 < 0", exc.getMessage());
}
}
@Test
public void testNegativeLength() {
try {
sub(1, -1);
fail("Expected IndexOutOfBoundsException");
}
catch (final IndexOutOfBoundsException exc) {
assertEquals("Length -1 < 0", exc.getMessage());
}
}
@Test
public void testOffsetTooLarge() {
final int len = PHRASE.length();
final int off = len + 1;
try {
sub(off, 1);
fail("Expected IndexOutOfBoundsException");
}
catch (final IndexOutOfBoundsException exc) {
assertEquals("Offset " + off + " > " + len, exc.getMessage());
}
}
@Test
public void testLengthTooLong() {
final int len = PHRASE.length();
try {
sub(1, len);
fail("Expected IndexOutOfBoundsException");
}
catch (final IndexOutOfBoundsException exc) {
assertEquals("Offset 1 + length " + len + " > " + len, exc.getMessage());
}
}
// -- Helper methods --
private SubSequence sub(final int offset, final int length) {
return new SubSequence(PHRASE, offset, length);
}
}
parsington-parsington-1.0.1/src/test/java/org/scijava/parse/SyntaxTreeTest.java 0000664 0000000 0000000 00000011465 13103137730 0027705 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import java.util.Arrays;
import java.util.LinkedList;
import org.junit.Test;
/**
* Tests {@link SyntaxTree}.
*
* @author Curtis Rueden
*/
public class SyntaxTreeTest extends AbstractTest {
@Test
public void testSimple() {
// infix: a + b * c
// postfix: a b c * +
final LinkedList queue =
queue(var("a"), var("b"), var("c"), Operators.MUL, Operators.ADD);
// NB: SyntaxTree constructor consumes the queue, so save a copy.
final LinkedList expected = new LinkedList(queue);
final SyntaxTree tree = new SyntaxTree(queue);
assertNotNull(tree);
assertSame(Operators.ADD, tree.token());
assertCount(2, tree);
assertVariable("a", tree.child(0).token());
assertSame(Operators.MUL, tree.child(1).token());
assertCount(2, tree.child(1));
assertVariable("b", tree.child(1).child(0).token());
assertVariable("c", tree.child(1).child(1).token());
assertSameLists(expected, tree.postfix());
}
@Test
public void testComplicated() {
// infix: a / b * c + a ^ b ^ c - f(d, c, b, a)
// postfix: a b / c * a b c ^ ^ + f d c b a (4) -
final LinkedList queue =
queue(var("a"), var("b"), Operators.DIV, var("c"), Operators.MUL,
var("a"), var("b"), var("c"), Operators.POW, Operators.POW,
Operators.ADD, var("f"), var("d"), var("c"), var("b"), var("a"),
group(Operators.PARENS, 4), func(), Operators.SUB);
// NB: SyntaxTree constructor consumes the queue, so save a copy.
final LinkedList expected = new LinkedList(queue);
final SyntaxTree tree = new SyntaxTree(queue);
assertNotNull(tree);
assertSame(Operators.SUB, token(tree));
assertSame(Operators.ADD, token(tree, 0));
assertSame(Operators.MUL, token(tree, 0, 0));
assertSame(Operators.DIV, token(tree, 0, 0, 0));
assertVariable("a", token(tree, 0, 0, 0, 0));
assertVariable("b", token(tree, 0, 0, 0, 1));
assertVariable("c", token(tree, 0, 0, 1));
assertSame(Operators.POW, token(tree, 0, 1));
assertVariable("a", token(tree, 0, 1, 0));
assertSame(Operators.POW, token(tree, 0, 1, 1));
assertVariable("b", token(tree, 0, 1, 1, 0));
assertVariable("c", token(tree, 0, 1, 1, 1));
assertFunction(token(tree, 1));
assertVariable("f", token(tree, 1, 0));
assertGroup(Operators.PARENS, 4, token(tree, 1, 1));
assertVariable("d", token(tree, 1, 1, 0));
assertVariable("c", token(tree, 1, 1, 1));
assertVariable("b", token(tree, 1, 1, 2));
assertVariable("a", token(tree, 1, 1, 3));
assertSameLists(expected, tree.postfix());
}
// -- Helper methods --
private LinkedList queue(final Object... args) {
return new LinkedList(Arrays.asList(args));
}
private Variable var(final String token) {
return new Variable(token);
}
private Group group(final Group g, final int arity) {
final Group group = g.instance();
for (int a = 0; a < arity; a++)
group.incArity();
return group;
}
private Function func() {
return new Function(0); // NB: Precedence does not matter here.
}
private Object token(final SyntaxTree tree, final int... indices) {
if (indices.length == 0) return tree.token();
final int[] subIndices = new int[indices.length - 1];
System.arraycopy(indices, 1, subIndices, 0, subIndices.length);
return token(tree.child(indices[0]), subIndices);
}
}
parsington-parsington-1.0.1/src/test/java/org/scijava/parse/eval/ 0000775 0000000 0000000 00000000000 13103137730 0025014 5 ustar 00root root 0000000 0000000 parsington-parsington-1.0.1/src/test/java/org/scijava/parse/eval/DefaultEvaluatorTest.java 0000664 0000000 0000000 00000072233 13103137730 0031775 0 ustar 00root root 0000000 0000000 /*
* #%L
* Parsington: the SciJava mathematical expression parser.
* %%
* Copyright (C) 2015 - 2016 Board of Regents of the University of
* Wisconsin-Madison.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/
package org.scijava.parse.eval;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.scijava.parse.AbstractTest;
import org.scijava.parse.Operators;
import org.scijava.parse.SyntaxTree;
import org.scijava.parse.Variable;
/** Tests {@link DefaultEvaluator}. */
public class DefaultEvaluatorTest extends AbstractTest {
private DefaultEvaluator e;
@Before
public void setUp() {
e = new DefaultEvaluator();
}
/** Tests {@link DefaultEvaluator#evaluate(String)}. */
@Test
public void testEvaluate() {
assertEquals(26, e.evaluate("(2*3)+(4*5)"));
}
/** Tests strict mode; see {@link Evaluator#setStrict(boolean)}. */
@Test(expected = IllegalArgumentException.class)
public void testStrict() {
e.evaluate("foo=bar");
}
/** Tests non-strict mode; see {@link Evaluator#setStrict(boolean)}. */
@Test
public void testNonStrict() {
e.setStrict(false);
e.evaluate("foo=bar");
final Object bar = e.get(new Variable("foo"));
assertTrue(bar instanceof Unresolved);
assertEquals("bar", ((Unresolved) bar).getToken());
}
/**
* Tests that {@link DefaultEvaluator#evaluate(String)} handles the built-in
* {@code postfix} and {@code tree} functions as expected.
*/
@Test
public void testBuiltIns() {
final Object[] o = {1, 2, 3, Operators.MUL, Operators.ADD};
final List postfix = Arrays.asList(o);
assertEquals(postfix, e.evaluate("postfix('1+2*3')"));
final SyntaxTree tree = new SyntaxTree(new LinkedList(postfix));
assertEquals(tree, e.evaluate("tree('1+2*3')"));
}
// -- function --
/** Tests {@link DefaultEvaluator#function(Object, Object)}. */
@Test
public void testFunction() {
// test list access
final Variable v = new Variable("v");
e.set(v, Arrays.asList("a", "b", "c"));
assertEquals("a", e.function(v, Arrays.asList(0)));
assertEquals("b", e.function(v, Arrays.asList(1)));
assertEquals("c", e.function(v, Arrays.asList(2)));
assertNull(e.function(o(0), o(1)));
}
// -- dot --
/** Tests {@link DefaultEvaluator#dot(Object, Object)}. */
@Test
public void testDot() {
assertNull(e.dot(o(0), o(1)));
}
// -- groups --
/** Tests {@link DefaultEvaluator#parens(Object[])}. */
@Test
public void testParens() {
final Object[] o = {1, 2, 3};
assertEquals(Arrays.asList(o), e.parens(o));
// test empty parentheses
assertEquals(Collections.emptyList(), e.parens(new Object[0]));
// test collapse of single elements
assertEquals(4, e.parens(new Object[] {4}));
}
/** Tests {@link DefaultEvaluator#brackets(Object[])}. */
@Test
public void testBrackets() {
final Object[] o = {1, 2, 3};
assertEquals(Arrays.asList(o), e.brackets(o));
// test empty brackets
assertEquals(Collections.emptyList(), e.brackets(new Object[0]));
}
/** Tests {@link DefaultEvaluator#braces(Object[])}. */
@Test
public void testBraces() {
final Object[] o = {1, 2, 3};
assertEquals(Arrays.asList(o), e.braces(o));
// test empty braces
assertEquals(Collections.emptyList(), e.braces(new Object[0]));
}
// -- transpose, power --
/** Tests {@link DefaultEvaluator#transpose(Object)}. */
@Test
public void testTranspose() {
assertNull(e.transpose(o(0)));
}
/** Tests {@link DefaultEvaluator#dotTranspose(Object)}. */
@Test
public void testDotTranspose() {
assertNull(e.dotTranspose(o(0)));
}
/** Tests {@link DefaultEvaluator#pow(Object, Object)}. */
@Test
public void testPow() {
assertNumber(15.625d, e.pow(o(2.5d), o(3d)));
assertNumber(bi(15625), e.pow(o(bi(5)), o(6)));
assertNumber(bd(15.625), e.pow(o(bd(2.5d)), o(3)));
}
/** Tests {@link DefaultEvaluator#dotPow(Object, Object)}. */
@Test
public void testDotPow() {
assertNull(e.dotPow(o(0), o(0)));
}
// -- postfix --
/** Tests {@link DefaultEvaluator#postInc(Object)}. */
@Test
public void testPostInc() {
final Variable v = new Variable("v");
e.set(v, 2); assertEquals(2, e.postInc(v)); assertEquals(3, e.get(v));
e.set(v, 4L); assertEquals(4L, e.postInc(v)); assertEquals(5L, e.get(v));
e.set(v, 6f); assertEquals(6f, e.postInc(v)); assertEquals(7f, e.get(v));
e.set(v, 8d); assertEquals(8d, e.postInc(v)); assertEquals(9d, e.get(v));
e.set(v, bi(10)); assertEquals(bi(10), e.postInc(v)); assertEquals(bi(11), e.get(v));
e.set(v, bd(12)); assertEquals(bd(12), e.postInc(v)); assertEquals(bd(13), e.get(v));
}
/** Tests {@link DefaultEvaluator#postDec(Object)}. */
@Test
public void testPostDec() {
final Variable v = new Variable("v");
e.set(v, 2); assertEquals(2, e.postDec(v)); assertEquals(1, e.get(v));
e.set(v, 4L); assertEquals(4L, e.postDec(v)); assertEquals(3L, e.get(v));
e.set(v, 6f); assertEquals(6f, e.postDec(v)); assertEquals(5f, e.get(v));
e.set(v, 8d); assertEquals(8d, e.postDec(v)); assertEquals(7d, e.get(v));
e.set(v, bi(10)); assertEquals(bi(10), e.postDec(v)); assertEquals(bi(9), e.get(v));
e.set(v, bd(12)); assertEquals(bd(12), e.postDec(v)); assertEquals(bd(11), e.get(v));
}
// -- unary --
/** Tests {@link DefaultEvaluator#preInc(Object)}. */
@Test
public void testPreInc() {
final Variable v = new Variable("v");
e.set(v, 2); assertEquals(3, e.preInc(v)); assertEquals(3, e.get(v));
e.set(v, 4L); assertEquals(5L, e.preInc(v)); assertEquals(5L, e.get(v));
e.set(v, 6f); assertEquals(7f, e.preInc(v)); assertEquals(7f, e.get(v));
e.set(v, 8d); assertEquals(9d, e.preInc(v)); assertEquals(9d, e.get(v));
e.set(v, bi(10)); assertEquals(bi(11), e.preInc(v)); assertEquals(bi(11), e.get(v));
e.set(v, bd(12)); assertEquals(bd(13), e.preInc(v)); assertEquals(bd(13), e.get(v));
}
/** Tests {@link DefaultEvaluator#preDec(Object)}. */
@Test
public void testPreDec() {
final Variable v = new Variable("v");
e.set(v, 2); assertEquals(1, e.preDec(v)); assertEquals(1, e.get(v));
e.set(v, 4L); assertEquals(3L, e.preDec(v)); assertEquals(3L, e.get(v));
e.set(v, 6f); assertEquals(5f, e.preDec(v)); assertEquals(5f, e.get(v));
e.set(v, 8d); assertEquals(7d, e.preDec(v)); assertEquals(7d, e.get(v));
e.set(v, bi(10)); assertEquals(bi(9), e.preDec(v)); assertEquals(bi(9), e.get(v));
e.set(v, bd(12)); assertEquals(bd(11), e.preDec(v)); assertEquals(bd(11), e.get(v));
}
/** Tests {@link DefaultEvaluator#pos(Object)}. */
@Test
public void testPos() {
assertNumber(7, e.pos(o(7)));
assertNumber(7L, e.pos(o(7L)));
assertNumber(7.8d, e.pos(o(7.8d)));
assertNumber(7.8f, e.pos(o(7.8f)));
assertSame(BigInteger.ZERO, e.pos(BigInteger.ZERO));
assertSame(BigInteger.ONE, e.pos(BigInteger.ONE));
assertSame(BigInteger.TEN, e.pos(BigInteger.TEN));
assertSame(BigDecimal.ZERO, e.pos(BigDecimal.ZERO));
assertSame(BigDecimal.ONE, e.pos(BigDecimal.ONE));
assertSame(BigDecimal.TEN, e.pos(BigDecimal.TEN));
}
/** Tests {@link DefaultEvaluator#neg(Object)}. */
@Test
public void testNeg() {
assertNumber(7, e.neg(o(-7)));
assertNumber(7L, e.neg(o(-7L)));
assertNumber(7.8f, e.neg(o(-7.8f)));
assertNumber(7.8d, e.neg(o(-7.8d)));
assertNumber(bi(7), e.neg(o(bi(-7))));
assertNumber(bd(7.8), e.neg(o(bd(-7.8))));
assertNumber(-7, e.neg(o(7)));
assertNumber(-7L, e.neg(o(7L)));
assertNumber(-7.8f, e.neg(o(7.8f)));
assertNumber(-7.8d, e.neg(o(7.8d)));
assertNumber(bi(-7), e.neg(o(bi(7))));
assertNumber(bd(-7.8), e.neg(o(bd(7.8))));
}
/** Tests {@link DefaultEvaluator#complement(Object)}. */
@Test
public void testComplement() {
assertNumber(0x35014541, e.complement(o(0xcafebabe)));
assertNumber(0x2152350141104541L, e.complement(o(0xdeadcafebeefbabeL)));
}
/** Tests {@link DefaultEvaluator#not(Object)}. */
@Test
public void testNot() {
assertSame(false, e.not(o(true)));
assertSame(true, e.not(o(false)));
}
// -- multiplicative --
/** Tests {@link DefaultEvaluator#mul(Object, Object)}. */
@Test
public void testMul() {
assertNumber(24, e.mul(o(4), o(6)));
assertNumber(24L, e.mul(o(4L), o(6L)));
assertNumber(8.75f, e.mul(o(2.5f), o(3.5f)));
assertNumber(8.75d, e.mul(o(2.5d), o(3.5d)));
assertNumber(bi(24), e.mul(o(bi(4)), o(bi(6))));
assertNumber(bd(8.75), e.mul(o(bd(2.5)), o(bd(3.5))));
}
/** Tests {@link DefaultEvaluator#div(Object, Object)}. */
@Test
public void testDiv() {
assertNumber(4, e.div(o(27), o(6)));
assertNumber(4L, e.div(o(27L), o(6L)));
assertNumber(2.5f, e.div(o(8.75f), o(3.5f)));
assertNumber(2.5d, e.div(o(8.75d), o(3.5d)));
assertNumber(bi(4), e.div(o(bi(27)), o(bi(6))));
assertNumber(bd(2.5), e.div(o(bd(8.75)), o(bd(3.5))));
}
/** Tests {@link DefaultEvaluator#mod(Object, Object)}. */
@Test
public void testMod() {
assertNumber(3, e.mod(o(27), o(6)));
assertNumber(3L, e.mod(o(27L), o(6L)));
assertNumber(1.75f, e.mod(o(8.75f), o(3.5f)));
assertNumber(1.75d, e.mod(o(8.75d), o(3.5d)));
assertNumber(bi(3), e.mod(o(bi(27)), o(bi(6))));
assertNumber(bd(1.75), e.mod(o(bd(8.75)), o(bd(3.5))));
}
/** Tests {@link DefaultEvaluator#rightDiv(Object, Object)}. */
@Test
public void testRightDiv() {
assertNull(e.rightDiv(o(0), o(0)));
}
/** Tests {@link DefaultEvaluator#dotDiv(Object, Object)}. */
@Test
public void testDotDiv() {
assertNull(e.dotDiv(o(0), o(0)));
}
/** Tests {@link DefaultEvaluator#dotRightDiv(Object, Object)}. */
@Test
public void testDotRightDiv() {
assertNull(e.dotRightDiv(o(0), o(0)));
}
// -- additive --
/** Tests {@link DefaultEvaluator#add(Object, Object)}. */
@Test
public void testAdd() {
assertEquals("Hello, world", e.add(o("Hello,"), o(" world")));
assertNumber(10, e.add(o(4), o(6)));
assertNumber(10L, e.add(o(4L), o(6L)));
assertNumber(3.6f, e.add(o(1.5f), o(2.1f)));
assertNumber(3.6d, e.add(o(1.5d), o(2.1d)));
assertNumber(bi(10), e.add(o(bi(4)), o(bi(6))));
assertNumber(bd(3.6), e.add(o(bd(1.5)), o(bd(2.1))));
}
/** Tests {@link DefaultEvaluator#sub(Object, Object)}. */
@Test
public void testSub() {
assertNumber(4, e.sub(o(10), o(6)));
assertNumber(4L, e.sub(o(10L), o(6L)));
assertNumber(1.5f, e.sub(o(3.6f), o(2.1f)));
assertNumber(1.5d, e.sub(o(3.6d), o(2.1d)));
assertNumber(bi(4), e.sub(o(bi(10)), o(bi(6))));
assertNumber(bd(1.5), e.sub(o(bd(3.6)), o(bd(2.1))));
}
// -- shift --
/** Tests {@link DefaultEvaluator#leftShift(Object, Object)}. */
@Test
public void testLeftShift() {
assertNumber(0xafebabe0, e.leftShift(o(0xcafebabe), o(4)));
assertNumber(0xdcafebeefbabe000L, e.leftShift(o(0xdeadcafebeefbabeL), o(12)));
assertNumber(bi(7296), e.leftShift(o(bi(57)), o(7)));
}
/** Tests {@link DefaultEvaluator#rightShift(Object, Object)}. */
@Test
public void testRightShift() {
assertNumber(0xfcafebab, e.rightShift(o(0xcafebabe), o(4)));
assertNumber(0xfffdeadcafebeefbL, e.rightShift(o(0xdeadcafebeefbabeL), o(12)));
assertNumber(bi(278), e.rightShift(o(bi(8920)), o(5)));
}
/** Tests {@link DefaultEvaluator#unsignedRightShift(Object, Object)}. */
@Test
public void testUnsignedRightShift() {
assertNumber(0x0cafebab, e.unsignedRightShift(o(0xcafebabe), o(4)));
assertNumber(0x000deadcafebeefbL, e.unsignedRightShift(o(0xdeadcafebeefbabeL), o(12)));
}
// -- colon --
/** Tests {@link DefaultEvaluator#colon(Object, Object)}. */
@Test
public void testColon() {
assertNull(e.colon(o(0), o(0)));
}
// -- relational --
/** Tests {@link DefaultEvaluator#lessThan(Object, Object)}. */
@Test
public void testLessThan() {
assertSame(true, e.lessThan(o(false), o(true)));
assertSame(false, e.lessThan(o(false), o(false)));
assertSame(false, e.lessThan(o(true), o(false)));
assertSame(true, e.lessThan(o("hello"), o("world")));
assertSame(false, e.lessThan(o("hello"), o("hello")));
assertSame(false, e.lessThan(o("young"), o("world")));
assertSame(true, e.lessThan(o(2), o(3)));
assertSame(false, e.lessThan(o(2), o(2)));
assertSame(false, e.lessThan(o(2), o(1)));
assertSame(true, e.lessThan(o(5L), o(6L)));
assertSame(false, e.lessThan(o(5L), o(5L)));
assertSame(false, e.lessThan(o(5L), o(4L)));
assertSame(true, e.lessThan(o(8f), o(9f)));
assertSame(false, e.lessThan(o(8f), o(8f)));
assertSame(false, e.lessThan(o(8f), o(7f)));
assertSame(true, e.lessThan(o(11d), o(12d)));
assertSame(false, e.lessThan(o(11d), o(11d)));
assertSame(false, e.lessThan(o(11d), o(10d)));
assertSame(true, e.lessThan(o(bi(14)), o(bi(15))));
assertSame(false, e.lessThan(o(bi(14)), o(bi(14))));
assertSame(false, e.lessThan(o(bi(14)), o(bi(13))));
assertSame(true, e.lessThan(o(bd(17)), o(bd(18))));
assertSame(false, e.lessThan(o(bd(17)), o(bd(17))));
assertSame(false, e.lessThan(o(bd(17)), o(bd(16))));
}
/** Tests {@link DefaultEvaluator#greaterThan(Object, Object)}. */
@Test
public void testGreaterThan() {
assertSame(false, e.greaterThan(o(false), o(true)));
assertSame(false, e.greaterThan(o(false), o(false)));
assertSame(true, e.greaterThan(o(true), o(false)));
assertSame(false, e.greaterThan(o("hello"), o("world")));
assertSame(false, e.greaterThan(o("hello"), o("hello")));
assertSame(true, e.greaterThan(o("young"), o("world")));
assertSame(false, e.greaterThan(o(2), o(3)));
assertSame(false, e.greaterThan(o(2), o(2)));
assertSame(true, e.greaterThan(o(2), o(1)));
assertSame(false, e.greaterThan(o(5L), o(6L)));
assertSame(false, e.greaterThan(o(5L), o(5L)));
assertSame(true, e.greaterThan(o(5L), o(4L)));
assertSame(false, e.greaterThan(o(8f), o(9f)));
assertSame(false, e.greaterThan(o(8f), o(8f)));
assertSame(true, e.greaterThan(o(8f), o(7f)));
assertSame(false, e.greaterThan(o(11d), o(12d)));
assertSame(false, e.greaterThan(o(11d), o(11d)));
assertSame(true, e.greaterThan(o(11d), o(10d)));
assertSame(false, e.greaterThan(o(bi(14)), o(bi(15))));
assertSame(false, e.greaterThan(o(bi(14)), o(bi(14))));
assertSame(true, e.greaterThan(o(bi(14)), o(bi(13))));
assertSame(false, e.greaterThan(o(bd(17)), o(bd(18))));
assertSame(false, e.greaterThan(o(bd(17)), o(bd(17))));
assertSame(true, e.greaterThan(o(bd(17)), o(bd(16))));
}
/** Tests {@link DefaultEvaluator#lessThanOrEqual(Object, Object)}. */
@Test
public void testLessThanOrEqual() {
assertSame(true, e.lessThanOrEqual(o(false), o(true)));
assertSame(true, e.lessThanOrEqual(o(false), o(false)));
assertSame(false, e.lessThanOrEqual(o(true), o(false)));
assertSame(true, e.lessThanOrEqual(o("hello"), o("world")));
assertSame(true, e.lessThanOrEqual(o("hello"), o("hello")));
assertSame(false, e.lessThanOrEqual(o("young"), o("world")));
assertSame(true, e.lessThanOrEqual(o(2), o(3)));
assertSame(true, e.lessThanOrEqual(o(2), o(2)));
assertSame(false, e.lessThanOrEqual(o(2), o(1)));
assertSame(true, e.lessThanOrEqual(o(5L), o(6L)));
assertSame(true, e.lessThanOrEqual(o(5L), o(5L)));
assertSame(false, e.lessThanOrEqual(o(5L), o(4L)));
assertSame(true, e.lessThanOrEqual(o(8f), o(9f)));
assertSame(true, e.lessThanOrEqual(o(8f), o(8f)));
assertSame(false, e.lessThanOrEqual(o(8f), o(7f)));
assertSame(true, e.lessThanOrEqual(o(11d), o(12d)));
assertSame(true, e.lessThanOrEqual(o(11d), o(11d)));
assertSame(false, e.lessThanOrEqual(o(11d), o(10d)));
assertSame(true, e.lessThanOrEqual(o(bi(14)), o(bi(15))));
assertSame(true, e.lessThanOrEqual(o(bi(14)), o(bi(14))));
assertSame(false, e.lessThanOrEqual(o(bi(14)), o(bi(13))));
assertSame(true, e.lessThanOrEqual(o(bd(17)), o(bd(18))));
assertSame(true, e.lessThanOrEqual(o(bd(17)), o(bd(17))));
assertSame(false, e.lessThanOrEqual(o(bd(17)), o(bd(16))));
}
/** Tests {@link DefaultEvaluator#greaterThanOrEqual(Object, Object)}. */
@Test
public void testGreaterThanOrEqual() {
assertSame(false, e.greaterThanOrEqual(o(false), o(true)));
assertSame(true, e.greaterThanOrEqual(o(false), o(false)));
assertSame(true, e.greaterThanOrEqual(o(true), o(false)));
assertSame(false, e.greaterThanOrEqual(o("hello"), o("world")));
assertSame(true, e.greaterThanOrEqual(o("hello"), o("hello")));
assertSame(true, e.greaterThanOrEqual(o("young"), o("world")));
assertSame(false, e.greaterThanOrEqual(o(2), o(3)));
assertSame(true, e.greaterThanOrEqual(o(2), o(2)));
assertSame(true, e.greaterThanOrEqual(o(2), o(1)));
assertSame(false, e.greaterThanOrEqual(o(5L), o(6L)));
assertSame(true, e.greaterThanOrEqual(o(5L), o(5L)));
assertSame(true, e.greaterThanOrEqual(o(5L), o(4L)));
assertSame(false, e.greaterThanOrEqual(o(8f), o(9f)));
assertSame(true, e.greaterThanOrEqual(o(8f), o(8f)));
assertSame(true, e.greaterThanOrEqual(o(8f), o(7f)));
assertSame(false, e.greaterThanOrEqual(o(11d), o(12d)));
assertSame(true, e.greaterThanOrEqual(o(11d), o(11d)));
assertSame(true, e.greaterThanOrEqual(o(11d), o(10d)));
assertSame(false, e.greaterThanOrEqual(o(bi(14)), o(bi(15))));
assertSame(true, e.greaterThanOrEqual(o(bi(14)), o(bi(14))));
assertSame(true, e.greaterThanOrEqual(o(bi(14)), o(bi(13))));
assertSame(false, e.greaterThanOrEqual(o(bd(17)), o(bd(18))));
assertSame(true, e.greaterThanOrEqual(o(bd(17)), o(bd(17))));
assertSame(true, e.greaterThanOrEqual(o(bd(17)), o(bd(16))));
}
/** Tests {@link DefaultEvaluator#instanceOf(Object, Object)}. */
@Test
public void testInstanceOf() {
assertNull(e.instanceOf(o(0), o(0)));
}
// -- equality --
/** Tests {@link DefaultEvaluator#equal(Object, Object)}. */
@Test
public void testEqual() {
assertSame(false, e.equal(o(false), o(true)));
assertSame(true, e.equal(o(false), o(false)));
assertSame(false, e.equal(o(true), o(false)));
assertSame(false, e.equal(o("hello"), o("world")));
assertSame(true, e.equal(o("hello"), o("hello")));
assertSame(false, e.equal(o("young"), o("world")));
assertSame(false, e.equal(o(2), o(3)));
assertSame(true, e.equal(o(2), o(2)));
assertSame(false, e.equal(o(2), o(1)));
assertSame(false, e.equal(o(5L), o(6L)));
assertSame(true, e.equal(o(5L), o(5L)));
assertSame(false, e.equal(o(5L), o(4L)));
assertSame(false, e.equal(o(8f), o(9f)));
assertSame(true, e.equal(o(8f), o(8f)));
assertSame(false, e.equal(o(8f), o(7f)));
assertSame(false, e.equal(o(11d), o(12d)));
assertSame(true, e.equal(o(11d), o(11d)));
assertSame(false, e.equal(o(11d), o(10d)));
assertSame(false, e.equal(o(bi(14)), o(bi(15))));
assertSame(true, e.equal(o(bi(14)), o(bi(14))));
assertSame(false, e.equal(o(bi(14)), o(bi(13))));
assertSame(false, e.equal(o(bd(17)), o(bd(18))));
assertSame(true, e.equal(o(bd(17)), o(bd(17))));
assertSame(false, e.equal(o(bd(17)), o(bd(16))));
}
/** Tests {@link DefaultEvaluator#notEqual(Object, Object)}. */
@Test
public void testNotEqual() {
assertSame(true, e.notEqual(o(false), o(true)));
assertSame(false, e.notEqual(o(false), o(false)));
assertSame(true, e.notEqual(o(true), o(false)));
assertSame(true, e.notEqual(o("hello"), o("world")));
assertSame(false, e.notEqual(o("hello"), o("hello")));
assertSame(true, e.notEqual(o("young"), o("world")));
assertSame(true, e.notEqual(o(2), o(3)));
assertSame(false, e.notEqual(o(2), o(2)));
assertSame(true, e.notEqual(o(2), o(1)));
assertSame(true, e.notEqual(o(5L), o(6L)));
assertSame(false, e.notEqual(o(5L), o(5L)));
assertSame(true, e.notEqual(o(5L), o(4L)));
assertSame(true, e.notEqual(o(8f), o(9f)));
assertSame(false, e.notEqual(o(8f), o(8f)));
assertSame(true, e.notEqual(o(8f), o(7f)));
assertSame(true, e.notEqual(o(11d), o(12d)));
assertSame(false, e.notEqual(o(11d), o(11d)));
assertSame(true, e.notEqual(o(11d), o(10d)));
assertSame(true, e.notEqual(o(bi(14)), o(bi(15))));
assertSame(false, e.notEqual(o(bi(14)), o(bi(14))));
assertSame(true, e.notEqual(o(bi(14)), o(bi(13))));
assertSame(true, e.notEqual(o(bd(17)), o(bd(18))));
assertSame(false, e.notEqual(o(bd(17)), o(bd(17))));
assertSame(true, e.notEqual(o(bd(17)), o(bd(16))));
}
// -- bitwise --
/** Tests {@link DefaultEvaluator#bitwiseAnd(Object, Object)}. */
@Test
public void testBitwiseAnd() {
assertNumber(0xcaacbaae, e.bitwiseAnd(o(0xcafebabe), o(0xdeadbeef)));
assertNumber(0L, e.bitwiseAnd(o(0x0d0e0a0d0c0a0f0eL), o(0xb0e0e0f0b0a0b0e0L)));
assertNumber(bi(0xcaacbaae), e.bitwiseAnd(o(bi(0xcafebabe)), o(bi(0xdeadbeef))));
}
/** Tests {@link DefaultEvaluator#bitwiseOr(Object, Object)}. */
@Test
public void testBitwiseOr() {
assertNumber(0xdeffbeff, e.bitwiseOr(o(0xcafebabe), o(0xdeadbeef)));
assertNumber(0xbdeeeafdbcaabfeeL, e.bitwiseOr(o(0x0d0e0a0d0c0a0f0eL), o(0xb0e0e0f0b0a0b0e0L)));
assertNumber(bi(0xdeffbeff), e.bitwiseOr(o(bi(0xcafebabe)), o(bi(0xdeadbeef))));
}
// -- logical --
/** Tests {@link DefaultEvaluator#logicalAnd(Object, Object)}. */
@Test
public void testLogicalAnd() {
assertSame(false, e.logicalAnd(o(false), o(false)));
assertSame(false, e.logicalAnd(o(false), o(true)));
assertSame(false, e.logicalAnd(o(true), o(false)));
assertSame(true, e.logicalAnd(o(true), o(true)));
}
/** Tests {@link DefaultEvaluator#logicalOr(Object, Object)}. */
@Test
public void testLogicalOr() {
assertSame(false, e.logicalOr(o(false), o(false)));
assertSame(true, e.logicalOr(o(false), o(true)));
assertSame(true, e.logicalOr(o(true), o(false)));
assertSame(true, e.logicalOr(o(true), o(true)));
}
// -- assignment --
/** Tests {@link DefaultEvaluator#assign(Object, Object)}. */
@Test
public void testAssign() {
final Variable v = new Variable("v");
assertAssigned(true, v, e.assign(v, true));
assertAssigned("hello", v, e.assign(v, "hello"));
assertAssigned(1, v, e.assign(v, 1));
assertAssigned(2L, v, e.assign(v, 2L));
assertAssigned(3f, v, e.assign(v, 3f));
assertAssigned(4d, v, e.assign(v, 4d));
assertAssigned(bi(5), v, e.assign(v, bi(5)));
assertAssigned(bd(6), v, e.assign(v, bd(6)));
}
/** Tests {@link DefaultEvaluator#powAssign(Object, Object)}. */
@Test
public void testPowAssign() {
final Variable v = new Variable("v");
e.set(v, 2.5d); assertAssigned(15.625d, v, e.powAssign(v, 3));
e.set(v, bi(5)); assertAssigned(bi(15625), v, e.powAssign(v, 6));
e.set(v, bd(2.5)); assertAssigned(bd(15.625), v, e.powAssign(v, 3));
}
/** Tests {@link DefaultEvaluator#dotPowAssign(Object, Object)}. */
@Test
public void testDotPowAssign() {
// NB: Nothing to test; dotPow is unimplemented.
}
/** Tests {@link DefaultEvaluator#mulAssign(Object, Object)}. */
@Test
public void testMulAssign() {
final Variable v = new Variable("v");
e.set(v, 4); assertAssigned(24, v, e.mulAssign(v, 6));
e.set(v, 4L); assertAssigned(24L, v, e.mulAssign(v, 6L));
e.set(v, 2.5f); assertAssigned(8.75f, v, e.mulAssign(v, 3.5f));
e.set(v, 2.5d); assertAssigned(8.75d, v, e.mulAssign(v, 3.5d));
e.set(v, bi(4)); assertAssigned(bi(24), v, e.mulAssign(v, bi(6)));
e.set(v, bd(2.5)); assertAssigned(bd(8.75), v, e.mulAssign(v, bd(3.5)));
}
/** Tests {@link DefaultEvaluator#divAssign(Object, Object)}. */
@Test
public void testDivAssign() {
final Variable v = new Variable("v");
e.set(v, 27); assertAssigned(4, v, e.divAssign(v, 6));
e.set(v, 27L); assertAssigned(4L, v, e.divAssign(v, 6L));
e.set(v, 8.75f); assertAssigned(2.5f, v, e.divAssign(v, 3.5f));
e.set(v, 8.75d); assertAssigned(2.5d, v, e.divAssign(v, 3.5d));
e.set(v, bi(27)); assertAssigned(bi(4), v, e.divAssign(v, bi(6)));
e.set(v, bd(8.75)); assertAssigned(bd(2.5), v, e.divAssign(v, bd(3.5)));
}
/** Tests {@link DefaultEvaluator#modAssign(Object, Object)}. */
@Test
public void testModAssign() {
final Variable v = new Variable("v");
e.set(v, 27); assertAssigned(3, v, e.modAssign(v, 6));
e.set(v, 27L); assertAssigned(3L, v, e.modAssign(v, 6L));
e.set(v, 8.75f); assertAssigned(1.75f, v, e.modAssign(v, 3.5f));
e.set(v, 8.75d); assertAssigned(1.75d, v, e.modAssign(v, 3.5d));
e.set(v, bi(27)); assertAssigned(bi(3), v, e.modAssign(v, bi(6)));
e.set(v, bd(8.75)); assertAssigned(bd(1.75), v, e.modAssign(v, bd(3.5)));
}
/** Tests {@link DefaultEvaluator#rightDivAssign(Object, Object)}. */
@Test
public void testRightDivAssign() {
// NB: Nothing to test; rightDiv is unimplemented.
}
/** Tests {@link DefaultEvaluator#dotDivAssign(Object, Object)}. */
@Test
public void testDotDivAssign() {
// NB: Nothing to test; dotDiv is unimplemented.
}
/** Tests {@link DefaultEvaluator#dotRightDivAssign(Object, Object)}. */
@Test
public void testDotRightDivAssign() {
// NB: Nothing to test; dotRightDiv is unimplemented.
}
/** Tests {@link DefaultEvaluator#addAssign(Object, Object)}. */
@Test
public void testAddAssign() {
final Variable v = new Variable("v");
e.set(v, "Hello,");
assertAssigned("Hello, world", v, e.addAssign(v, " world"));
e.set(v, 4); assertAssigned(10, v, e.addAssign(v, 6));
e.set(v, 4L); assertAssigned(10L, v, e.addAssign(v, 6L));
e.set(v, 1.5f); assertAssigned(3.6f, v, e.addAssign(v, 2.1f));
e.set(v, 1.5d); assertAssigned(3.6d, v, e.addAssign(v, 2.1d));
e.set(v, bi(4)); assertAssigned(bi(10), v, e.addAssign(v, bi(6)));
e.set(v, bd(1.5)); assertAssigned(bd(3.6), v, e.addAssign(v, bd(2.1)));
}
/** Tests {@link DefaultEvaluator#subAssign(Object, Object)}. */
@Test
public void testSubAssign() {
final Variable v = new Variable("v");
e.set(v, 10); assertAssigned(4, v, e.subAssign(v, 6));
e.set(v, 10L); assertAssigned(4L, v, e.subAssign(v, 6L));
e.set(v, 3.6f); assertAssigned(1.5f, v, e.subAssign(v, 2.1f));
e.set(v, 3.6d); assertAssigned(1.5d, v, e.subAssign(v, 2.1d));
e.set(v, bi(10)); assertAssigned(bi(4), v, e.subAssign(v, bi(6)));
e.set(v, bd(3.6)); assertAssigned(bd(1.5), v, e.subAssign(v, bd(2.1)));
}
/** Tests {@link DefaultEvaluator#andAssign(Object, Object)}. */
@Test
public void testAndAssign() {
final Variable v = new Variable("v");
e.set(v, 0xcafebabe); assertAssigned(0xcaacbaae, v, e.andAssign(v, 0xdeadbeef));
e.set(v, 0x0d0e0a0d0c0a0f0eL); assertAssigned(0L, v, e.andAssign(v, 0xb0e0e0f0b0a0b0e0L));
e.set(v, bi(0xcafebabeL)); assertAssigned(bi(0xcaacbaaeL), v, e.andAssign(v, bi(0xdeadbeefL)));
}
/** Tests {@link DefaultEvaluator#orAssign(Object, Object)}. */
@Test
public void testOrAssign() {
final Variable v = new Variable("v");
e.set(v, 0xcafebabe); assertAssigned(0xdeffbeff, v, e.orAssign(v, 0xdeadbeef));
e.set(v, 0x0d0e0a0d0c0a0f0eL); assertAssigned(0xbdeeeafdbcaabfeeL, v, e.orAssign(v, 0xb0e0e0f0b0a0b0e0L));
e.set(v, bi(0xcafebabeL)); assertAssigned(bi(0xdeffbeffL), v, e.orAssign(v, bi(0xdeadbeefL)));
}
/** Tests {@link DefaultEvaluator#leftShiftAssign(Object, Object)}. */
@Test
public void testLeftShiftAssign() {
final Variable v = new Variable("v");
e.set(v, 0xcafebabe); assertAssigned(0xafebabe0, v, e.leftShiftAssign(v, 4));
e.set(v, 0xdeadcafebeefbabeL); assertAssigned(0xdcafebeefbabe000L, v, e.leftShiftAssign(v, 12));
e.set(v, bi(57)); assertAssigned(bi(7296), v, e.leftShiftAssign(v, 7));
}
/** Tests {@link DefaultEvaluator#rightShiftAssign(Object, Object)}. */
@Test
public void testRightShiftAssign() {
final Variable v = new Variable("v");
e.set(v, 0xcafebabe); assertAssigned(0xfcafebab, v, e.rightShiftAssign(v, 4));
e.set(v, 0xdeadcafebeefbabeL); assertAssigned(0xfffdeadcafebeefbL, v, e.rightShiftAssign(v, 12));
e.set(v, bi(8920)); assertAssigned(bi(278), v, e.rightShiftAssign(v, 5));
}
/** Tests {@link DefaultEvaluator#unsignedRightShiftAssign(Object, Object)}. */
@Test
public void testUnsignedRightShiftAssign() {
final Variable v = new Variable("v");
e.set(v, 0xcafebabe); assertAssigned(0x0cafebab, v, e.unsignedRightShiftAssign(v, 4));
e.set(v, 0xdeadcafebeefbabeL); assertAssigned(0x000deadcafebeefbL, v, e.unsignedRightShiftAssign(v, 12));
}
// -- Helper methods --
/** Widens the given object to an {@link Object}. */
private Object o(final Object o) { return o; }
private BigInteger bi(final Object o) { return new BigInteger(o.toString()); }
private BigDecimal bd(final Object o) { return new BigDecimal(o.toString()); }
private void assertAssigned(final Object expected, final Variable v,
final Object result)
{
assertSame(v, result);
assertEquals(expected, e.get(v));
}
}