Evaluate logical expression at runtime - java

How do I go about evaluating logical expression like "VERB1 OR (VERB2 AND VERB3) OR (VERB4)" entered at runtime. VERB* are placeholder to evaluate certain conditions. For example, VERB1 might mean check for the existence of a record in database.
In expression "VERB1 OR (VERB2 AND VERB3) OR (VERB4)", other verbs should not be executed if VERB1 is true
EDIT: Example described at http://www.alittlemadness.com/2006/06/05/antlr-by-example-part-1-the-language/ seems very similar to what I am trying to do. However, the optimization step (other verbs should not be executed if VERB1 is true) doesn't seem to be there.

If you can use || and && in place of AND and OR, you can just use groovy's missing property methods and the GroovyShell base class setting like so:
import org.codehaus.groovy.control.CompilerConfiguration
// The command to be executes
def command = "VERB1 || (VERB2 && VERB3) || (VERB4)"
// Set a base class for the GroovyShell
new CompilerConfiguration().with { compiler ->
compiler.scriptBaseClass = 'VerbHandlingBaseClass'
new GroovyShell( this.class.classLoader, new Binding(), compiler ).with { shell ->
// and evaluate the command
shell.evaluate( command )
}
}
abstract class VerbHandlingBaseClass extends Script {
boolean VERB1() {
System.out.println( 'CHECK THE DATABASE, RETURN FALSE' )
false
}
boolean VERB2() {
System.out.println( 'WRITE A LOG ENTRY RETURN TRUE' )
true
}
boolean VERB3() {
System.out.println( 'VALIDATE SOMETHING, RETURN TRUE' )
true
}
boolean VERB4() {
System.out.println( 'THIS WONT BE REACHED, AS VERB2 && VERB3 == true' )
true
}
def propertyMissing( String name ) {
"$name"()
}
}
That should print:
CHECK THE DATABASE, RETURN FALSE
WRITE A LOG ENTRY RETURN TRUE
VALIDATE SOMETHING, RETURN TRUE

You mentioned ANTLR in your tags: have you given this a go? You can create a full boolean grammar in ANTLR but it gets much harder when you get down to the level of how to evaluate the verbs.
If there is a small, fixed set of verbs which may be queried you can easily create a mapping between the verbs and the functions.
If there is a larger list of verbs, you may be able to use reflection to call specific methods to evaluate them.
If your verbs can include mathematical comparisons, this all gets a bit harder as you create a mathematical lexer and parser as well.
Without a more specific question and knowledge of what you have tried in ANTLR I'm not sure I can give you much more advice.
EDIT: Based on your comments, I'll add some more.
You can add parsing rules to your grammar:
boolean_or returns [boolean b]
: b1=boolean_and {$b = $b1.b;}
(OR b2=boolean_and {$b = $b || $b2.b;})*
;
boolean_atom returns [boolean b]
:
((numeric_comparison)=> b1=numeric_comparison {$b = $b1.b;}
| TRUE {$b = true;} | FALSE {$b = false;}
| s1=VERB {$b = evalVerb($s1.s);}
| LPAREN b1=boolean_expr RPAREN {$b = $b1.b;}
)
;
Thats a small part of a boolean parser I'm currently using. You can fill in the blanks.
And then call the parser using something like
ANTLRStringStream in = new ANTLRStringStream(booleanString);
ActionLexer lexer = new ActionLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
BooleanParser parser = new BooleanParser(tokens);
try {
return parser.eval();
} catch (Exception e) {
}
This doesn't account for your requirement of returning early, but I'm sure you can figure out how to do that.
This might not be the best way to do things, but its the way that I've gotten it to work for me in the past. Hope this helps.

Related

Custom Sonar Rule To Check For Correct Method Call

I have my custom SonarQube plugIn up and running on a local SonarQube server and it works fine. Now I want to add more stuff to it. I'm interested in coding my own Sonar Rule which checks if the non deprecated constructor is used for one class.
Possible constructor calls:
#Deprecated
public ExampleClass(String a)
{
//deprecated/old/wrong stuff happening
}
public ExampleClass(String a, String b)
{
//correct stuff happening
}
I'm already at the state, that only Method notes will be visited.
Now I'm wondering how can I check which new ExampleClass expression is used?
Found a working solution.
Here's what I did:
set nodesToVisit to Tree.Kind.ASSIGNMENT
check if the expression is Tree.Kind.NEW_CLASS
check if identifier is ExampleClass.class.getSimpleName()
do my argument checks
Code:
AssignmentExpressionTree assignment = (AssignmentExpressionTree) tree;
if ( assignment.expression().is(Tree.Kind.NEW_CLASS) )
{
NewClassTreeImpl expression = (NewClassTreeImpl) assignment.expression();
IdentifierTreeImpl identifier = (IdentifierTreeImpl) expression.identifier();
if ( StringUtils.equals(identifier.name(), ExampleClass.class.getSimpleName()) )
{
ArgumentListTreeImpl arguments = (ArgumentListTreeImpl) expression.arguments();
if ( arguments.size() != 2 )
{
reportIssue(expression, "Use the 2 parameter constructor call when creating new ExampleClass objects!");
}
else if ( StringUtils.indexOfAny(arguments.get(1).symbolType().name(), POSSIBLE_PARAMETER_TYPES) == -1 )
{
reportIssue(expression, "The second parameter must be from type String");
}
}
}
If you find any improvement of my rule, please let me know. Thanks!

Calling a method in the while loop condition

I'm curious is it possible to call a method that returns a boolean value in the condition part of a while loop?
As in:
while(someMethod()!= true){
//Do stuff
}
And the method simply returns a true or false. Is this possible or not and if so is there a correct syntax or a better way?
Edit: Thanks for the quick responses. As an extension to my question is it possible to call the method multiple times for different things but require them all to be the same before exiting the loop?
For example:
while(!(someMethod(input_a) == someMethod(input_b))){
//Do stuff
}
Where both of the returned values are the returned values are equal?
Hope this will help you
public boolean functionOne(int i){
// some operation
if(i == 1) return true;
else return false;
}
public void otherFunc(){
int i = 0;
if(functionOne(i)) { // e.g: if(functionOne(i) == true)
// your code
// 0!=1 so result is fort
}
if(!functionOne(i)){ // e.g: if(functionOne(i) == false)
// your code
// 0!=1 it is false, but ! before functionOne negate so ! of false is true
}
// **for your while**
while(functionOne(i)){ // while function returns true
// code
}
// **or**
while(!functionOne(i)){ // while function returns false
// code
}
}
Yes of course!
public static boolean someMethod(){
return false;
}
public static void main(String[] args){
while(!someMethod()){
//do something
System.out.println("Hi");
}
}
Like in this code, an infinite loop will be called if the method returns false, but if the method returns true, it will just come out of the while loop. :)
Less is best:
while (!someMethod()) {
// Do stuff
}
It's never a good idea to compare to a boolean result to a boolean literal. Prefer using the result in-line, using the logical unary not operator ! as required.
Answering the now-edited version of the question, less is still best:
while (someMethod(input_a) != someMethod(input_b))
You can find the specification of the while loop in JLS Sec 14.12:
The while statement executes an Expression and a Statement repeatedly until the value of the Expression is false.
WhileStatement:
while ( Expression ) Statement
WhileStatementNoShortIf:
while ( Expression ) StatementNoShortIf
The Expression must have type boolean or Boolean, or a compile-time error occurs.
So, you can use anything which is an Expression of type boolean (or Boolean).
And if you click through the productions in the language spec:
Expression, contains
AssignmentExpression, contains
ConditionalExpression, contains
ConditionalOrExpression, contains
ConditionalAndExpression, contains
InclusiveOrExpression, contains
ExclusiveOrExpression, contains
AndExpression, contains
EqualityExpression, contains
RelationalExpression, contains
ShiftExpression, contains
AdditiveExpression, contains
MultiplicativeExpression, contains
UnaryExpression, contains
UnaryExpressionNotPlusMinus, contains
PostfixExpression, contains
Primary, contains
PrimaryNoNewArray, contains
MethodInvocation
Phew! That's pretty deeply buried! (You can read this like an inheritance hierarchy, so every MethodInvocation is a PrimaryNoNewArray, and every PrimaryNoNewArray is a Primary etc).
So, transitively, every MethodInvocation is an Expression, hence it's fine to use it as the expression in a while loop.
Addressing your edit: yes, that's fine too. If you look at the detail of the EqualityExpression:
EqualityExpression:
RelationalExpression
EqualityExpression == RelationalExpression
EqualityExpression != RelationalExpression
As already described above, you can use an EqualityExpression as the Expression in a WhileStatement. And something of the form
RelationalExpression != RelationalExpression
is an EqualityExpression by the rule shown. Since all MethodInvocations are RelationalExpressions, you can use method invocations in the while statement as you've shown:
while(someMethod(input_a) != someMethod(input_b)) {
(a != b is an easier way of writing !(a == b)).
This is the way we have done loops over java iterators. For instance:
Iterator[String] iterator = util.Arrays.asList("One", "Two", "Three").iterator();
while(iterator.hasNext()) {
println(iterator.next());
}
We have also done something similar for the JDBC ResultSet interface.

String representation of an expression for assertion implementation

Since Java's assert keyword is fundamentally broken on Android, I am about to implement an assertion class that can be configured to check assertions in release builds as well.
Now I can do something like:
MyAssertion.assert(a != 2)
which throws an AssertionException when the expression is false. But how can I get a String representation of the expression to pass to the error message?
The only way is to add a String parameter to your assert method:
MyAssertion.assert(a != 2, "a must not be equal to 2");
What you get as input for assert is either true or false so you can't build a representative String from that.
Otherwise, you could implement assert like this:
MyAssertion.assertNotEquals(a, 2);
When this fails, you know that it is because what you tested was equal to 2 and you can build an informative message (though you won't know what specifically was equal to 2).
If you want to somehow be able to construct a meaningful message from an assertion, the only way I see it possible is to construct an String expression, ask the JavaScript engine to evaluate it and build a message if the expression evaluates to false. Note that will degrade a lot performance as launching the JavaScript engine takes a lot of time. This could be solved with a mechanism of disabling assertions in production.
The following is an example of that. Note that I'm using the new Java 8 Nashorn JavaScript engine but this should work with the older Rhino.
Usage example:
int value = 3;
String str = "test";
Assertions.assertTrue("$1 == 3", value);
Assertions.assertTrue("$1 == 3 && $2 == 'test'", value, str);
Assertions.assertTrue("$1 == 4 && $2 == 'test'", value, str);
This will throw for the 3rd assertion:
An assertion has failed: 3 == 4 && 'test' == 'test'
The idea is that you can write any JavaScript-friendly expression that can be evaluated to a boolean. The placeholders $i will be replaced by what's given as a parameter to the method ($1 will be replaced by the first parameter, etc.).
This is the class. It could be improved (handle error conditions like not enough parameters, etc.) but this should be enough to get you started.
public final class Assertions {
private static final ScriptEngine ENGINE = new ScriptEngineManager().getEngineByName("nashorn");
private Assertions() { }
public static void assertTrue(String expression, Object... values) {
for (int i = 0; i < values.length; i++) {
ENGINE.put("$" + (i+1), values[i]);
}
try {
boolean pass = (Boolean) ENGINE.eval(expression);
if (!pass) {
for (int i = 0; i < values.length; i++) {
expression = expression.replace("$" + (i+1), stringRepresentation(values[i]));
}
throw new AssertionError("An assertion has failed: " + expression);
}
} catch (ScriptException e) {
throw new InternalError(e);
} finally {
for (int i = 0; i < values.length; i++) {
ENGINE.getBindings(ScriptContext.ENGINE_SCOPE).remove("$" + (i+1));
}
}
}
private static String stringRepresentation(Object o) {
if (o instanceof String) {
return "'" + o + "'";
}
return o.toString();
}
}
Annotation processing can do this. You'd create an annotation e.g. #InlineAssertExpressions. Then write a processor that parses your source file and creates a string representing the expression and adds it to the call to your assert method, which you could overload to take an optional String argument. This way is quite optimal performance-wise, since the inlining happens compile-time. Annotation processing is a bit overlooked, but I think this is a great use for it.
(1) Simple to use, but hard to implement. Java 8 required. You can use lambda expressions:
Assert.isTrue(() => a != 2)
On evaluation failure your implementation of Assert.isTrue method should repeat all steps as IDEs do - (a) discover bytecode of lambda class, (b) decompile e.g. with JAD, (c) discover sources if available
(2) Simple to use, simple to implement, but does not fully cover your requirements. You can use CodeStyle rules to check & force correct assertions usage. One regexp will check there is no single-argument assertions, the second (using regexp back refs) will check code and text description are similar.
(3) Simple to use, simple to implement, but relies on your build system. You can automatically check and fix source code during project build.
E.g. for Maven build system you can create your own plugin to check and fix assertions usage in sources on process-sources stage.
I think you cannot access the internal java expression, which was passed to method call.
You can, however, use some expression language libraries and do a custom expression handling for your assertion implementation.
Here is a list of some expression language libraries:
http://java-source.net/open-source/expression-languages
Hope that helps :)

How to extract BDD meta-statements from Spock specification classes

Suppose we have a Spock specification class like below.
class SomeFeature extends Specification {
def "some scenario"() {
given: "some resource"
def resource = someResource()
when: "some action is taken"
someAction()
then: "some condition must be met"
true == someCondition()
}
}
How can I extract the BDD meta-statements like some scenario, given, when, then? It is straightforward to process the source file, but I am wondering if it is possible to use reflection to achieve that.
BTW, the motivation to get that information is to facilitate the communication between product owner and developer, such that the product owner can know what behaviors have been implemented and verified without looking at the source code.
Thank you very much.
In the cold hard light of day, there are some issues with this.
It's probably quite brittle and would need sorting out to handle different cases and formats (unrolled descriptions? helper methods? parameterised descriptions?)
It will just blindly dump out everything even if the test is never executed.
I think a much better and more stable solution would be the one in #PeterNiederwieser's comment above.
I'll leave this here for prosperity though, as it's quite a good example of how to generate an AST from some Groovy code as a String...
I don't think reflection will help, as it won't get you the contents of the methods.
You can do it by generating an AST from the source code, and then walking it looking for the nodes of interest.
So given the code in a String like so:
def code = '''import spock.*
class SomeFeature extends Specification {
def "some scenario"() {
given: "some resource"
def resource = someResource()
when: "some action is taken"
someAction()
then: "some condition must be met"
true == someCondition()
}
def "another"() {
given: 'a value 1'
def value = 1
then: '1 == 1'
value == 1
}
}'''
You can generate an AST:
import org.codehaus.groovy.antlr.*
import org.codehaus.groovy.antlr.parser.*
def ast = new GroovyRecognizer(
new GroovyLexer(
new StringReader( code ) ).plumb() ).with { p ->
p.compilationUnit()
p.AST
}
And then you can do something like this (this is probably not the cleanest way of doing it, I was under time constraints) ;-)
while( ast ) {
if( ast.type == GroovyTokenTypes.CLASS_DEF ) {
def child = ast.firstChild.nextSibling
println "Specification '${child.text}'"
while( child && child.type != GroovyTokenTypes.OBJBLOCK ) {
child = child.nextSibling
}
if( child ) {
child = child.firstChild
while( child ) {
if( child.type == GroovyTokenTypes.METHOD_DEF ) {
def method = child.firstChild
println " Scenario '${method.nextSibling?.nextSibling?.text}'"
while( method ) {
if( method.type == GroovyTokenTypes.SLIST ) {
def statements = method.firstChild
while( statements ) {
if( statements.type == GroovyTokenTypes.LABELED_STAT ) {
def label = statements.firstChild
println " ${label.text.toUpperCase()} '${label.nextSibling?.firstChild?.text}'"
}
statements = statements.nextSibling
}
}
method = method.nextSibling
}
}
child = child.nextSibling
}
}
}
ast = ast.nextSibling
}
That gives me the output:
Specification 'SomeFeature'
Scenario 'some scenario'
GIVEN 'some resource'
WHEN 'some action is taken'
THEN 'some condition must be met'
Scenario 'another'
GIVEN 'a value 1'
THEN '1 == 1'
Hope it helps...

Reformatting code with Regular Expressions

We have an ArrayList of items in several classes which are giving me trouble every time I'd like to insert a new item into the list. It was a mistake on my part to have designed the classes in the way I did but changing the design now would be more headache than it's worth (bureaucratic waterfall model.) I should have anticipated format changes to the documents the customer was supplying us waterfall be damned.
I'd like to write a simple script in python which goes into a class, adds the item to the list, and then increments all retrievals for the following items. That doesn't sound very explanatory:
Foo extends Bar{
public Foo(){
m_Tags.add("Jane");
m_Tags.add("Bob");
m_Tags.add("Jim");
}
public String GetJane() { return m_ParsedValue.get( m_Tags.get(1) ); }
public String GetBob() { return m_ParsedValue.get( m_Tags.get(2) ); }
public String GetJim() { return m_ParsedValue.get( m_Tags.get(3) ); }
}
You see if I want to add a value between "Jane" and "Bob" I then have to increment the integers in the Get* functions. I just want to write a simple script in Python that does the work for me. Someone I very much respect suggested regex.
Edit:
Yes, LinkedHashMap. So simple, so easy and so not in the design specs now. I hate waterfall. Hate it with a passion. This whole bit was a "small" and "easy" part that "shouldn't take much time to design." I made mistakes. It's stuck in stone now.
You want your regular expression to be as flexible as the compiler will be with respect to whitespace between tokens. Doing so and mimicking whitespace usage makes the pattern pretty messy. The code below (sorry: Perl, not Python) edits your source files in-place.
#! /usr/bin/perl -i.bak
use warnings;
use strict;
my $template =
'^( public
String
Get)(\w+)( \( \) { return
m_ParsedValue . get \( m_Tags . get \( )(\d+)( \) \) ; } )$';
$template =~ s/ +/\\s*/g;
$template =~ s/(\r?\n)+/\\s+/g;
my $getter = qr/$template/x;
die "Usage: $0 after new-name source ..\n" unless #ARGV >= 3;
my $after = shift;
my $add = shift;
my $index;
while (<>) {
unless (/$getter/) {
print;
next;
}
my($abc,$name,$lmno,$i,$xyz) = ($1,$2,$3,$4,$5);
if (defined $index) {
print join "" => $abc, $name, $lmno, ++$index, $xyz;
}
else {
if ($name eq $after) {
$index = $i;
print; print join "" => $abc, $add, $lmno, ++$index, $xyz;
}
else { print; }
}
}
For example,
$ ./add-after Jane Foo code.java
$ cat code.java
Foo extends Bar{
public Foo(){
m_Tags.add("Jane");
m_Tags.add("Bob");
m_Tags.add("Jim");
}
public String GetJane() { return m_ParsedValue.get( m_Tags.get(1) ); }
public String GetFoo() { return m_ParsedValue.get( m_Tags.get(2) ); }
public String GetBob() { return m_ParsedValue.get( m_Tags.get(3) ); }
public String GetJim() { return m_ParsedValue.get( m_Tags.get(4) ); }
}
Don't do this with regexp. Create symbolic constants (using for example an enum) that map the names to numbers.
Comments about bad-practices apart - here is the code you asked in the language you asked for.
The best thing if you are keeping the system this way, probably would be to make these java files be automatically generated in the build process itself -- you 'd just keep a names list in a .txt file in the directory. This script is suitable to do that.
(It won't modify your files, it genrate new ones based on the template you posted here)
import re, sys
template = """Foo extends Bar{
public Foo(){
%s
}
%s
}
"""
tag_templ = """ m_Tags.add("%s");"""
getter_templ = """ public String GetJane() { return m_ParsedValue.get( m_Tags.get(%d) ); }"""
def parse_names(filename):
data = open(filename).read()
names = re.findall(r'm_Tags\.add\("(.*?)"', data)
return names
def create_file(filename, names):
tag_lines = [tag_templ % name for name in names]
getter_lines = [getter_templ % (i + 1) for i in range(len(names))]
code = template % ("\n".join(tag_lines), "\n".join(getter_lines))
file = open(filename,"wt")
file.write(code)
file.close()
def insert_name(after, new_name, names):
names.insert(names.index(after) + 1, new_name)
if __name__ == "__main__":
if len(sys.argv ) < 4:
sys.stderr.write("Usage: changer.py <filename> <name-before-insertion> <new-name>")
sys.exit(1)
filename, name_before, new_name = sys.argv[1:]
names = parse_names(filename)
insert_name(name_before, new_name, names)
create_file(filename, names)
I'm doing this (well, something very similar) right now, but using Excel and VBA macros. All of the Business Values are organized and ordered in a spreadsheet. I just have to click a button to generate the appropriate code for the selected cells, then copy-paste to the IDE. Better yet, I have several "code columns" for each row. Some of them generate queries, some XSL transformations, and some procedures. For one row of business data, I can get all three types of generated code very easily.
I found this (re-generate) to be MUCH easier than re-formatting the existing code I had.

Categories

Resources