📄 expressionparser.jj
字号:
* Returns a "negative safe" logarithm base 10 of <code>x</code>, equivalent to
* <code>SIGN(x) * LOG10(ABS(x))</code>
* </li>
* <li><strong><code>POW(x)</code></strong><br/>
* Returns a "negative safe" square root of <code>x</code>, equivalent to
* <code>SIGN(x) * SQRT(ABS(x))</code>
* </li>
* </ul>
*
* <h2>String Functions</h2>
* <p>Functions for processing text strings.</p>
* <ul>
* <li><strong><code>CAP(str)</code></strong><br/>
* Capitalize words in the string <code>str</code>. Individual words/names will be given
* uppercase first letters, with all other letters in lowercase.
* </li>
* <li><strong><code>CONCAT(a, b, c, ...)</code></strong><br/>
* Concatenate the input strings into one resulting string.
* </li>
* <li><strong><code>CONCAT_WS(sep, a, b, c, ...)</code></strong><br/>
* Concatenate with separator. Concatenates the input strings into one resulting
* string, placing the string <code>sep</code> between each of the other arguments
* </li>
* <li><strong><code>FORMAT(x, d)</code></strong><br/>
* Format the number <code>x</code> as a string of the type "#,###.##", showing <code>d</code> decimal places
* </li>
* <li><strong><code>INSERT(str, pos, len, newstr)</code></strong><br/>
* Replaces the substring of length <code>len</code> starting at position <code>pos</code> in input
* string <code>str</code> with the string <code>newstr</code>
* </li>
* <li><strong><code>LEFT(str, len)</code></strong><br/>
* Returns the leftmost <code>len</code> characters of string <code>str</code>
* </li>
* <li><strong><code>LENGTH(str)</code></strong><br/>
* Returns the length, in characters, of the input string <code>str</code>
* </li>
* <li><strong><code>LOWER(str), LCASE(str)</code></strong><br/>
* Returns the string <code>str</code> mapped to lowercase letters
* </li>
* <li><strong><code>LPAD(str, len, pad)</code></strong><br/>
* Pad the left side of string <code>str</code> with copies of string <code>pad</code>,
* up to a total padding of <code>len</code> characters
* </li>
* <li><strong><code>MID(str, pos, len)</code></strong><br/>
* Return a substring of <code>str</code> of length <code>len</code>, starting at
* position <code>pos</code>
* </li>
* <li><strong><code>POSITION(substr, str)</code></strong><br/>
* Returns the starting position of the first occurrence of substring <code>substr</code>
* in the string <code>str</code>. Returns -1 if the substring is not found.
* </li>
* <li><strong><code>REVERSE(str)</code></strong><br/>
* Returns a reversed copy of the input string <code>str</code>
* </li>
* <li><strong><code>REPEAT(str, count)</code></strong><br/>
* Returns a string consisting of <code>str</code> repeated <code>count</code> times
* </li>
* <li><strong><code>REPLACE(str, orig, replace)</code></strong><br/>
* Returns a copy of <code>str</code> in which all occurrences of <code>orig</code> have been
* replaced by <code>replace</code>
* </li>
* <li><strong><code>RIGHT(str, len)</code></strong><br/>
* Returns the <code>len</code> rightmost characters of string<code>str</code>
* </li>
* <li><strong><code>RPAD(x)</code></strong><br/>
* Pad the right side of string <code>str</code> with copies of string <code>pad</code>,
* up to a total padding of <code>len</code> characters
* </li>
* <li><strong><code>SPACE(n)</code></strong><br/>
* Returns a string consisting of <code>n</code> whitespace characters
* </li>
* <li><strong><code>SUBSTRING(str,pos), SUBSTRING(str,pos,len)</code></strong><br/>
* For two arguments, returns the substring of <code>str</code> starting at position
* <code>pos</code> and continuing to the end of the string.<br/>
* For three arguments, returns the substring of <code>str</code> of length <code>len</code>,
* beginning at position <code>pos</code>
* </li>
* <li><strong><code>UPPER(str), UCASE(str</code></strong><br/>
* Returns the string <code>str</code> mapped to uppercase letters
* </li>
* </ul>
*
* <h2>Color Functions</h2>
* <p>Functions for generating, translating, and interpolating color values.</p>
* <ul>
* <li><strong><code>RGB(r, g, b)</code></strong><br/>
* Returns an integer representing a fully opaque RGB (red, green, blue) color value
* </li>
* <li><strong><code>RGBA(r, g, b, a)</code></strong><br/>
* Returns an integer representing an RGBA (red, green, blue, alpha/transparency) color value
* </li>
* <li><strong><code>GRAY(v)</code></strong><br/>
* Returns an integer representing a grayscale color value of intensity <code>v</code>
* </li>
* <li><strong><code>HEX(hex)</code></strong><br/>
* Returns an integer representing the RGB color value encoded by the hexadecimal number
* <code>hex</code>
* </li>
* <li><strong><code>HSB(h, s, b)</code></strong><br/>
* Maps the given hue (<code>hue</code>), saturation (<code>s</code>), and brightness
* (<code>b</code>) color space values (as floating point numbers between 0 and 1) to
* an integer representing an RGB color value
* </li>
* <li><strong><code>HSBA(h, s, b, a)</code></strong><br/>
* Maps the given hue (<code>hue</code>), saturation (<code>s</code>), brightness
* (<code>b</code>), and alpha (<code>a</code>) color space values (as floating point
* numbers between 0 and 1) to an integer representing an RGBA color value
* </li>
* <li><strong><code>COLORINTERP(c1, c2, f)</code></strong><br/>
* Returns an interpolated color value between the input colors <code>c1</code> and
* <code>c2</code> determined by the mixing proportion <code>f</code>, a value
* between 0 and 1
* </li>
* </ul>
*
* <h2>Visualization Functions</h2>
* <p>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, <code>_x</code>, <code>_y</code>,
* <code>_hover</code>, <code>_highlight</code>, <code>_fillColor</code> would
* evaluate to references for the x-coordinate, y-coordinate, mouse hover status,
* highlight status, and fill color, respectively.</p>
* <ul>
* <li><strong><code>GROUPSIZE(group)</code></strong><br/>
* Returns the number of members in the data group <code>group</code>
* </li>
* <li><strong><code>INGROUP(group)</code></strong><br/>
* Returns true if the current VisualItem is a member of data group <code>group</code>
* </li>
* <li><strong><code>MATCH(group, includeAll)</code></strong><br/>
* Returns true if the current VisualItem is currently a search match. This is similar
* to <code>INGROUP(group)</code>, but also includes a possible special case when no
* query has been issued and all items should be counted as "matches" (indicated
* by <code>includeAll</code> being true).
* </li>
* <li><strong><code>QUERY(group)</code></strong><br/>
* Returns the current search query string in a search group of name <code>group</code>
* </li>
* <li><strong><code>VISIBLE()</code></strong><br/>
* Returns true if the current VisualItem is visible, equivalent to <code>_visible</code>
* </li>
* <li><strong><code>VALIDATED()</code></strong><br/>
* Returns true if the current VisualItem's bounds have been validated,
* equivalent to <code>_validated</code>
* </li>
* </ul>
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
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> | <HEX_LITERAL> | <OCTAL_LITERAL> >
| < #DECIMAL_LITERAL: ["1"-"9"] (["0"-"9"])* >
| < #HEX_LITERAL: "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ >
| < #OCTAL_LITERAL: "0" (["0"-"7"])* >
| < LONG : <INT>["l","L"] >
| < DOUBLE :
(["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)?
| "." (["0"-"9"])* (<EXPONENT>)?
| (["0"-"9"])+ <EXPONENT>
>
| < FLOAT : <DOUBLE>["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"]
)
)
)*
"\""
|
"'"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -