So far it's parsing multiple rules with multiple patterns, it supports literal, bound variable, predicate and return value field constraints as well as & and | field constraint connectives. I don't yet have it working with functions, so I've just put text into the predicate and return value for now, for the purposes of testing. The next stage is to get nested Conditional Elements working including 'and', 'or', 'not' and 'exists'. The really adventerous can help make 'accumulate', 'collect' and 'from' available :)
Clips/Lisp is a fairly simple grammar so this is a great learning project for anyone that wants to learn ANTLR and how to write custom parsers for the Drools Rule Engine; so if you want to help out why not pop onto codehause IRC #drools, or subscribe to our developer mailing list, and we'll help you get started.
The Clips ANTLR grammar is here http://anonsvn.labs.jboss.com/labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/clp/CLP.g
And for those interested here is the current unit test. This demonstrates the intermediate AST we use to build a language agnostic view of a grammar. This AST is "dumb" and we call it Descr, short for Description, this is because everything at this stage is held in a String format; little or not validation has been done, it's just a pure string based tree representing the rules, this is then pass to the PackageBuider which validates the descr tree and builds the resulting rule AST.
public void testRule() throws Exception {
RuleDescr rule = parse(
"(defrule xxx ?b <- (person (name \"yyy\"&?bf|~\"zzz\"|~=(ppp)&:(ooo)) )
?c <- (hobby (type ?bf2&~iii) (rating fivestar) )").rule();
assertEquals( "xxx", rule.getName() );
AndDescr lhs = rule.getLhs();
List lhsList = lhs.getDescrs();
assertEquals(2, lhsList.size());
// Parse the first column
ColumnDescr col = ( ColumnDescr ) lhsList.get( 0 );
assertEquals("?b", col.getIdentifier() );
assertEquals("person", col.getObjectType() );
List colList = col.getDescrs();
assertEquals(2, colList.size());
FieldConstraintDescr fieldConstraintDescr = ( FieldConstraintDescr ) colList.get( 0 );
List restrictionList = fieldConstraintDescr.getRestrictions();
assertEquals("name", fieldConstraintDescr.getFieldName() );
// @todo the 7th one has no constraint, as its a predicate, have to figure out how to handle this
assertEquals(8, restrictionList.size());
LiteralRestrictionDescr litDescr = ( LiteralRestrictionDescr ) restrictionList.get( 0 );
assertEquals("==", litDescr.getEvaluator() );
assertEquals("yyy", litDescr.getText() );
RestrictionConnectiveDescr connDescr = ( RestrictionConnectiveDescr ) restrictionList.get( 1 );
assertEquals(RestrictionConnectiveDescr.AND, connDescr.getConnective() );
VariableRestrictionDescr varDescr = ( VariableRestrictionDescr ) restrictionList.get( 2 );
assertEquals("==", varDescr.getEvaluator() );
assertEquals("?bf", varDescr.getIdentifier() );
connDescr = ( RestrictionConnectiveDescr ) restrictionList.get( 3 );
assertEquals(RestrictionConnectiveDescr.OR, connDescr.getConnective() );
litDescr = ( LiteralRestrictionDescr ) restrictionList.get( 4 );
assertEquals("!=", litDescr.getEvaluator() );
assertEquals("zzz", litDescr.getText() );
connDescr = ( RestrictionConnectiveDescr ) restrictionList.get( 5 );
assertEquals(RestrictionConnectiveDescr.OR, connDescr.getConnective() );
ReturnValueRestrictionDescr retDescr = ( ReturnValueRestrictionDescr ) restrictionList.get( 6 );
assertEquals("!=", retDescr.getEvaluator() );
assertEquals("ppp", retDescr.getText() );
PredicateDescr predicateDescr = ( PredicateDescr ) colList.get( 1 );
assertEquals( "ooo", predicateDescr.getText() );
// Parse the second column
col = ( ColumnDescr ) lhsList.get( 1 );
assertEquals("?c", col.getIdentifier() );
assertEquals("hobby", col.getObjectType() );
colList = col.getDescrs();
assertEquals(2, colList.size());
fieldConstraintDescr = ( FieldConstraintDescr ) colList.get( 0 );
restrictionList = fieldConstraintDescr.getRestrictions();
assertEquals("type", fieldConstraintDescr.getFieldName() );
varDescr = ( VariableRestrictionDescr ) restrictionList.get( 0 );
assertEquals("==", varDescr.getEvaluator() );
assertEquals("?bf2", varDescr.getIdentifier() );
connDescr = ( RestrictionConnectiveDescr ) restrictionList.get( 1 );
assertEquals(RestrictionConnectiveDescr.AND, connDescr.getConnective() );
litDescr = ( LiteralRestrictionDescr ) restrictionList.get( 2 );
assertEquals("!=", litDescr.getEvaluator() );
assertEquals("iii", litDescr.getText() );
fieldConstraintDescr = ( FieldConstraintDescr ) colList.get( 1 );
restrictionList = fieldConstraintDescr.getRestrictions();
assertEquals("rating", fieldConstraintDescr.getFieldName() );
litDescr = ( LiteralRestrictionDescr ) restrictionList.get( 0 );
assertEquals("==", litDescr.getEvaluator() );
assertEquals("fivestar", litDescr.getText() );
}

LISP and dialects are the language of the gods.
ReplyDeleteIf aliens came to earth, they would wonder why we kept inventing programming languages after LISP was discovered.
I better stop now, before I get in trouble.
My plan is to get you programming in Lisp, so when the aliens do come they can take you and Adrian Brocke with them :)
ReplyDeleteNice move on this, Mark! I suggest you try to cover some of the other ART derivatives, especially Eclipse and JESS, too.
ReplyDeletehttp://www.haley.com/brmsoverview/evolutionRL.html
Best Regards,
Paul