public final class Expression extends java.lang.Object implements ExpressionFlags
CompiledExpression
generated for the expression is
cached in the SymbolResolver
. Future accesses of the same
expression use the cached instance, rather than recompiling and generating
a new instance. The following characteristics of an expression are
considered when determining whether it has already been compiled:
current scope
of the symbol resolver at the time of
access;
runtime flags
set for the
expression.
Several runtime flag constants can be set to alter the behavior of an
expression. If multiple flags are to be set, they are bitwise OR'd
together. The setFlags
method is used to set these flags.
RT_NONE
: the default; turns off any special runtime
behavior previously set.
RT_INT_NARROWING
: throws an exception at runtime if an
automatic, integral, narrowing conversion (e.g., long
to int
) would cause a loss of information, given the
runtime data value to be converted (not currently implemented).
RT_FP_WIDENING
: throws an exception at runtime if an
automatic widening conversion from an integral value to a floating
point value would cause a loss of information. This occurs when a
very large integral number cannot be properly represented in a
floating point representation (not currently implemented).
RT_FP_ROUNDING
: performs floating point rounding to the
number of decimal places specified with the setPrecision(int)
method. This rounding occurs after each arithmetic operation
within the expression, not just on the final result. Note that while
more precise for financial calculations, this rounding adds
significant overhead to an expression's execution time. The
default number of decimal places of precision is 6.
RT_NO_ASSIGN
: supports SQL-like where clause syntax with
respect to the =
operator. This operator is interpreted
as an equivalence test (i.e., ==
) instead of as an
assignment.
RT_CLONE
: if set, a new instance of the compiled
expression will be created for each execution. Otherwise, the same
instance will be shared across executions.
RT_ERROR
: this flag should be turned on for debugging
purposes only. It causes the compiler to add additional instructions
to the compiled bytecode array for the compiled expression's
execute
method. These maintain
diagnostic information about the executing expression. An exception
handler in execute()
uses this information to provide a
detailed error message to stderr
in the event of an
execution-time exception, which is useful to pinpoint the part of
an expression which is the cause of the problem. During runs of an
expression compiled without this flag, no exception handler is used,
in order to improve performance.
RT_DEBUG
: this flag should be turned on for debugging
purposes only. It provides a superset of the diagnostic features
supported by the RT_ERROR
flag. In addition to those
features, it triggers verbose reporting on the compilation of the
expression and on each execution of the expression. Reporting is
sent to stdout
, except in the event of an error, in
which case it is sent to stderr
, as with
RT_ERROR
.
Modifier and Type | Class and Description |
---|---|
private static class |
Expression.CacheKey
Definition of the key to the cache of
CompiledExpression
instances. |
Modifier and Type | Field and Description |
---|---|
private CompiledExpression |
compiled
Compiled expression instance
|
private boolean |
dirty
Flag used to determine whether a cache check is necessary
|
private int |
flags
Bitset of runtime safety checks to be performed
|
private java.lang.String |
infix
Infix (pre-parsed) expression
|
private static java.lang.String |
LINE_SEP
Line separator
|
private int |
precision
Number of decimal places of precision for double rounding
|
private java.lang.ref.WeakReference<SymbolResolver> |
resolver
Symbol resolver used to compile this expression
|
RT_CLONE, RT_DEBUG, RT_ERROR, RT_FP_ROUNDING, RT_FP_WIDENING, RT_INT_NARROWING, RT_NO_ASSIGN, RT_NONE
Constructor and Description |
---|
Expression(SymbolResolver resolver,
java.lang.String infix)
Construct a new instance of an
Expression using the
specified symbol resolver and infix notation expression. |
Modifier and Type | Method and Description |
---|---|
java.lang.Object |
execute()
Execute the expression and return its result.
|
private CompiledExpression |
getCompiledInstance()
Get a configured instance of the custom, compiled expression class
associated with this expression's current state.
|
java.lang.String |
getInfix()
Report the infix notation expression string provided at construction
of this object.
|
int |
getPrecision()
Report the number of decimal places of precision currently set for
floating point rounding operations for this expression object.
|
(package private) SymbolResolver |
getResolver()
Report the symbol resolver associated with this object at construction.
|
java.lang.Class<?> |
getReturnType()
Report the type of object which will be returned by the expression
when it is
executed . |
int |
getRuntimeFlags()
Report the bitfield of runtime flags currently set for this expression
object.
|
static void |
main(java.lang.String[] args)
Entry point for manual testing of this class.
|
private ExtraAst |
reportFailingNode(ExtraAst ast,
int failingId,
int level,
java.lang.String errorMessage)
A dual-purpose method which both isolates the AST node within an
expression's syntax tree which is the cause of a runtime failure, and
optionally prints diagnostic information about the faiure to
stderr . |
void |
setPrecision(int precision)
Set the number of decimal places of precision to use for floating point
rounding operations for this expression object.
|
void |
setRuntimeFlags(int flags)
Set the bitfield of runtime flags for this expression object.
|
private static final java.lang.String LINE_SEP
private final java.lang.ref.WeakReference<SymbolResolver> resolver
private final java.lang.String infix
private int flags
private CompiledExpression compiled
private int precision
private boolean dirty
public Expression(SymbolResolver resolver, java.lang.String infix)
Expression
using the
specified symbol resolver and infix notation expression.
Any line breaks are stripped from the infix phrase, as is any leading and trailing whitespace from each line.
resolver
- Object which will define the scope for this expression and
which will be used to resolve symbols encountered within the
expression at parse time into constants, library or variable
references, or method calls.infix
- The text of the expression, in infix notation (i.e.,
A = B + C
). May not be null
.public java.lang.Class<?> getReturnType()
executed
. Expressions which would normally
return void
will report a null
return type.
Expressions which would normally return a primitive value will report
that primitive value's wrapper class. Expressions which return an
object reference will report that reference's class or interface.
Note: invocation of this method will trigger a lazy compile of the underlying expression, if it has not previously been compiled.
null
if the expression should return
void
.public int getRuntimeFlags()
public void setRuntimeFlags(int flags)
flags
- Runtime flags.public int getPrecision()
RT_FP_ROUNDING
runtime
flag is set; otherwise, it is ignored.public void setPrecision(int precision)
RT_FP_ROUNDING
runtime flag is set;
otherwise, it is ignored.precision
- Number of decimal places of precision.public java.lang.Object execute()
If the RT_DEBUG
flag is set, an expression execution debug
report is generated to stdout
. This report includes the
class name of the custom, compiled expression, the original infix
expression string, the result generated by the execution (if execution
completes successfully), and the state of the variable pool associated
with the expression's scope, after execution.
If either the RT_ERROR
or RT_DEBUG
flag is
set, the exception handler for this method catches any exception thrown
while executing the expression and writes an error message to
stderr
which provides detail about which part of the
expression was executing when the exception occurred. This helps the
end user pinpoint the exact problem within a failing expression.
This method must be allowed to perform all of its work within the
context of a single scope. That is, each and every call to the
SymbolResolver.getCurrentScope()
method of the symbol resolver
associated with this expression made while this method is executing
must return the same Scope
object. Otherwise, proper
compilation of the expression may be compromised and the results will
be undefined.
getReturnType()
.private ExtraAst reportFailingNode(ExtraAst ast, int failingId, int level, java.lang.String errorMessage)
stderr
. The optional diagnostic dump is triggered by
providing a non-null
errorMessage
parameter.
In the latter mode, the expression's postfix form (an indented AST
representation) is written, with errorMessage
annotated
to the failing node.
This method is recursive, implementing a depth-first iteration of the
expression's AST. If errorMessage
is null
,
the iteration terminates as soon as the node whose ID is
failingID
is visited.
ast
- The postfix (AST) representation of the parsed infix
expression.failingId
- Unique identifier associated with the failing node within
the expression's AST.level
- Zero-based AST node level currently being visited in this
method's recursive iteration of the tree.errorMessage
- An optional error message which will annotate the failing
AST node in a dump of the tree to stderr
. If
null
, no such dump is written.failingId
.public java.lang.String getInfix()
SymbolResolver getResolver()
private CompiledExpression getCompiledInstance()
public static void main(java.lang.String[] args)
SymbolResolver
. It executes an
arbitrary expression 1 or more times and reports the results.args
- The following arguments are expected:
TestResolver test resolver internal class
.
RT_FP_ROUNDING
flag.