// ----------------------------------------------------------------------------
// Options
options {
JAVA_UNICODE_ESCAPE = true;
}
// ----------------------------------------------------------------------------
// Parser Begin
PARSER_BEGIN(ExpressionParser)
package prefuse.data.expression.parser;
import java.io.StringReader;
import java.util.logging.Logger;
import prefuse.data.expression.AndPredicate;
import prefuse.data.expression.ArithmeticExpression;
import prefuse.data.expression.BooleanLiteral;
import prefuse.data.expression.ColumnExpression;
import prefuse.data.expression.ComparisonPredicate;
import prefuse.data.expression.Expression;
import prefuse.data.expression.Function;
import prefuse.data.expression.FunctionTable;
import prefuse.data.expression.IfExpression;
import prefuse.data.expression.NotPredicate;
import prefuse.data.expression.NumericLiteral;
import prefuse.data.expression.ObjectLiteral;
import prefuse.data.expression.OrPredicate;
import prefuse.data.expression.Predicate;
import prefuse.data.expression.XorPredicate;
import prefuse.util.StringLib;
/**
* Parser for statements written in the prefuse expression language. Text
* expression are parsed into {@link prefuse.data.expression.Expression}
* instances, and can be used as predicates or to create derived
* table columns. This parser is implemented using the
* JavaCC package. To parse
* a text String to an {@link prefuse.data.expression.Expression}, use
* the {@link #parse(String)} method. If a parse error occurs, the method
* will fail silently and return null. Any generated exception can be
* later retrieved using the {@link #getError()} method. One can also
* use the {@link #parse(String, boolean)} with a true
* boolean argument to request that Exceptions be thrown when
* errors occur.
*
*
Prefuse Expression Language Reference
*
* The prefuse expression language provides a convenient way of creating manipulable statements
* over data in a prefuse data structure. For example, the expression language can be used to
* write {@link prefuse.data.expression.Predicate} instances for querying and filtering a table
* or graph, or to create arbitrary expressions over a data set to generate new, derived data
* fields that can in turn be subject to additional processing or visualization. For example,
* the {@link prefuse.data.tuple.TupleSet#tuples(prefuse.data.expression.Predicate)} method
* uses a Predicate to filter the requested set of tuples, and the
* {@link prefuse.data.Table#addColumn(java.lang.String,prefuse.data.expression.Expression)}
* method creates a new table column whose values are generated by the provided Expression.
* The expression machinery is used
* throughout the toolkit -- it underlies the filtering and query optimization features,
* is a key component of {@link prefuse.data.query dynamic query bindings}, and is used to
* create the rule chains evaluated by the
* {@link prefuse.render.DefaultRendererFactory},
* {@link prefuse.action.assignment.ColorAction},
* {@link prefuse.action.assignment.ShapeAction},
* {@link prefuse.action.assignment.FontAction}, and
* {@link prefuse.action.assignment.SizeAction} classes.
*
*
* The {@link prefuse.data.expression.Expression} interface is quite simple: given a single
* Tuple, compute and return a value. The returned value could be an Object, a boolean, an int,
* or other primitive type. Individual methods for each type are available, and which ones are
* legal to call for any given Expression depends on the type of Expression.
*
*
* Expressions can be created directly in Java, by instantiating and chaining together the
* desired Expression instances. This process, however, can be somewhat tedious, so prefuse
* also provides a built-in parser/compiler for generating these chains of Expression
* instances from a textual language. The language is based on a subset of SQL, the
* standard language for database queries. If you have ever written a "WHERE" clause in
* a SQL "SELECT" query, you probably know most of the language already. To parse an
* expression, simply pass a text string containing an expression statement to the
* {@link prefuse.data.expression.parser.ExpressionParser#parse(java.lang.String)}
* method. If the string parses successfully, the parsed Expression instance will be
* returned.
*
*
* Below is the reference for the language, including literal types, data field references,
* basic operators, and included functions. If need be, you can also introduce a new
* function by creating a new instance of the {@link prefuse.data.expression.Function} interface
* and registering it with the {@link prefuse.data.expression.FunctionTable} class.
*
*
* All keywords and functions in the prefuse expression language can be written in
* either uppercase or lowercase. Writing in mixed-case, however, will likely result in parse
* errors.
*
*
* Literal Values and Data Field References
* The fundamental building blocks of the expression language, representing data values
* or referencing the contents of a Tuple data field.
*
* - Boolean literals (
TRUE, FALSE
)
* The boolean literals representing true and false conditions, parsed to type boolean
*
* - Integer literals (
1, -5, 12340
)
* Undecorated, non-decimal numbers are parsed as numbers of type int
*
* - Long literals (
1L, -5L, 12340L
)
* Integer values decorated with the suffix "L" are parsed as numbers of type long
*
* - Double literals (
1.0, 3.1415, 1e-35, 2.3e6
)
* Numbers with decimals or exponents in scientific notation are parsed as numbers of type double
*
* - Float literals (
1.0f, 3.1415f, 1e-35f, 2.3e6f
)
* Floating-point values decorated with the suffix "f" are parsed as numbers of type float
*
* - String literals (
"some text", 'a label'
)
* Text strings placed in double (") or single (') quotations are parsed as String
literals
*
* - Null literal (
null
)
* The string null
is parsed as an ObjectLiteral of type null.
*
* - Data field references (
_strokeColor, [a data field]
)
* Free-standing strings or those placed within brackets are parsed as a reference to the
* data field of that name. Brackets are required for any fields that include spaces or other
* unusual characters in their name (e.g., characters like +, -, *, etc), or conflict with
* an existing keyword For example, true
parses to a boolean literal while
* [true]
parses to a reference to a data field named 'true'.
*
*
*
* Operators and Control Flow
* Basic operators and control flow structures for the expression language.
*
* x + y
(addition)
* Add x
and y
*
* x - y
(subtraction)
* Subtract y
from x
*
* x * y
(multiplication)
* Multiply x
and y
*
* x / y
(division)
* Divide x
by y
*
* x ^ y
(exponentiation, pow)
* Raise x
to the exponent y
*
* x % y
(modulo)
* Return the remainder of x
divded by y
*
* x = y, x == y
(equality)
* Indicates if x
and y
are equal
*
* x != y, x <> y
(inequality)
* Indicates if x
and y
are not equal
*
* x > y
(greater than)
* Indicates if x
is greater than y
*
* x >= y
(greater than or equal to)
* Indicates if x
is greater than or equal to y
*
* x < y
(less than)
* Indicates if x
is less than y
*
* x <= y
(less than or equal to)
* Indicates if x
is less than or equal to y
*
* x AND y, x && y
(and)
* Indicates if both x
and y
are true
*
* x OR y, x || y
(or)
* Indicates if either x
or y
is true
*
* NOT x, !x
(not)
* Indicates if the negation of x
is true
*
* x XOR y
(exclusive or)
* Indicates if one, but not both, of x
or y
is true
*
* IF test THEN x ELSE y
(if-then-else)
* Evaluates the predicate test
, and if true evaluates and returns the
* expression x
, and if false evaluates and returns the expression
* y
*
* ()
(parentheses)
* Groups expressions together to enfore a particular order of evaluation. For example,
* 1+2*3
evaluates to 7
, while (1+2)*3
evaluates
* to 9
.
*
*
*
* General Functions
* General purpose functions.
*
* ROW()
* Returns the table row number (or -1 if none) of the current Tuple.
*
* ISNODE()
* Returns true if the current Tuple is a graph Node.
*
* ISEDGE()
* Returns true if the current Tuple is a graph Edge.
*
* DEGREE()
* If the current Tuple is graph Node, returns the Node degree
* (the total number of incident edges). Otherwise returns 0.
*
* INDEGREE()
* If the current Tuple is graph Node, returns the Node indegree
* (the number of incident edges pointing towards this node).
* Otherwise returns 0.
*
* OUTDEGREE()
* If the current Tuple is graph Node, returns the Node outdegree
* (the number of incident edges pointing away from the node).
* Otherwise returns 0.
*
* CHILDCOUNT()
* If the current Tuple is graph Node, returns the number of tree
* children nodes. If the Tuple is not a Node, this method returns 0.
* If the Node is part of a Graph (not a Tree), the number of children
* nodes in the current spanning tree is returned. If no spanning tree has
* been computed, a new spanning tree will be computed using the default
* method. See {@link prefuse.data.Graph#getSpanningTree()} for more.
*
* TREEDEPTH()
* If the current Tuple is graph Node, returns the depth of this Node
* in its Tree or SpanningTree. If the Tuple is not a Node, this method
* returns 0. If the Node is part of a Graph (not a Tree), the tree depth
* of the node in the current spanning tree is returned. If no spanning
* tree has been computed, a new spanning tree will be computed using the
* default method. See {@link prefuse.data.Graph#getSpanningTree()} for
* more.
*
*
*
* Mathematical Functions
* Functions for performing mathematical calculations.
*
* ABS(x)
* Returns the absolute value of x
*
* ACOS(x)
* Returns the inverse cosine (arc cosine) of a x
*
* ASIN(x)
* Returns the inverse sine (arc sine) of a x
*
* ATAN(x)
* Returns the inverse tangent (arc tangent) of a x
*
* ATAN2(y, x)
* For the Cartesian coordinates x
, y
return the polar coordinate angle theta
*
* CEIL(x), CEILING(x)
* Returns the nearest integer value greater than or equal to x
.
*
* COS(x)
* Returns the cosine of x
*
* COT(x)
* Returns the cotangent of x
*
* DEGREES(x)
* Converts x
from radians to degrees
*
* EXP(x)
* Returns the value of e (the base of natural logarithms) raised to the x
power
*
* FLOOR(x)
* Returns the nearest integer value less than or equal to x
.
*
* LOG(x), LOG(b, x)
* With one argument, returns the natural logarithm (logarithm base e) of x
* With two arguments, returns the logarithm of x
for the provided base b
*
* LOG2(x)
* Returns the logarithm base 2 of x
*
* LOG10(x)
* Returns the logarithm base 10 of x
*
* MAX(a, b, c, ...)
* Returns the maximum value among the provided arguments
*
* MIN(a, b, c, ...)
* Returns the minimum value among the provided arguments
*
* MOD(x, y)
* Returns x
modulo y
(the remainder of x
divided by y
)
*
* PI()
* Returns the constant π (= 3.1415926535...), the ratio between the circumference and diameter of a circle
*
* POW(x, y), POWER(x, y)
* Return the value of x
raised to the exponent y
*
* RADIANS(x)
* Converts x
from degrees to radians
*
* RAND()
* Returns a random floating-point value between 0 and 1
*
* ROUND(x)
* Returns the value of x
rounded to the nearest integer
*
* SIGN(x)
* Returns the sign of x
: 1 for positive, -1 for negative
*
* SIN(x)
* Returns the sine of x
*
* SQRT(x)
* Returns the square root of x
*
* SUM(a, b, c, ...)
* Returns the sum of the provided input value
*
* TAN(x)
* Returns the tangent of x
*
* SAFELOG10(x)
* Returns a "negative safe" logarithm base 10 of x
, equivalent to
* SIGN(x) * LOG10(ABS(x))
*
* POW(x)
* Returns a "negative safe" square root of x
, equivalent to
* SIGN(x) * SQRT(ABS(x))
*
*
*
* String Functions
* Functions for processing text strings.
*
* CAP(str)
* Capitalize words in the string str
. Individual words/names will be given
* uppercase first letters, with all other letters in lowercase.
*
* CONCAT(a, b, c, ...)
* Concatenate the input strings into one resulting string.
*
* CONCAT_WS(sep, a, b, c, ...)
* Concatenate with separator. Concatenates the input strings into one resulting
* string, placing the string sep
between each of the other arguments
*
* FORMAT(x, d)
* Format the number x
as a string of the type "#,###.##", showing d
decimal places
*
* INSERT(str, pos, len, newstr)
* Replaces the substring of length len
starting at position pos
in input
* string str
with the string newstr
*
* LEFT(str, len)
* Returns the leftmost len
characters of string str
*
* LENGTH(str)
* Returns the length, in characters, of the input string str
*
* LOWER(str), LCASE(str)
* Returns the string str
mapped to lowercase letters
*
* LPAD(str, len, pad)
* Pad the left side of string str
with copies of string pad
,
* up to a total padding of len
characters
*
* MID(str, pos, len)
* Return a substring of str
of length len
, starting at
* position pos
*
* POSITION(substr, str)
* Returns the starting position of the first occurrence of substring substr
* in the string str
. Returns -1 if the substring is not found.
*
* REVERSE(str)
* Returns a reversed copy of the input string str
*
* REPEAT(str, count)
* Returns a string consisting of str
repeated count
times
*
* REPLACE(str, orig, replace)
* Returns a copy of str
in which all occurrences of orig
have been
* replaced by replace
*
* RIGHT(str, len)
* Returns the len
rightmost characters of stringstr
*
* RPAD(x)
* Pad the right side of string str
with copies of string pad
,
* up to a total padding of len
characters
*
* SPACE(n)
* Returns a string consisting of n
whitespace characters
*
* SUBSTRING(str,pos), SUBSTRING(str,pos,len)
* For two arguments, returns the substring of str
starting at position
* pos
and continuing to the end of the string.
* For three arguments, returns the substring of str
of length len
,
* beginning at position pos
*
* UPPER(str), UCASE(str
* Returns the string str
mapped to uppercase letters
*
*
*
* Color Functions
* Functions for generating, translating, and interpolating color values.
*
* RGB(r, g, b)
* Returns an integer representing a fully opaque RGB (red, green, blue) color value
*
* RGBA(r, g, b, a)
* Returns an integer representing an RGBA (red, green, blue, alpha/transparency) color value
*
* GRAY(v)
* Returns an integer representing a grayscale color value of intensity v
*
* HEX(hex)
* Returns an integer representing the RGB color value encoded by the hexadecimal number
* hex
*
* HSB(h, s, b)
* Maps the given hue (hue
), saturation (s
), and brightness
* (b
) color space values (as floating point numbers between 0 and 1) to
* an integer representing an RGB color value
*
* HSBA(h, s, b, a)
* Maps the given hue (hue
), saturation (s
), brightness
* (b
), and alpha (a
) color space values (as floating point
* numbers between 0 and 1) to an integer representing an RGBA color value
*
* COLORINTERP(c1, c2, f)
* Returns an interpolated color value between the input colors c1
and
* c2
determined by the mixing proportion f
, a value
* between 0 and 1
*
*
*
* Visualization Functions
* These functions can only be used when the Tuple being evaluated is
* a VisualItem, and provide access to data group information of the VisualItem's
* Visualization. Individual visual data fields can be accessed directly using
* a data field reference. For example, _x
, _y
,
* _hover
, _highlight
, _fillColor
would
* evaluate to references for the x-coordinate, y-coordinate, mouse hover status,
* highlight status, and fill color, respectively.
*
* GROUPSIZE(group)
* Returns the number of members in the data group group
*
* INGROUP(group)
* Returns true if the current VisualItem is a member of data group group
*
* MATCH(group, includeAll)
* Returns true if the current VisualItem is currently a search match. This is similar
* to INGROUP(group)
, but also includes a possible special case when no
* query has been issued and all items should be counted as "matches" (indicated
* by includeAll
being true).
*
* QUERY(group)
* Returns the current search query string in a search group of name group
*
* VISIBLE()
* Returns true if the current VisualItem is visible, equivalent to _visible
*
* VALIDATED()
* Returns true if the current VisualItem's bounds have been validated,
* equivalent to _validated
*
*
*
* @author jeffrey heer
*/
public class ExpressionParser {
private static final Logger s_logger
= Logger.getLogger(ExpressionParser.class.getName());
private static boolean s_init = false;
private static Throwable s_error;
/**
* Parse an expression.
* @param expr the expression text to parse
* @param throwsException true if this method should throw an
* exception if an error occurs or should fail quietly
* @return the parsed Expression, or null if the parse failed
* and throwsException is false
*/
public synchronized static Expression parse(String expr,
boolean throwsException)
{
// initialize the parser
if ( !s_init ) {
new ExpressionParser(new StringReader(expr));
s_init = true;
} else {
ExpressionParser.ReInit(new StringReader(expr));
}
// attempt to parse the expression
try {
Expression e = Parse();
s_error = null;
s_logger.info("Parsed Expression: "+e);
return e;
} catch ( ParseException t ) {
s_error = t;
if ( throwsException ) {
throw t;
} else {
s_logger.warning("Expression Parse Error: " + t.getMessage()
+ "\n" + StringLib.getStackTrace(t));
return null;
}
}
}
/**
* Parse an expression. This method does not throw an exception if
* a parse error occurs. Use {@link #getError()} to access any
* generated exceptions.
* @param expr the expression text to parse
* @return the parsed Expression, or null if the parse failed
*/
public synchronized static Expression parse(String expr) {
return parse(expr, false);
}
/**
* Parse an expression as a predicate. This method does not throw an
* exception if a parse error occurs. Use {@link #getError()} to access
* any generated exceptions.
* @param expr the expression text to parse
* @return the parsed Expression, or null if the parse failed
*/
public synchronized static Predicate predicate(String expr) {
Expression ex = parse(expr, false);
if ( ex == null ) {
return null;
} else if ( ex instanceof Predicate ) {
return (Predicate) ex;
} else {
s_error = new ClassCastException("Expression is not a predicate");
return null;
}
}
/**
* Get the last error, if any, generated by a parse operation.
* @return the last error generated during parsing
*/
public synchronized static Throwable getError() {
return s_error;
}
/**
* Replace escape sequences with represented characters. This
* includes newlines, tabs, and quotes.
* @param s the input String, possibly with escape sequences
* @return a String with recognized escape sequences properly replaced
*/
private static String unescape(String s) {
int len = s.length(), base = 0, idx;
String escapes = "tnrbf\\\"'";
String chars = "\t\n\r\b\f\\\"'";
StringBuffer sbuf = null;
while ( (idx=s.indexOf('\\',base)) != -1) {
if ( sbuf != null )
sbuf.append(s.substring(base, idx));
if (idx+1 == len) break;
// find escape character
char c = s.charAt(idx+1);
// find the index of the escape character
int cidx = escapes.indexOf(c);
if (cidx == -1) {
// no match, so continue
sbuf.append('\\');
sbuf.append(c);
} else {
// replace escape sequence with true char
if ( sbuf == null )
sbuf = new StringBuffer(s.substring(base, idx));
sbuf.append(chars.charAt(cidx));
}
// skip over escape sequence
base = idx + 2;
}
if ( sbuf != null && base < len )
sbuf.append(s.substring(base));
return ( sbuf == null ? s : sbuf.toString() );
}
} // end of class ExpressionParser
PARSER_END(ExpressionParser)
// ----------------------------------------------------------------------------
// Token definitions
/* characters to skip */
SKIP : { " " | "\t" | "\n" | "\r" | "\f" }
/* keywords */
TOKEN : {
< TRUE : "TRUE"|"true" >
| < FALSE : "FALSE"|"false" >
| < NULL : "NULL"|"null" >
| < IF : "IF"|"if" >
| < THEN : "THEN"|"then" >
| < ELSE : "ELSE"|"else" >
| < AND : "AND"|"and"|"&&" >
| < OR : "OR"|"or"|"||" >
| < NOT : "NOT"|"not"|"!" >
| < XOR : "XOR"|"xor" >
}
/* literal values */
TOKEN : {
< INT : | | >
| < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
| < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
| < #OCTAL_LITERAL: "0" (["0"-"7"])* >
| < LONG : ["l","L"] >
| < DOUBLE :
(["0"-"9"])+ "." (["0"-"9"])* ()?
| "." (["0"-"9"])* ()?
| (["0"-"9"])+
>
| < FLOAT : ["f","F"] >
| < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ >
| < STRING:
"\""
( (~["\"","\\","\n","\r"])
| ("\\"
( ["n","t","b","r","f","\\","'","\""]
| ["0"-"7"] ( ["0"-"7"] )?
| ["0"-"3"] ["0"-"7"] ["0"-"7"]
)
)
)*
"\""
|
"'"
( (~["'","\\","\n","\r"])
| ("\\"
( ["n","t","b","r","f","\\","'","\""]
| ["0"-"7"] ( ["0"-"7"] )?
| ["0"-"3"] ["0"-"7"] ["0"-"7"]
)
)
)*
"'"
>
}
/* identifiers */
TOKEN : {
< QUOTED: "[" (~["]"])+ "]" >
| < IDENTIFIER: (|)* >
| < #LETTER:
[
"\u0024",
"\u0041"-"\u005a",
"\u005f",
"\u0061"-"\u007a",
"\u00c0"-"\u00d6",
"\u00d8"-"\u00f6",
"\u00f8"-"\u00ff",
"\u0100"-"\u1fff",
"\u3040"-"\u318f",
"\u3300"-"\u337f",
"\u3400"-"\u3d2d",
"\u4e00"-"\u9fff",
"\uf900"-"\ufaff"
]
>
| < #DIGIT:
[
"\u0030"-"\u0039",
"\u0660"-"\u0669",
"\u06f0"-"\u06f9",
"\u0966"-"\u096f",
"\u09e6"-"\u09ef",
"\u0a66"-"\u0a6f",
"\u0ae6"-"\u0aef",
"\u0b66"-"\u0b6f",
"\u0be7"-"\u0bef",
"\u0c66"-"\u0c6f",
"\u0ce6"-"\u0cef",
"\u0d66"-"\u0d6f",
"\u0e50"-"\u0e59",
"\u0ed0"-"\u0ed9",
"\u1040"-"\u1049"
]
>
}
/* separators */
TOKEN : {
< LPAREN: "(" >
| < RPAREN: ")" >
}
/* operators */
TOKEN : {
< EQ: "=" | "==" >
| < GT: ">" >
| < LT: "<" >
| < LE: "<=" >
| < GE: ">=" >
| < NE: "!=" | "<>" >
| < ADD: "+" >
| < SUB: "-" >
| < MUL: "*" >
| < DIV: "/" >
| < POW: "^" >
| < MOD: "%" >
}
// ----------------------------------------------------------------------------
// Grammar definitions
String Name() :
{ Token t; }
{
t= { return t.image; }
}
String Quoted() :
{ Token t; }
{
t= { return t.image.substring(1,t.image.length()-1); }
}
Expression Parse() :
{ Expression e; }
{
e=Expression() { return e; }
| { throw new ParseException("No expression provided"); }
}
Expression Expression() :
{ Expression e; }
{
e=OrExpression() { return e; }
}
Expression OrExpression() :
{ Expression l, r; }
{
l=XorExpression() ( r=XorExpression()
{
if ( l instanceof OrPredicate ) {
((OrPredicate)l).add((Predicate)r);
} else {
l = new OrPredicate((Predicate)l,(Predicate)r);
}
}
)* { return l; }
}
Expression XorExpression() :
{ Expression l, r; }
{
l=AndExpression() ( r=AndExpression()
{
if ( l instanceof XorPredicate ) {
((XorPredicate)l).add((Predicate)r);
} else {
l = new XorPredicate((Predicate)l,(Predicate)r);
}
}
)* { return l; }
}
Expression AndExpression() :
{ Expression l, r; }
{
l=EqualityExpression() ( r=EqualityExpression()
{
if ( l instanceof AndPredicate ) {
((AndPredicate)l).add((Predicate)r);
} else {
l = new AndPredicate((Predicate)l,(Predicate)r);
}
}
)* { return l; }
}
Expression EqualityExpression() :
{ Expression l, r; Token t; int op; }
{
l=RelationalExpression() (
( t= | t= ) r=RelationalExpression()
{
op = (t.kind==EQ ? ComparisonPredicate.EQ : ComparisonPredicate.NEQ);
l = new ComparisonPredicate(op, l, r);
}
)* { return l; }
}
Expression RelationalExpression() :
{ Expression l, r; Token t; int op=-1; }
{
l=AdditiveExpression() (
( t= | t= | t= | t= ) r=AdditiveExpression()
{
switch ( t.kind ) {
case LT:
op = ComparisonPredicate.LT;
break;
case GT:
op = ComparisonPredicate.GT;
break;
case LE:
op = ComparisonPredicate.LTEQ;
break;
case GE:
op = ComparisonPredicate.GTEQ;
break;
}
l = new ComparisonPredicate(op, l, r);
}
)* { return l; }
}
Expression AdditiveExpression() :
{ Expression l, r; Token t; int op=-1; }
{
l=MultiplicativeExpression() (
( t= | t= | t= ) r=MultiplicativeExpression()
{
switch ( t.kind ) {
case ADD:
op = ArithmeticExpression.ADD;
break;
case SUB:
op = ArithmeticExpression.SUB;
break;
case MOD:
op = ArithmeticExpression.MOD;
break;
}
l = new ArithmeticExpression(op, l, r);
}
)* { return l; }
}
Expression MultiplicativeExpression() :
{ Expression l, r; Token t; int op=-1; }
{
l=UnaryExpression() (
( t= | t= | t=
) r=UnaryExpression()
{
switch ( t.kind ) {
case MUL:
op = ArithmeticExpression.MUL;
break;
case DIV:
op = ArithmeticExpression.DIV;
break;
case POW:
op = ArithmeticExpression.POW;
break;
}
l = new ArithmeticExpression(op, l, r);
}
)* { return l; }
}
Expression UnaryExpression() :
{ Expression e; Token t;}
{
( t= | t= ) e=UnaryExpression() {
if ( t.kind == SUB && e instanceof NumericLiteral ) {
Number n = (Number)e.get(null);
if ( n instanceof Integer ) {
return new NumericLiteral(-1*n.intValue());
} if ( n instanceof Double ) {
return new NumericLiteral(-1*n.doubleValue());
} if ( n instanceof Long ) {
return new NumericLiteral(-1*n.longValue());
} if ( n instanceof Float ) {
return new NumericLiteral(-1*n.floatValue());
} else {
return new ArithmeticExpression(ArithmeticExpression.MUL,
new NumericLiteral(-1), e);
}
} else if ( t.kind == SUB ) {
return new ArithmeticExpression(ArithmeticExpression.MUL,
new NumericLiteral(-1), e);
} else {
return e;
}
}
| e=UnaryExpressionNotPlusMinus() { return e; }
| e=PrimaryExpression() { return e; }
}
Expression UnaryExpressionNotPlusMinus() :
{ Expression e; }
{
e=UnaryExpression() {
if ( e instanceof NotPredicate ) {
return ((NotPredicate)e).getPredicate();
} else {
if ( !(e instanceof Predicate) ) {
throw new ParseException("Can't negate a non-predicate");
} else {
return new NotPredicate((Predicate)e);
}
}
}
}
Expression PrimaryExpression() :
{ Expression e; }
{
e=Literal() { return e; }
| e=IfStatement() { return e; }
| e=Identifier() { return e; }
| e=Expression() { return e; }
}
Expression Literal() :
{ Token t; }
{
t= { return new NumericLiteral(Integer.parseInt(t.image)); }
| t= { return new NumericLiteral(Long.parseLong(t.image.substring(0,t.image.length()-1))); }
| t= { return new NumericLiteral(Float.parseFloat(t.image)); }
| t= { return new NumericLiteral(Double.parseDouble(t.image)); }
| t= {
String s = unescape(t.image.substring(1, t.image.length()-1));
return new ObjectLiteral(s); }
| { return new BooleanLiteral(true); }
| { return new BooleanLiteral(false); }
| { return new ObjectLiteral(null); }
}
Expression Identifier() :
{ String s; Function f=null; Expression e; }
{
s=Quoted() { return new ColumnExpression(s); }
| s=Name()
( { f = FunctionTable.createFunction(s); }
( e=Expression() { f.addParameter(e); }
("," e=Expression() { f.addParameter(e); } )* )?
)?
{ return f==null ? new ColumnExpression(s) : (Expression)f; }
}
Expression IfStatement() :
/*
* The disambiguating algorithm of JavaCC automatically binds dangling
* else's to the innermost if statement. The LOOKAHEAD specification
* is to tell JavaCC that we know what we are doing.
*/
{ Expression p, t, e; }
{
p=Expression() t=Expression() e=Expression()
{
if ( !(p instanceof Predicate) )
throw new ParseException("IF-statement test must be a predicate");
return new IfExpression((Predicate)p, t, e);
}
}