[jboss-svn-commits] JBL Code SVN: r5456 - in labs/jbossrules/trunk/drools-compiler/src: main/java/org/drools/compiler main/java/org/drools/lang/descr main/java/org/drools/semantics/java main/resources/META-INF main/resources/org/drools/lang test/java/org/drools/compiler

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Aug 3 20:22:49 EDT 2006


Author: mark.proctor at jboss.com
Date: 2006-08-03 20:22:41 -0400 (Thu, 03 Aug 2006)
New Revision: 5456

Added:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/FactTemplateError.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/FieldTemplateError.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/FactTemplateDescr.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/FieldTemplateDescr.java
   labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/lang/drl.g
Modified:
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/PackageDescr.java
   labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java
   labs/jbossrules/trunk/drools-compiler/src/main/resources/META-INF/drools-3.0.xsd
   labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java
Log:
JBRULES-328 FactTemplates
-Rule/Package Builder now works FactTemplates

Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/FactTemplateError.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/FactTemplateError.java	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/FactTemplateError.java	2006-08-04 00:22:41 UTC (rev 5456)
@@ -0,0 +1,77 @@
+package org.drools.compiler;
+
+/*
+ * Copyright 2005 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.commons.jci.problems.CompilationProblem;
+import org.drools.lang.descr.PatternDescr;
+import org.drools.rule.Rule;
+import org.drools.rule.Package;
+
+public class FactTemplateError extends DroolsError {
+    private Package pkg;
+    private PatternDescr descr;
+    private Object       object;
+    private String       message;
+
+    public FactTemplateError(final Package pkg,
+                     final PatternDescr descr,
+                     final Object object,
+                     final String message) {
+        super();
+        this.pkg = pkg;
+        this.descr = descr;
+        this.object = object;
+        this.message = message;
+    }
+
+    public Package getPackage() {
+        return this.pkg;
+    }
+
+    public PatternDescr getDescr() {
+        return this.descr;
+    }
+
+    public Object getObject() {
+        return this.object;
+    }
+
+    /** 
+     * This will return the line number of the error, if possible
+     * Otherwise it will be -1
+     */
+    public int getLine() {
+        if ( this.descr != null ) {
+            return this.descr.getLine();
+        } else {
+            return -1;
+        }
+    }
+
+    public String getMessage() {
+        String summary = this.message;
+        if ( this.object instanceof CompilationProblem[] ) {
+            final CompilationProblem[] problem = (CompilationProblem[]) this.object;
+            for ( int i = 0; i < problem.length; i++ ) {
+                summary = summary + " " + problem[i].getMessage();
+            }
+
+        }
+        return summary;
+    }
+
+}
\ No newline at end of file

Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/FieldTemplateError.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/FieldTemplateError.java	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/FieldTemplateError.java	2006-08-04 00:22:41 UTC (rev 5456)
@@ -0,0 +1,76 @@
+package org.drools.compiler;
+
+/*
+ * Copyright 2005 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.commons.jci.problems.CompilationProblem;
+import org.drools.lang.descr.PatternDescr;
+import org.drools.rule.Rule;
+import org.drools.rule.Package;
+
+public class FieldTemplateError extends DroolsError {
+    private Package      pkg;
+    private PatternDescr descr;
+    private Object       object;
+    private String       message;
+
+    public FieldTemplateError(final Package pkg,
+                              final PatternDescr descr,
+                              final Object object,
+                              final String message) {
+        this.pkg = pkg;
+        this.descr = descr;
+        this.object = object;
+        this.message = message;
+    }
+
+    public Package getPackage() {
+        return this.pkg;
+    }
+
+    public PatternDescr getDescr() {
+        return this.descr;
+    }
+
+    public Object getObject() {
+        return this.object;
+    }
+
+    /** 
+     * This will return the line number of the error, if possible
+     * Otherwise it will be -1
+     */
+    public int getLine() {
+        if ( this.descr != null ) {
+            return this.descr.getLine();
+        } else {
+            return -1;
+        }
+    }
+
+    public String getMessage() {
+        String summary = this.message;
+        if ( this.object instanceof CompilationProblem[] ) {
+            final CompilationProblem[] problem = (CompilationProblem[]) this.object;
+            for ( int i = 0; i < problem.length; i++ ) {
+                summary = summary + " " + problem[i].getMessage();
+            }
+
+        }
+        return summary;
+    }
+
+}
\ No newline at end of file

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/compiler/PackageBuilder.java	2006-08-04 00:22:41 UTC (rev 5456)
@@ -37,6 +37,12 @@
 import org.apache.commons.jci.readers.ResourceReader;
 import org.drools.RuntimeDroolsException;
 import org.drools.base.ClassFieldExtractorCache;
+import org.drools.facttemplates.FactTemplate;
+import org.drools.facttemplates.FactTemplateImpl;
+import org.drools.facttemplates.FieldTemplate;
+import org.drools.facttemplates.FieldTemplateImpl;
+import org.drools.lang.descr.FactTemplateDescr;
+import org.drools.lang.descr.FieldTemplateDescr;
 import org.drools.lang.descr.FunctionDescr;
 import org.drools.lang.descr.PackageDescr;
 import org.drools.lang.descr.PatternDescr;
@@ -185,6 +191,10 @@
 
         //only try to compile if there are no parse errors
         if ( !hasErrors() ) {
+            for ( final Iterator it = packageDescr.getFactTemplates().iterator(); it.hasNext(); ) {
+                addFactTemplate( (FactTemplateDescr) it.next() );
+            }
+
             //iterate and compile
             for ( final Iterator it = packageDescr.getFunctions().iterator(); it.hasNext(); ) {
                 addFunction( (FunctionDescr) it.next() );
@@ -293,6 +303,30 @@
 
     }
 
+    private void addFactTemplate(final FactTemplateDescr factTemplateDescr) {
+        List fields = new ArrayList();
+        int index = 0;
+        for ( final Iterator it = factTemplateDescr.getFields().iterator(); it.hasNext(); ) {
+            FieldTemplateDescr fieldTemplateDescr = (FieldTemplateDescr) it.next();
+            FieldTemplate fieldTemplate = null;
+            try {
+                fieldTemplate = new FieldTemplateImpl( fieldTemplateDescr.getName(),
+                                                       index++,
+                                                       getTypeResolver().resolveType( fieldTemplateDescr.getClassType() ) );
+            } catch ( ClassNotFoundException e ) {
+                this.results.add( new FieldTemplateError( this.pkg,
+                                                          fieldTemplateDescr,
+                                                          null,
+                                                          "Unable to resolve Class '" + fieldTemplateDescr.getClassType() + "'" ) );
+            }
+            fields.add( fieldTemplate );
+        }
+
+        FactTemplate factTemplate = new FactTemplateImpl( this.pkg,
+                                                          factTemplateDescr.getName(),
+                                                          (FieldTemplate[]) fields.toArray( new FieldTemplate[fields.size()] ) );
+    }
+
     private void addRule(final RuleDescr ruleDescr) {
 
         final String ruleClassName = getUniqueLegalName( this.pkg.getName(),
@@ -421,11 +455,11 @@
         if ( result.getErrors().length > 0 ) {
             for ( int i = 0; i < result.getErrors().length; i++ ) {
                 CompilationProblem err = result.getErrors()[i];
-                
+
                 ErrorHandler handler = (ErrorHandler) this.errorHandlers.get( err.getFileName() );
-                if (handler instanceof RuleErrorHandler) {                    
+                if ( handler instanceof RuleErrorHandler ) {
                     RuleErrorHandler rh = (RuleErrorHandler) handler;
-                    
+
                 }
                 handler.addError( err );
             }
@@ -433,14 +467,14 @@
             Collection errors = this.errorHandlers.values();
             for ( Iterator iter = errors.iterator(); iter.hasNext(); ) {
                 ErrorHandler handler = (ErrorHandler) iter.next();
-                if (handler.isInError()) {
+                if ( handler.isInError() ) {
                     if ( !(handler instanceof RuleInvokerErrorHandler) ) {
                         this.results.add( handler.getError() );
                     } else {
                         //we don't really want to report invoker errors.
                         //mostly as they can happen when there is a syntax error in the RHS
                         //and otherwise, it is a programmatic error in drools itself.
-                        System.err.println( "Warning: An error occurred compiling a semantic invoker. Errors should have been reported elsewhere.");
+                        System.err.println( "Warning: An error occurred compiling a semantic invoker. Errors should have been reported elsewhere." );
                     }
                 }
             }
@@ -554,15 +588,15 @@
      * that originally spawned the code to be compiled.
      */
     public abstract static class ErrorHandler {
-        private List     errors = new ArrayList();
+        private List     errors  = new ArrayList();
         protected String message;
-        private boolean inError = false;
+        private boolean  inError = false;
 
         /** This needes to be checked if there is infact an error */
         public boolean isInError() {
             return inError;
         }
-        
+
         public void addError(CompilationProblem err) {
             this.errors.add( err );
             this.inError = true;

Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/FactTemplateDescr.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/FactTemplateDescr.java	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/FactTemplateDescr.java	2006-08-04 00:22:41 UTC (rev 5456)
@@ -0,0 +1,29 @@
+package org.drools.lang.descr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FactTemplateDescr extends PatternDescr {
+    private static final long serialVersionUID = 320;
+    
+    String name;
+    List fields = new ArrayList( 1 );
+    
+    public FactTemplateDescr(String name) {
+        this.name = name;
+    }
+    
+    public void addFieldTemplate(FieldTemplateDescr fieldTemplate) {
+        this.fields.add( fieldTemplate );
+    }
+
+    public List getFields() {
+        return this.fields;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+    
+    
+}

Added: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/FieldTemplateDescr.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/FieldTemplateDescr.java	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/FieldTemplateDescr.java	2006-08-04 00:22:41 UTC (rev 5456)
@@ -0,0 +1,20 @@
+package org.drools.lang.descr;
+
+public class FieldTemplateDescr extends PatternDescr {
+    private final String      name;
+    private final String      classType;
+    public FieldTemplateDescr(final String name,
+                              final String type) {
+        super();
+        this.name = name;
+        this.classType = type;
+    }
+    public String getName() {
+        return this.name;
+    }
+    public String getClassType() {
+        return this.classType;
+    }
+    
+    
+}

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/PackageDescr.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/PackageDescr.java	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/lang/descr/PackageDescr.java	2006-08-04 00:22:41 UTC (rev 5456)
@@ -27,14 +27,15 @@
      * 
      */
     private static final long serialVersionUID = 4491974850482281807L;
-    private final String name;
-    private final String documentation;
+    private final String      name;
+    private final String      documentation;
 
-    private List         imports    = Collections.EMPTY_LIST;
-    private List         attributes = Collections.EMPTY_LIST;
-    private Map          globals    = Collections.EMPTY_MAP;
-    private List         functions  = Collections.EMPTY_LIST;
-    private List         rules      = Collections.EMPTY_LIST;
+    private List              imports          = Collections.EMPTY_LIST;
+    private List              attributes       = Collections.EMPTY_LIST;
+    private Map               globals          = Collections.EMPTY_MAP;
+    private List              factTemplates    = Collections.EMPTY_LIST;
+    private List              functions        = Collections.EMPTY_LIST;
+    private List              rules            = Collections.EMPTY_LIST;
 
     public PackageDescr(final String name) {
         this( name,
@@ -77,7 +78,7 @@
 
     public Map getGlobals() {
         return this.globals;
-    }
+    }    
 
     public void addAttribute(final AttributeDescr attribute) {
         if ( this.attributes == Collections.EMPTY_LIST ) {
@@ -89,6 +90,17 @@
     public List getAttributes() {
         return this.attributes;
     }
+    
+    public void addFactTemplate(final FactTemplateDescr  factTemplate) {
+        if ( this.factTemplates == Collections.EMPTY_LIST ) {
+            this.factTemplates = new ArrayList( 1 );
+        }
+        this.factTemplates.add( factTemplate );
+    }
+    
+    public List getFactTemplates() {
+        return this.factTemplates;
+    }
 
     public void addFunction(final FunctionDescr function) {
         if ( this.functions == Collections.EMPTY_LIST ) {

Modified: labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/java/org/drools/semantics/java/RuleBuilder.java	2006-08-04 00:22:41 UTC (rev 5456)
@@ -37,6 +37,9 @@
 import org.drools.base.ValueType;
 import org.drools.base.evaluators.Operator;
 import org.drools.compiler.RuleError;
+import org.drools.facttemplates.FactTemplate;
+import org.drools.facttemplates.FactTemplateFieldExtractor;
+import org.drools.facttemplates.FactTemplateObjectType;
 import org.drools.lang.descr.AndDescr;
 import org.drools.lang.descr.AttributeDescr;
 import org.drools.lang.descr.ColumnDescr;
@@ -81,6 +84,7 @@
 import org.drools.spi.Extractor;
 import org.drools.spi.FieldExtractor;
 import org.drools.spi.FieldValue;
+import org.drools.spi.ObjectType;
 import org.drools.spi.Restriction;
 import org.drools.spi.TypeResolver;
 
@@ -382,24 +386,30 @@
             return null;
         }
 
-        Class clazz = null;
-
-        try {
-            //clazz = Class.forName( columnDescr.getObjectType() );
-            clazz = this.typeResolver.resolveType( columnDescr.getObjectType() );
-        } catch ( final ClassNotFoundException e ) {
-            this.errors.add( new RuleError( this.rule,
-                                            columnDescr,
-                                            null,
-                                            "Unable to resolve ObjectType '" + columnDescr.getObjectType() + "'" ) );
-            return null;
+        ObjectType objectType = null;
+                
+        FactTemplate factTemplate  = this.pkg.getFactTemplate( columnDescr.getObjectType() );
+        
+        if ( factTemplate != null ){
+            objectType = new FactTemplateObjectType( factTemplate );
+        } else {            
+            try {
+                //clazz = Class.forName( columnDescr.getObjectType() );
+                objectType = new ClassObjectType( this.typeResolver.resolveType( columnDescr.getObjectType() )) ;
+            } catch ( final ClassNotFoundException e ) {
+                this.errors.add( new RuleError( this.rule,
+                                                columnDescr,
+                                                null,
+                                                "Unable to resolve ObjectType '" + columnDescr.getObjectType() + "'" ) );
+                return null;
+            }
         }
 
         Column column;
         if ( columnDescr.getIdentifier() != null && !columnDescr.getIdentifier().equals( "" ) ) {
             column = new Column( this.columnCounter.getNext(),
                                  this.columnOffset,
-                                 new ClassObjectType( clazz ),
+                                 objectType,
                                  columnDescr.getIdentifier() );;
             this.declarations.put( column.getDeclaration().getIdentifier(),
                                    column.getDeclaration() );
@@ -411,7 +421,7 @@
         } else {
             column = new Column( this.columnCounter.getNext(),
                                  this.columnOffset,
-                                 new ClassObjectType( clazz ),
+                                 objectType,
                                  null );
         }
 
@@ -434,10 +444,8 @@
     private void build(final Column column,
                        final FieldConstraintDescr fieldConstraintDescr) {
 
-        final Class clazz = ((ClassObjectType) column.getObjectType()).getClassType();
-
         final FieldExtractor extractor = getFieldExtractor( fieldConstraintDescr,
-                                                            clazz,
+                                                            column.getObjectType(),
                                                             fieldConstraintDescr.getFieldName() );
         if ( extractor == null ) {
             // @todo log error
@@ -603,10 +611,8 @@
             return;
         }
 
-        final Class clazz = ((ClassObjectType) column.getObjectType()).getClassType();
-
         final FieldExtractor extractor = getFieldExtractor( fieldBindingDescr,
-                                                            clazz,
+                                                            column.getObjectType(),
                                                             fieldBindingDescr.getFieldName() );
         if ( extractor == null ) {
             return;
@@ -780,10 +786,8 @@
         final String classMethodName = "predicate" + this.counter++;
         predicateDescr.setClassMethodName( classMethodName );
 
-        final Class clazz = ((ClassObjectType) column.getObjectType()).getClassType();
-
         final FieldExtractor extractor = getFieldExtractor( predicateDescr,
-                                                            clazz,
+                                                            column.getObjectType(),
                                                             predicateDescr.getFieldName() );
         if ( extractor == null ) {
             return;
@@ -1062,17 +1066,24 @@
     }
 
     private FieldExtractor getFieldExtractor(final PatternDescr descr,
-                                             final Class clazz,
+                                             final ObjectType objectType,
                                              final String fieldName) {
         FieldExtractor extractor = null;
-        try {
-            extractor = classFieldExtractorCache.getExtractor( clazz,
-                                                               fieldName );
-        } catch ( final RuntimeDroolsException e ) {
-            this.errors.add( new RuleError( this.rule,
-                                            descr,
-                                            e,
-                                            "Unable to create Field Extractor for '" + fieldName + "'" ) );
+        
+        if ( objectType.getValueType() == ValueType.FACTTEMPLATE_TYPE ) {
+            //@todo use extractor cache            
+            FactTemplate factTemplate = ( ( FactTemplateObjectType ) objectType ).getFactTemplate();
+            extractor = new FactTemplateFieldExtractor( factTemplate, factTemplate.getFieldTemplateIndex( fieldName ));
+        } else {        
+            try {
+                extractor = classFieldExtractorCache.getExtractor( ( ( ClassObjectType ) objectType ).getClassType(),
+                                                                   fieldName );
+            } catch ( final RuntimeDroolsException e ) {
+                this.errors.add( new RuleError( this.rule,
+                                                descr,
+                                                e,
+                                                "Unable to create Field Extractor for '" + fieldName + "'" ) );
+            }
         }
 
         return extractor;

Modified: labs/jbossrules/trunk/drools-compiler/src/main/resources/META-INF/drools-3.0.xsd
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/resources/META-INF/drools-3.0.xsd	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/resources/META-INF/drools-3.0.xsd	2006-08-04 00:22:41 UTC (rev 5456)
@@ -180,6 +180,7 @@
   <xs:element name="field-constraint">
     <xs:complexType>
       <xs:choice maxOccurs="unbounded" minOccurs="0">  
+        <xs:element ref="drools:connective-restriction"/>                            
         <xs:element ref="drools:literal-restriction"/>                      
         <xs:element ref="drools:variable-restriction"/>                
         <xs:element ref="drools:return-value-restriction"/>                

Added: labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/lang/drl.g
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/lang/drl.g	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/main/resources/org/drools/lang/drl.g	2006-08-04 00:22:41 UTC (rev 5456)
@@ -0,0 +1,1136 @@
+grammar RuleParser; 
+
+ at parser::header {
+	package org.drools.lang;
+	import java.util.List;
+	import java.util.ArrayList;
+	import java.util.Iterator;
+	import java.util.StringTokenizer;
+	import org.drools.lang.descr.*;
+}
+
+ at parser::members {
+	private ExpanderResolver expanderResolver;
+	private Expander expander;
+	private boolean expanderDebug = false;
+	private PackageDescr packageDescr;
+	private List errors = new ArrayList();
+	private String source = "unknown";
+	private int lineOffset = 0;
+	
+	private boolean parserDebug = false;
+	
+	public void setParserDebug(boolean parserDebug) {
+		this.parserDebug = parserDebug;
+	}
+	
+	public void debug(String message) {
+		if ( parserDebug ) 
+			System.err.println( "drl parser: " + message );
+	}
+	
+	public void setSource(String source) {
+		this.source = source;
+	}
+
+	/**
+	 * This may be set to enable debuggin of DSLs/expanders.
+	 * If set to true, expander stuff will be sent to the Std out.
+	 */	
+	public void setExpanderDebug(boolean status) {
+		expanderDebug = status;
+	}
+	public String getSource() {
+		return this.source;
+	}
+	
+	public PackageDescr getPackageDescr() {
+		return packageDescr;
+	}
+	
+	private int offset(int line) {
+		return line + lineOffset;
+	}
+	
+	/**
+	 * This will set the offset to record when reparsing. Normally is zero of course 
+	 */
+	public void setLineOffset(int i) {
+	 	this.lineOffset = i;
+	}
+	
+	public void setExpanderResolver(ExpanderResolver expanderResolver) {
+		this.expanderResolver = expanderResolver;
+	}
+	
+	public ExpanderResolver getExpanderResolver() {
+		return expanderResolver;
+	}
+	
+	/** Expand the LHS */
+	private String runWhenExpander(String text, int line) throws RecognitionException {
+		String expanded = text.trim();
+		if (expanded.startsWith(">")) {
+			expanded = expanded.substring(1);  //escape !!
+		} else {
+			try {
+				expanded = expander.expand( "when", text );			
+			} catch (Exception e) {
+				this.errors.add(new ExpanderException("Unable to expand: " + text + ". Due to " + e.getMessage(), line));
+				return "";
+			}
+		}
+		if (expanderDebug) {
+			System.out.println("Expanding LHS: " + text + " ----> " + expanded + " --> from line: " + line);
+		}
+		return expanded;	
+		
+	}
+
+        /** Reparse the results of the expansion */
+    	private void reparseLhs(String text, AndDescr descrs) throws RecognitionException {
+    		CharStream charStream = new ANTLRStringStream( text );
+    		RuleParserLexer lexer = new RuleParserLexer( charStream );
+    		TokenStream tokenStream = new CommonTokenStream( lexer );
+    		RuleParser parser = new RuleParser( tokenStream );
+    		parser.setLineOffset( descrs.getLine() );
+    		parser.normal_lhs_block(descrs);
+            
+                if (parser.hasErrors()) {
+    			this.errors.addAll(parser.getErrors());
+    		}
+		if (expanderDebug) {
+			System.out.println("Reparsing LHS: " + text + " --> successful:" + !parser.hasErrors());
+		}    		
+    		
+    	}
+	
+	/** Expand a line on the RHS */
+	private String runThenExpander(String text, int startLine) {
+		//System.err.println( "expand THEN [" + text + "]" );
+		StringTokenizer lines = new StringTokenizer( text, "\n\r" );
+
+		StringBuffer expanded = new StringBuffer();
+		
+		String eol = System.getProperty( "line.separator" );
+				
+		while ( lines.hasMoreTokens() ) {
+			startLine++;
+			String line = lines.nextToken();
+			line = line.trim();
+			if ( line.length() > 0 ) {
+				if ( line.startsWith( ">" ) ) {
+					expanded.append( line.substring( 1 ) );
+					expanded.append( eol );
+				} else {
+					try {
+						expanded.append( expander.expand( "then", line ) );
+						expanded.append( eol );
+					} catch (Exception e) {
+						this.errors.add(new ExpanderException("Unable to expand: " + line + ". Due to " + e.getMessage(), startLine));			
+					}
+				}
+			}
+		}
+		
+		if (expanderDebug) {
+			System.out.println("Expanding RHS: " + text + " ----> " + expanded.toString() + " --> from line starting: " + startLine);
+		}		
+		
+		return expanded.toString();
+	}
+	
+
+	
+	private String getString(Token token) {
+		String orig = token.getText();
+		return orig.substring( 1, orig.length() -1 );
+	}
+	
+	public void reportError(RecognitionException ex) {
+	        // if we've already reported an error and have not matched a token
+                // yet successfully, don't report any errors.
+                if ( errorRecovery ) {
+                        return;
+                }
+                errorRecovery = true;
+
+		ex.line = offset(ex.line); //add the offset if there is one
+		errors.add( ex ); 
+	}
+     	
+     	/** return the raw RecognitionException errors */
+     	public List getErrors() {
+     		return errors;
+     	}
+     	
+     	/** Return a list of pretty strings summarising the errors */
+     	public List getErrorMessages() {
+     		List messages = new ArrayList();
+ 		for ( Iterator errorIter = errors.iterator() ; errorIter.hasNext() ; ) {
+     	     		messages.add( createErrorMessage( (RecognitionException) errorIter.next() ) );
+     	     	}
+     	     	return messages;
+     	}
+     	
+     	/** return true if any parser errors were accumulated */
+     	public boolean hasErrors() {
+  		return ! errors.isEmpty();
+     	}
+     	
+     	/** This will take a RecognitionException, and create a sensible error message out of it */
+     	public String createErrorMessage(RecognitionException e)
+        {
+		StringBuffer message = new StringBuffer();		
+                message.append( source + ":"+e.line+":"+e.charPositionInLine+" ");
+                if ( e instanceof MismatchedTokenException ) {
+                        MismatchedTokenException mte = (MismatchedTokenException)e;
+                        message.append("mismatched token: "+
+                                                           e.token+
+                                                           "; expecting type "+
+                                                           tokenNames[mte.expecting]);
+                }
+                else if ( e instanceof MismatchedTreeNodeException ) {
+                        MismatchedTreeNodeException mtne = (MismatchedTreeNodeException)e;
+                        message.append("mismatched tree node: "+
+                                                           mtne.foundNode+
+                                                           "; expecting type "+
+                                                           tokenNames[mtne.expecting]);
+                }
+                else if ( e instanceof NoViableAltException ) {
+                        NoViableAltException nvae = (NoViableAltException)e;
+			message.append( "Unexpected token '" + e.token.getText() + "'" );
+                        /*
+                        message.append("decision=<<"+nvae.grammarDecisionDescription+">>"+
+                                                           " state "+nvae.stateNumber+
+                                                           " (decision="+nvae.decisionNumber+
+                                                           ") no viable alt; token="+
+                                                           e.token);
+                                                           */
+                }
+                else if ( e instanceof EarlyExitException ) {
+                        EarlyExitException eee = (EarlyExitException)e;
+                        message.append("required (...)+ loop (decision="+
+                                                           eee.decisionNumber+
+                                                           ") did not match anything; token="+
+                                                           e.token);
+                }
+                else if ( e instanceof MismatchedSetException ) {
+                        MismatchedSetException mse = (MismatchedSetException)e;
+                        message.append("mismatched token '"+
+                                                           e.token+
+                                                           "' expecting set "+mse.expecting);
+                }
+                else if ( e instanceof MismatchedNotSetException ) {
+                        MismatchedNotSetException mse = (MismatchedNotSetException)e;
+                        message.append("mismatched token '"+
+                                                           e.token+
+                                                           "' expecting set "+mse.expecting);
+                }
+                else if ( e instanceof FailedPredicateException ) {
+                        FailedPredicateException fpe = (FailedPredicateException)e;
+                        message.append("rule "+fpe.ruleName+" failed predicate: {"+
+                                                           fpe.predicateText+"}?");
+                } else if (e instanceof GeneralParseException) {
+			message.append(" " + e.getMessage());
+		}
+               	return message.toString();
+        }   
+        
+        void checkTrailingSemicolon(String text, int line) {
+        	if (text.trim().endsWith( ";" ) ) {
+        		this.errors.add( new GeneralParseException( "Trailing semi-colon not allowed", offset(line) ) );
+        	}
+        }
+      
+}
+
+ at lexer::header {
+	package org.drools.lang;
+}
+
+opt_eol	:
+		(';'|EOL)*	
+	;
+
+compilation_unit
+	:	opt_eol
+		prolog 
+		(	r=rule 	{this.packageDescr.addRule( r ); } 
+		| 	q=query	{this.packageDescr.addRule( q ); }
+		|	extra_statement 
+		)*
+	;
+	
+prolog
+	@init {
+		String packageName = "";
+	}
+	:	opt_eol
+		( name=package_statement { packageName = name; } )?
+		{ 
+			this.packageDescr = new PackageDescr( name ); 
+		}
+		(	extra_statement
+		|	expander
+		)*
+		
+		opt_eol
+	;
+	
+package_statement returns [String packageName]
+	@init{
+		packageName = null;
+	}
+	:	
+		'package' opt_eol name=dotted_name ';'? opt_eol
+		{
+			packageName = name;
+		}
+	;
+	
+import_statement
+	:	'import' opt_eol name=import_name ';'? opt_eol
+		{
+			if (packageDescr != null) 
+				packageDescr.addImport( name );
+		}	
+	;
+
+import_name returns [String name]
+	@init {
+		name = null;
+	}
+	:	
+		id=ID { name=id.getText(); } ( '.' id=ID { name = name + "." + id.getText(); } )* (star='.*' { name = name + star.getText(); })?
+	;
+expander
+	@init {
+		String config=null;
+	}
+	:	'expander' (name=dotted_name)? ';'? opt_eol
+		{
+			if (expanderResolver == null) 
+				throw new IllegalArgumentException("Unable to use expander. Make sure a expander or dsl config is being passed to the parser. [ExpanderResolver was not set].");
+			if ( expander != null )
+				throw new IllegalArgumentException( "Only one 'expander' statement per file is allowed" );
+			expander = expanderResolver.get( name, config );
+		}
+	;
+	
+global
+	@init {
+	}
+	:
+		'global' type=dotted_name id=ID ';'? opt_eol
+		{
+			packageDescr.addGlobal( id.getText(), type );
+		}
+	;
+	
+function
+	@init {
+		FunctionDescr f = null;
+	}
+	:
+		'function' opt_eol (retType=dotted_name)? opt_eol name=ID opt_eol
+		{
+			//System.err.println( "function :: " + name.getText() );
+			f = new FunctionDescr( name.getText(), retType );
+		} 
+		'(' opt_eol
+			(	(paramType=dotted_name)? opt_eol paramName=argument opt_eol
+				{
+					f.addParameter( paramType, paramName );
+				}
+				(	',' opt_eol (paramType=dotted_name)? opt_eol paramName=argument opt_eol 
+					{
+						f.addParameter( paramType, paramName );
+					}
+				)*
+			)?
+		')'
+		opt_eol
+		'{'
+			body=curly_chunk
+			{
+				f.setText( body );
+			}
+		'}'
+		{
+			packageDescr.addFunction( f );
+		}
+		opt_eol
+	;
+
+
+query returns [QueryDescr query]
+	@init {
+		query = null;
+	}
+	:
+		opt_eol
+		loc='query' queryName=word opt_eol 
+		{ 
+			query = new QueryDescr( queryName, null ); 
+			query.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+			AndDescr lhs = new AndDescr(); query.setLhs( lhs ); 
+			lhs.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+		}
+		(
+			{ expander != null }? expander_lhs_block[lhs]
+			| normal_lhs_block[lhs]
+		)
+					
+		'end' opt_eol
+	;
+
+rule returns [RuleDescr rule]
+	@init {
+		rule = null;
+		String consequence = "";
+	}
+	:
+		opt_eol
+		loc='rule' ruleName=word opt_eol 
+		{ 
+			debug( "start rule: " + ruleName );
+			rule = new RuleDescr( ruleName, null ); 
+			rule.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+		}
+		(	rule_attributes[rule]
+		)?
+		opt_eol
+		((	loc='when' ':'? opt_eol
+			{ 
+				AndDescr lhs = new AndDescr(); rule.setLhs( lhs ); 
+				lhs.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+			}
+			(
+				{ expander != null }? expander_lhs_block[lhs]
+				| normal_lhs_block[lhs]
+			)
+					
+		)?
+		( opt_eol loc='then' ':'?  opt_eol
+			( options{greedy=false;} : any=.
+				{
+					consequence = consequence + " " + any.getText();
+				}
+			)*
+			{
+				if ( expander != null ) {
+					String expanded = runThenExpander( consequence, offset(loc.getLine()) );
+					rule.setConsequence( expanded );
+				} else { 
+					rule.setConsequence( consequence ); 
+				}
+				rule.setConsequenceLocation(offset(loc.getLine()), loc.getCharPositionInLine());
+			})?
+		)?
+		'end' opt_eol
+		{
+			debug( "end rule: " + ruleName );
+		} 
+	;
+	
+extra_statement
+	:
+	(	import_statement
+	|	global
+	|	function
+	)
+	;
+
+rule_attributes[RuleDescr rule]
+	: 
+			'attributes'? ':'? opt_eol
+			(	','? a=rule_attribute opt_eol
+				{
+					rule.addAttribute( a );
+				}
+			)*
+	;
+	
+rule_attribute returns [AttributeDescr d]
+	@init {
+		d = null;
+	}
+	:
+			a=salience { d = a; }
+		|	a=no_loop  { d = a; }
+		|	a=agenda_group  { d = a; }		
+		|	a=duration  { d = a; }			
+		|	a=activation_group { d = a; }	
+		|	a=auto_focus { d = a; }	
+		
+	;
+	
+salience returns [AttributeDescr d ]
+	@init {
+		d = null;
+	}
+	:	
+		loc='salience' opt_eol i=INT ';'? opt_eol
+		{
+			d = new AttributeDescr( "salience", i.getText() );
+			d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+		}
+	;
+	
+no_loop returns [AttributeDescr d]
+	@init {
+		d = null;
+	}
+	:
+		(
+			loc='no-loop' opt_eol ';'? opt_eol
+			{
+				d = new AttributeDescr( "no-loop", "true" );
+				d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+			}
+		) 
+		|
+		(
+			loc='no-loop' t=BOOL opt_eol ';'? opt_eol
+			{
+				d = new AttributeDescr( "no-loop", t.getText() );
+				d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+			}
+		
+		)
+		
+	;
+	
+auto_focus returns [AttributeDescr d]
+	@init {
+		d = null;
+	}
+	:
+		(
+			loc='auto-focus' opt_eol ';'? opt_eol
+			{
+				d = new AttributeDescr( "auto-focus", "true" );
+				d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+			}
+		) 
+		|
+		(
+			loc='auto-focus' t=BOOL opt_eol ';'? opt_eol
+			{
+				d = new AttributeDescr( "auto-focus", t.getText() );
+				d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+			}
+		
+		)
+		
+	;	
+	
+activation_group returns [AttributeDescr d]
+	@init {
+		d = null;
+	}
+	:
+		loc='activation-group' opt_eol name=STRING ';'? opt_eol
+		{
+			d = new AttributeDescr( "activation-group", getString( name ) );
+			d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+		}
+	;
+
+agenda_group returns [AttributeDescr d]
+	@init {
+		d = null;
+	}
+	:
+		loc='agenda-group' opt_eol name=STRING ';'? opt_eol
+		{
+			d = new AttributeDescr( "agenda-group", getString( name ) );
+			d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+		}
+	;		
+
+
+duration returns [AttributeDescr d]
+	@init {
+		d = null;
+	}
+	:
+		loc='duration' opt_eol i=INT ';'? opt_eol
+		{
+			d = new AttributeDescr( "duration", i.getText() );
+			d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+		}
+	;		
+	
+
+normal_lhs_block[AndDescr descrs]
+	:
+		(	d=lhs opt_eol
+			{ descrs.addDescr( d ); }
+		)* opt_eol
+	;
+
+	
+
+	
+expander_lhs_block[AndDescr descrs]
+	@init {
+		String lhsBlock = null;
+		String eol = System.getProperty( "line.separator" );
+	}
+	:
+		(options{greedy=false;} : 
+			text=paren_chunk loc=EOL 
+			{
+				//only expand non null
+				if (text != null) {
+					if (lhsBlock == null) {					
+						lhsBlock = runWhenExpander( text, offset(loc.getLine()));
+					} else {
+						lhsBlock = lhsBlock + eol + runWhenExpander( text, offset(loc.getLine()));
+					}
+					text = null;
+				}
+			}
+			
+		)* 
+		
+		{
+			if (lhsBlock != null) {
+				reparseLhs(lhsBlock, descrs);
+			}
+		}
+
+	;
+	
+	
+	
+lhs returns [PatternDescr d]
+	@init {
+		d=null;
+	}
+	:	l=lhs_or { d = l; } 
+	;
+
+	
+lhs_column returns [PatternDescr d]
+	@init {
+		d=null;
+	}
+	:	f=fact_binding	{ d = f; }
+	|	f=fact		{ d = f; }
+	;
+ 	
+fact_binding returns [PatternDescr d]
+	@init {
+		d=null;
+		boolean multi=false;
+	}
+ 	:
+ 		id=ID 
+ 		
+ 		opt_eol ':' opt_eol fe=fact_expression[id.getText()]
+ 		{
+ 			d=fe;
+ 		}
+	;
+ 
+ fact_expression[String id] returns [PatternDescr pd]
+ 	@init {
+ 		pd = null;
+ 		boolean multi = false;
+ 	}
+ 	:	'(' opt_eol fe=fact_expression[id]opt_eol ')' { pd=fe; }
+ 	| 	f=fact opt_eol
+ 		{
+ 			((ColumnDescr)f).setIdentifier( id );
+ 			pd = f;
+ 		}
+ 		(	('or'|'||') opt_eol
+ 			{	if ( ! multi ) {
+ 					PatternDescr first = pd;
+ 					pd = new OrDescr();
+ 					((OrDescr)pd).addDescr( first );
+ 					multi=true;
+ 				}
+ 			}
+ 			f=fact
+ 			{
+ 				((ColumnDescr)f).setIdentifier( id );
+ 				((OrDescr)pd).addDescr( f );
+ 			}
+ 		)*	
+	;
+ 
+fact returns [PatternDescr d] 
+	@init {
+		d=null;
+	}
+ 	:	id=dotted_name 
+ 		{ 
+ 			d = new ColumnDescr( id ); 
+ 		} opt_eol 
+ 		loc='(' {
+ 				d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+ 			}opt_eol (	c=constraints
+ 				{
+		 			for ( Iterator cIter = c.iterator() ; cIter.hasNext() ; ) {
+ 						((ColumnDescr)d).addDescr( (PatternDescr) cIter.next() );
+ 					}
+ 				}
+ 
+ 				)? opt_eol endLoc=')' opt_eol
+ 				{
+ 					d.setEndLocation( offset(endLoc.getLine()), endLoc.getCharPositionInLine() );	
+ 				}
+ 	;
+	
+	
+constraints returns [List constraints]
+	@init {
+		constraints = new ArrayList();
+	}
+	:	opt_eol
+		(constraint[constraints]|predicate[constraints])
+		( opt_eol ',' opt_eol (constraint[constraints]|predicate[constraints]))*
+		opt_eol
+	;
+	
+constraint[List constraints]
+	@init {
+		PatternDescr d = null;
+	}
+	:	opt_eol
+		( fb=ID opt_eol ':' opt_eol )? 
+		f=ID	
+		{
+
+			if ( fb != null ) {
+				//System.err.println( "fb: " + fb.getText() );
+				//System.err.println( " f: " + f.getText() );
+				d = new FieldBindingDescr( f.getText(), fb.getText() );
+				//System.err.println( "fbd: " + d );
+				
+				d.setLocation( offset(f.getLine()), f.getCharPositionInLine() );
+				constraints.add( d );
+			} 
+			FieldConstraintDescr fc = new FieldConstraintDescr(f.getText());
+			fc.setLocation( offset(f.getLine()), f.getCharPositionInLine() );
+									
+			
+		}				
+			opt_eol (	op=operator opt_eol	
+					
+					(	bvc=ID
+						{
+							
+														
+							
+							VariableRestrictionDescr vd = new VariableRestrictionDescr(op, bvc.getText());
+							fc.addRestriction(vd);
+							constraints.add(fc);
+							
+						}
+					|
+						lc=enum_constraint 
+						{ 
+
+							LiteralRestrictionDescr lrd  = new LiteralRestrictionDescr(op, lc, true);
+							fc.addRestriction(lrd);
+							constraints.add(fc);
+							
+						}						
+					|
+						lc=literal_constraint 
+						{ 
+							
+							LiteralRestrictionDescr lrd  = new LiteralRestrictionDescr(op, lc);
+							fc.addRestriction(lrd);
+							constraints.add(fc);
+							
+						}
+					|	rvc=retval_constraint 
+						{ 
+							
+							
+
+							ReturnValueRestrictionDescr rvd = new ReturnValueRestrictionDescr(op, rvc);							
+							fc.addRestriction(rvd);
+							constraints.add(fc);
+							
+						} 
+					)
+					(
+						con=('&'|'|')
+						{
+							if (con.getText().equals("&") ) {								
+								fc.addRestriction(new RestrictionConnectiveDescr(RestrictionConnectiveDescr.AND));	
+							} else {
+								fc.addRestriction(new RestrictionConnectiveDescr(RestrictionConnectiveDescr.OR));	
+							}							
+						}
+
+						op=operator
+						(	bvc=ID
+							{
+								VariableRestrictionDescr vd = new VariableRestrictionDescr(op, bvc.getText());
+								fc.addRestriction(vd);
+							}
+						|
+							lc=enum_constraint 
+							{ 
+								LiteralRestrictionDescr lrd  = new LiteralRestrictionDescr(op, lc, true);
+								fc.addRestriction(lrd);
+								
+							}						
+						|
+							lc=literal_constraint 
+							{ 
+								LiteralRestrictionDescr lrd  = new LiteralRestrictionDescr(op, lc);
+								fc.addRestriction(lrd);
+								
+							}
+						|	rvc=retval_constraint 
+							{ 
+								ReturnValueRestrictionDescr rvd = new ReturnValueRestrictionDescr(op, rvc);							
+								fc.addRestriction(rvd);
+								
+							} 
+						)						
+						
+					)*
+				)?					
+		opt_eol
+	;
+		
+literal_constraint returns [String text]
+	@init {
+		text = null;
+	}
+	:	(	t=STRING { text = getString( t ); } //t.getText(); text=text.substring( 1, text.length() - 1 ); }
+		|	t=INT    { text = t.getText(); }
+		|	t=FLOAT	 { text = t.getText(); }
+		|	t=BOOL 	 { text = t.getText(); }
+		|	t='null' { text = null; }
+		)
+	;
+	
+enum_constraint returns [String text]
+	@init {
+		text = null;
+	}
+	:	(cls=ID '.' en=ID) { text = cls.getText() + "." + en.getText(); }
+	;	
+	
+retval_constraint returns [String text]
+	@init {
+		text = null;
+	}
+	:	
+		'('  c=paren_chunk  ')' { text = c; }
+	;
+
+predicate[List constraints]
+	:
+		decl=ID ':' field=ID '->' '(' text=paren_chunk ')'
+		{
+			PredicateDescr d = new PredicateDescr(field.getText(), decl.getText(), text );
+			constraints.add( d );
+		}
+	;
+	
+paren_chunk returns [String text]
+	@init {
+		text = null;
+	}
+	
+	:
+		 (	options{greedy=false;} : 
+			'(' c=paren_chunk ')' 	
+			{
+				if ( c == null ) {
+					c = "";
+				}
+				if ( text == null ) {
+					text = "( " + c + " )";
+				} else {
+					text = text + " ( " + c + " )";
+				}
+			} 
+		| any=. 
+			{
+				if ( text == null ) {
+					text = any.getText();
+				} else {
+					text = text + " " + any.getText(); 
+				} 
+			}
+		)* 
+	;
+	
+//NOTE: this is needed as there is a bug in antlr if you sometimes use the same sub rule in multiple places
+paren_chunk2 returns [String text]
+	@init {
+		text = null;
+	}
+	
+	:
+		 (	options{greedy=false;} : 
+			'(' c=paren_chunk2 ')' 	
+			{
+				if ( c == null ) {
+					c = "";
+				}
+				if ( text == null ) {
+					text = "( " + c + " )";
+				} else {
+					text = text + " ( " + c + " )";
+				}
+			} 
+		| any=. 
+			{
+				if ( text == null ) {
+					text = any.getText();
+				} else {
+					text = text + " " + any.getText(); 
+				} 
+			}
+		)* 
+	;
+	
+curly_chunk returns [String text]
+	@init {
+		text = null;
+	}
+	
+	:
+		(	options{greedy=false;} : 
+			'{' c=curly_chunk '}' 	
+			{
+				//System.err.println( "chunk [" + c + "]" );
+				if ( c == null ) {
+					c = "";
+				}
+				if ( text == null ) {
+					text = "{ " + c + " }";
+				} else {
+					text = text + " { " + c + " }";
+				}
+			} 
+		| any=. 
+			{
+				//System.err.println( "any [" + any.getText() + "]" );
+				if ( text == null ) {
+					text = any.getText();
+				} else {
+					text = text + " " + any.getText(); 
+				} 
+			}
+		)*
+	;	
+	
+lhs_or returns [PatternDescr d]
+	@init{
+		d = null;
+	}
+	:	
+		{ OrDescr or = null; }
+		left=lhs_and {d = left; }
+		( ('or'|'||') opt_eol
+			right=lhs_and 
+			{
+				if ( or == null ) {
+					or = new OrDescr();
+					or.addDescr( left );
+					d = or;
+				}
+				
+				or.addDescr( right );
+			}
+		)*
+	;
+	
+lhs_and returns [PatternDescr d]
+	@init{
+		d = null;
+	}
+	:
+		{ AndDescr and = null; }
+		left=lhs_unary { d = left; }
+		( ('and'|'&&') opt_eol
+			right=lhs_unary 
+			{
+				if ( and == null ) {
+					and = new AndDescr();
+					and.addDescr( left );
+					d = and;
+				}
+				
+				and.addDescr( right );
+			}
+		)* 
+	;
+	
+lhs_unary returns [PatternDescr d]
+	@init {
+		d = null;
+	}
+	:	(	u=lhs_exist
+		|	u=lhs_not
+		|	u=lhs_eval
+		|	u=lhs_column
+		|	'(' opt_eol u=lhs opt_eol ')'
+		) { d = u; }
+	;
+	
+lhs_exist returns [PatternDescr d]
+	@init {
+		d = null;
+	}
+	:	loc='exists' ('(' column=lhs_column ')' | column=lhs_column)
+		{ 
+			d = new ExistsDescr( (ColumnDescr) column ); 
+			d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+		}	
+	;
+	
+lhs_not	returns [NotDescr d]
+	@init {
+		d = null;
+	}
+	:	loc='not' ('(' column=lhs_column  ')' | column=lhs_column)
+		{
+			d = new NotDescr( (ColumnDescr) column ); 
+			d.setLocation( offset(loc.getLine()), loc.getCharPositionInLine() );
+		}
+	;
+
+lhs_eval returns [PatternDescr d]
+	@init {
+		d = null;
+		String text = "";
+	}
+	:	'eval' loc='(' 
+			c=paren_chunk2
+		')' 
+		{ 
+			checkTrailingSemicolon( c, offset(loc.getLine()) );
+			d = new EvalDescr( c ); 
+		}
+	;
+	
+dotted_name returns [String name]
+	@init {
+		name = null;
+	}
+	:	
+		id=ID { name=id.getText(); } ( '.' id=ID { name = name + "." + id.getText(); } )* ( '[' ']' { name = name + "[]";})*
+	;
+	
+argument returns [String name]
+	@init {
+		name = null;
+	}
+	:
+		id=ID { name=id.getText(); } ( '[' ']' { name = name + "[]";})*
+	;
+
+	
+word returns [String word]
+	@init{
+		word = null;
+	}
+	:	id=ID      { word=id.getText(); }
+	|	'import'   { word="import"; }
+	|	'use'      { word="use"; }
+	|	'rule'     { word="rule"; }
+	|	'query'    { word="query"; }
+	|	'salience' { word="salience"; }
+ 	|	'no-loop'  { word="no-loop"; }
+	|	'when'     { word="when"; }
+	|	'then'     { word="then"; }
+	|	'end'      { word="end"; }
+	|	str=STRING { word=getString(str);} //str.getText(); word=word.substring( 1, word.length()-1 ); }
+	;
+
+operator returns [String str] 	
+	@init {
+		str = null;
+	}
+	:
+
+		'==' {str= "==";}
+		|'=' {str="==";}
+		|'>' {str=">";}
+		|'>=' {str=">=";}		
+		|'<' {str="<";}
+		|'<=' {str="<=";}
+		|'!=' {str="!=";}
+		|'contains' {str="contains";}
+		|'matches' {str="matches";}
+		|'excludes' {str="excludes";}
+					
+						
+	;
+
+
+
+MISC 	:
+		'!' | '@' | '$' | '%' | '^' | '&' | '*' | '_' | '-' | '+'  | '?'
+		| '|' | ',' | '{' | '}' | '[' | ']' | '=' | '/' | '(' | ')' | '\'' | '\\'
+		| '||' | '&&' | '<<<' | '++' | '--' | '>>>' | '==' | '+=' | '=+' | '-=' | '=-' |'*=' | '=*' 
+		| '/=' | '=/' | '>>=' 
+		
+	;
+	
+WS      :       (	' '
+                |	'\t'
+                |	'\f'
+                )
+                { channel=99; }
+        ;
+        
+EOL 	:	     
+   		(       ( '\r\n' )=> '\r\n'  // Evil DOS
+                |       '\r'    // Macintosh
+                |       '\n'    // Unix (the right way)
+                )
+        ;  
+        
+INT	
+	:	('-')?('0'..'9')+
+	;
+
+FLOAT
+	:	('-')?('0'..'9')+ '.' ('0'..'9')+
+	;
+	
+STRING
+	:	('"' ( options{greedy=false;} : .)* '"' ) | ('\'' ( options{greedy=false;} : .)* '\'')
+	;
+	
+BOOL
+	:	('true'|'false') 
+	;	
+	
+ID	
+	:	('a'..'z'|'A'..'Z'|'_'|'$' | '\u00c0'..'\u00ff')('a'..'z'|'A'..'Z'|'_'|'0'..'9' | '\u00c0'..'\u00ff')* 
+	;
+		
+
+SH_STYLE_SINGLE_LINE_COMMENT	
+	:	'#' ( options{greedy=false;} : .)* EOL /* ('\r')? '\n'  */
+                { channel=99; }
+	;
+        
+        
+C_STYLE_SINGLE_LINE_COMMENT	
+	:	'//' ( options{greedy=false;} : .)* EOL // ('\r')? '\n' 
+                { channel=99; }
+	;
+
+MULTI_LINE_COMMENT
+	:	'/*' (options{greedy=false;} : .)* '*/'
+                { channel=99; }
+	;

Modified: labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java
===================================================================
--- labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java	2006-08-04 00:03:47 UTC (rev 5455)
+++ labs/jbossrules/trunk/drools-compiler/src/test/java/org/drools/compiler/PackageBuilderTest.java	2006-08-04 00:22:41 UTC (rev 5456)
@@ -43,13 +43,16 @@
 import org.drools.common.ActivationGroupNode;
 import org.drools.common.InternalFactHandle;
 import org.drools.common.LogicalDependency;
+import org.drools.facttemplates.Fact;
 import org.drools.lang.descr.AndDescr;
 import org.drools.lang.descr.ColumnDescr;
 import org.drools.lang.descr.ConditionalElementDescr;
 import org.drools.lang.descr.EvalDescr;
 import org.drools.lang.descr.ExistsDescr;
+import org.drools.lang.descr.FactTemplateDescr;
 import org.drools.lang.descr.FieldBindingDescr;
 import org.drools.lang.descr.FieldConstraintDescr;
+import org.drools.lang.descr.FieldTemplateDescr;
 import org.drools.lang.descr.LiteralRestrictionDescr;
 import org.drools.lang.descr.NotDescr;
 import org.drools.lang.descr.OrDescr;
@@ -280,7 +283,54 @@
         } catch ( final RuntimeException e ) {
             assertNotNull( e.getMessage() );
         }
+    }
+    
+    public void testFactTemplate()  {
+        final PackageBuilder builder = new PackageBuilder();
 
+        final PackageDescr packageDescr = new PackageDescr( "p1" );
+        final RuleDescr ruleDescr = new RuleDescr( "rule-1" );
+        packageDescr.addRule( ruleDescr );
+
+        final AndDescr lhs = new AndDescr();
+        ruleDescr.setLhs( lhs );
+
+        FactTemplateDescr cheese = new FactTemplateDescr( "Cheese" );
+        cheese.addFieldTemplate( new FieldTemplateDescr( "name", "String" ) );
+        cheese.addFieldTemplate(new  FieldTemplateDescr( "price", "Integer" ) );
+
+        packageDescr.addFactTemplate( cheese );
+        
+        final ColumnDescr column = new ColumnDescr( "Cheese",
+                                                    "stilton" );
+        lhs.addDescr( column );
+        
+        FieldConstraintDescr literalDescr = new FieldConstraintDescr( "name" );
+        literalDescr.addRestriction( new LiteralRestrictionDescr("==", "stilton") );        
+
+        column.addDescr( literalDescr );
+
+        ruleDescr.setConsequence( "System.out.println( stilton.getFieldValue( \"name\" ) + \" \" + stilton.getFieldValue( \"price\" ) );" );
+
+        builder.addPackage( packageDescr );
+
+        assertLength( 0,
+                      builder.getErrors() );
+        
+        RuleBase ruleBase = RuleBaseFactory.newRuleBase();
+        Package pkg = builder.getPackage();
+        try {
+            ruleBase.addPackage( pkg );
+        } catch ( Exception e ) {
+            e.printStackTrace();
+        }
+        WorkingMemory workingMemory = ruleBase.newWorkingMemory();
+        Fact stilton = pkg.getFactTemplate( "Cheese" ).createFact( 1 );
+        stilton.setFieldValue( "name", "stilton" );
+        stilton.setFieldValue( "price", new Integer( 200 ) );
+        workingMemory.assertObject( stilton );        
+        workingMemory.fireAllRules();
+        
     }
 
     public void testLiteral() throws Exception {
@@ -298,7 +348,7 @@
         lhs.addDescr( column );
         
         FieldConstraintDescr literalDescr = new FieldConstraintDescr( "type" );
-        literalDescr.addRestriction( new VariableRestrictionDescr("==", "stilton") );        
+        literalDescr.addRestriction( new LiteralRestrictionDescr("==", "stilton") );        
 
         column.addDescr( literalDescr );
 




More information about the jboss-svn-commits mailing list