From 84512926a9b2ec5134e8ed69ae205aef09a1d754 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ji=C5=99=C3=AD=20Locker?= <jiri.locker@gmail.com>
Date: Mon, 15 Jan 2024 21:25:22 +0100
Subject: [PATCH] Move necessary files without any additional modifications

---
 .../org/drools/parser/DRL6Expressions.g4      | 836 ++++++++++++++++++
 .../org/drools/parser/DRLExpressions.java     |  54 ++
 .../java/org/drools/parser/DrlExprParser.java |  88 ++
 .../parser/DroolsParserExceptionFactory.java  | 380 ++++++++
 .../java/org/drools/parser/ParserHelper.java  | 672 ++++++++++++++
 .../org/drools/parser/DRLExprParserTest.java  | 270 ++++++
 6 files changed, 2300 insertions(+)
 create mode 100644 drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRL6Expressions.g4
 create mode 100644 drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLExpressions.java
 create mode 100644 drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DrlExprParser.java
 create mode 100644 drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DroolsParserExceptionFactory.java
 create mode 100644 drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/ParserHelper.java
 create mode 100644 drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/DRLExprParserTest.java

diff --git a/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRL6Expressions.g4 b/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRL6Expressions.g4
new file mode 100644
index 00000000000..b531c38feff
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/src/main/antlr4/org/drools/parser/DRL6Expressions.g4
@@ -0,0 +1,836 @@
+parser grammar DRL6Expressions;
+              
+options { 
+    language = Java;
+    tokenVocab = DRL6Lexer;
+    superClass=DRLExpressions;
+}
+  
+@header {
+    package org.drools.drl.parser.lang;
+
+    import java.util.LinkedList;
+    import org.drools.drl.parser.DroolsParserException;
+    import org.drools.drl.parser.lang.ParserHelper;
+    import org.drools.drl.parser.lang.DroolsParserExceptionFactory;
+    import org.drools.drl.parser.lang.Location;
+
+    import org.drools.drl.ast.dsl.AnnotatedDescrBuilder;
+    import org.drools.drl.ast.dsl.AnnotationDescrBuilder;
+
+    import org.drools.drl.ast.descr.AtomicExprDescr;
+    import org.drools.drl.ast.descr.AnnotatedBaseDescr;
+    import org.drools.drl.ast.descr.AnnotationDescr;
+    import org.drools.drl.ast.descr.BaseDescr;
+    import org.drools.drl.ast.descr.ConstraintConnectiveDescr;
+    import org.drools.drl.ast.descr.RelationalExprDescr;
+    import org.drools.drl.ast.descr.BindingDescr;
+}
+
+@members {
+    private ParserHelper helper;
+
+    public DRL6Expressions(TokenStream input,
+                          RecognizerSharedState state,
+                          ParserHelper helper ) {
+        this( input,
+              state );
+        this.helper = helper;
+    }
+
+    public ParserHelper getHelper()                           { return helper; }
+    public boolean hasErrors()                                { return helper.hasErrors(); }
+    public List<DroolsParserException> getErrors()            { return helper.getErrors(); }
+    public List<String> getErrorMessages()                    { return helper.getErrorMessages(); }
+    public void enableEditorInterface()                       {        helper.enableEditorInterface(); }
+    public void disableEditorInterface()                      {        helper.disableEditorInterface(); }
+    public LinkedList<DroolsSentence> getEditorInterface()    { return helper.getEditorInterface(); }
+    public void reportError(RecognitionException ex)          {        helper.reportError( ex ); }
+    public void emitErrorMessage(String msg)                  {}
+
+    private boolean buildDescr;
+    private int inMap = 0;
+    private int ternOp = 0;
+    private boolean hasBindings;
+    public void setBuildDescr( boolean build ) { this.buildDescr = build; }
+    public boolean isBuildDescr() { return this.buildDescr; }
+
+    public void setLeftMostExpr( String value ) { helper.setLeftMostExpr( value ); }
+    public String getLeftMostExpr() { return helper.getLeftMostExpr(); }
+
+    public void setHasBindings( boolean value ) { this.hasBindings = value; }
+    public boolean hasBindings() { return this.hasBindings; }
+
+    private boolean isNotEOF() {
+        if (state.backtracking != 0){
+            return false;
+        }
+        if (input.get( input.index() - 1 ).getType() == DRL6Lexer.WS){
+            return true;
+        }
+        if (input.LA(-1) == DRL6Lexer.LEFT_PAREN){
+            return true;
+        }
+        return input.get( input.index() ).getType() != DRL6Lexer.EOF;
+    }
+
+    private boolean notStartWithNewline() {
+        int currentTokenIndex = input.index(); // current position in input stream
+        Token previousHiddenToken = input.get(currentTokenIndex - 1);
+        String previousHiddenTokenText = previousHiddenToken.getText();
+        return !previousHiddenTokenText.contains("\n");
+    }
+}
+
+// Alter code generation so catch-clauses get replace with
+// this action.
+@rulecatch {
+catch (RecognitionException re) {
+    throw re;
+}
+}
+
+// --------------------------------------------------------
+//                      GENERAL RULES
+// --------------------------------------------------------
+literal
+    :	STRING        {	helper.emit($STRING, DroolsEditorType.STRING_CONST);	}
+    |	DECIMAL       {	helper.emit($DECIMAL, DroolsEditorType.NUMERIC_CONST);	}
+    |	HEX           {	helper.emit($HEX, DroolsEditorType.NUMERIC_CONST);	}
+    |	FLOAT         {	helper.emit($FLOAT, DroolsEditorType.NUMERIC_CONST);	}
+    |	BOOL          {	helper.emit($BOOL, DroolsEditorType.BOOLEAN_CONST);	}
+    |	NULL          {	helper.emit($NULL, DroolsEditorType.NULL_CONST);	}
+    |   TIME_INTERVAL {	helper.emit($TIME_INTERVAL, DroolsEditorType.NULL_CONST); }
+    |   STAR          { helper.emit($STAR, DroolsEditorType.NUMERIC_CONST); } // this means "infinity" in Drools
+    ;
+
+operator returns [boolean negated, String opr]
+@init{ if ( isNotEOF() ) helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR ); helper.setHasOperator( true ); }
+@after{ if( state.backtracking == 0 && input.LA( 1 ) != DRL6Lexer.EOF) { helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT ); } }
+  : x=TILDE?
+    ( op=EQUALS        { $negated = false; $opr=($x != null ? $x.text : "")+$op.text; helper.emit($op, DroolsEditorType.SYMBOL); }
+    | op=NOT_EQUALS    { $negated = false; $opr=($x != null ? $x.text : "")+$op.text; helper.emit($op, DroolsEditorType.SYMBOL); }
+    | rop=relationalOp { $negated = $rop.negated; $opr=($x != null ? $x.text : "")+$rop.opr; }
+    )
+    ;
+
+
+
+relationalOp returns [boolean negated, String opr, java.util.List<String> params]
+@init{ if ( isNotEOF() ) helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR ); helper.setHasOperator( true ); }
+@after{ if( state.backtracking == 0 && input.LA( 1 ) != DRL6Lexer.EOF) { helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT ); } }
+  : ( op=LESS_EQUALS     { $negated = false; $opr=$op.text; $params = null; helper.emit($op, DroolsEditorType.SYMBOL);}
+    | op=GREATER_EQUALS  { $negated = false; $opr=$op.text; $params = null; helper.emit($op, DroolsEditorType.SYMBOL);}
+    | op=LESS            { $negated = false; $opr=$op.text; $params = null; helper.emit($op, DroolsEditorType.SYMBOL);}
+    | op=GREATER         { $negated = false; $opr=$op.text; $params = null; helper.emit($op, DroolsEditorType.SYMBOL);}
+    | xop=complexOp      { $negated = false; $opr=$op.text; $params = null; helper.emit($op, DroolsEditorType.SYMBOL);}
+    | not_key nop=neg_operator_key { $negated = true; $opr=$nop.text;}
+    | cop=operator_key  { $negated = false; $opr=$cop.text;}
+    )
+    ;
+
+complexOp returns [String opr]
+    : t=TILDE e=EQUALS_ASSIGN   { $opr=$t.text+$e.text; }
+    ;
+
+typeList
+    :	type (COMMA type)*
+    ;
+
+type
+    : 	tm=typeMatch
+    ;
+
+typeMatch
+    : 	(primitiveType) => ( primitiveType ((LEFT_SQUARE RIGHT_SQUARE)=> LEFT_SQUARE RIGHT_SQUARE)* )
+    |	( ID ((typeArguments)=>typeArguments)? (DOT ID ((typeArguments)=>typeArguments)? )* ((LEFT_SQUARE RIGHT_SQUARE)=> LEFT_SQUARE RIGHT_SQUARE)* )
+    ;
+
+typeArguments
+    :	LESS typeArgument (COMMA typeArgument)* GREATER
+    ;
+
+typeArgument
+    :	type
+    |	QUESTION ((extends_key | super_key) type)?
+    ;
+
+// --------------------------------------------------------
+//                      EXPRESSIONS
+// --------------------------------------------------------
+// the following dymmy rule is to force the AT symbol to be
+// included in the follow set of the expression on the DFAs
+dummy
+    :	expression ( AT | SEMICOLON | EOF | ID | RIGHT_PAREN ) ;
+
+dummy2
+    :  relationalExpression EOF;
+
+// top level entry point for arbitrary expression parsing
+expression returns [BaseDescr result]
+    :	left=conditionalExpression { if( buildDescr  ) { $result = $left.result; } }
+        ((assignmentOperator) => op=assignmentOperator right=expression)?
+    ;
+
+conditionalExpression returns [BaseDescr result]
+    :   left=conditionalOrExpression { if( buildDescr  ) { $result = $left.result; } }
+        ternaryExpression?
+    ;
+
+ternaryExpression
+@init{ ternOp++; }
+    :	QUESTION ts=expression COLON fs=expression
+    ;
+finally { ternOp--; }
+
+
+fullAnnotation [AnnotatedDescrBuilder inDescrBuilder] returns [AnnotationDescr result]
+@init{ String n = ""; AnnotationDescrBuilder annoBuilder = null; }
+  : AT name=ID { n = $name.text; } ( DOT x=ID { n += "." + $x.text; } )*
+        { if( buildDescr ) {
+                if ( inDescrBuilder == null ) {
+                    $result = new AnnotationDescr( n );
+                } else {
+                    annoBuilder = inDescrBuilder instanceof AnnotationDescrBuilder ?
+                        ((AnnotationDescrBuilder) inDescrBuilder).newAnnotation( n ) : inDescrBuilder.newAnnotation( n );
+                    $result = (AnnotationDescr) annoBuilder.getDescr();
+                }
+            }
+        }
+    annotationArgs[result, annoBuilder]
+  ;
+
+annotationArgs [AnnotationDescr descr, AnnotatedDescrBuilder inDescrBuilder]
+  : LEFT_PAREN
+    (
+       (ID EQUALS_ASSIGN) => annotationElementValuePairs[descr, inDescrBuilder]
+       | value=annotationValue[inDescrBuilder] { if ( buildDescr ) { $descr.setValue( $value.result ); } }
+    )?
+    RIGHT_PAREN
+  ;
+
+annotationElementValuePairs [AnnotationDescr descr, AnnotatedDescrBuilder inDescrBuilder]
+  : annotationElementValuePair[descr, inDescrBuilder] ( COMMA annotationElementValuePair[descr, inDescrBuilder] )*
+  ;
+
+annotationElementValuePair [AnnotationDescr descr, AnnotatedDescrBuilder inDescrBuilder]
+  : key=ID EQUALS_ASSIGN val=annotationValue[inDescrBuilder] { if ( buildDescr ) { $descr.setKeyValue( $key.text, $val.result ); } }
+  ;
+
+annotationValue[AnnotatedDescrBuilder inDescrBuilder] returns [Object result]
+  : exp=expression { if ( buildDescr ) $result = $exp.text; }
+    | annos=annotationArray[inDescrBuilder] { if ( buildDescr ) $result = $annos.result.toArray(); }
+    | anno=fullAnnotation[inDescrBuilder] { if ( buildDescr ) $result = $anno.result; }
+  ;
+
+annotationArray[AnnotatedDescrBuilder inDescrBuilder] returns [java.util.List result]
+@init { $result = new java.util.ArrayList();}
+  :  LEFT_CURLY ( anno=annotationValue[inDescrBuilder] { $result.add( $anno.result ); }
+                ( COMMA anno=annotationValue[inDescrBuilder] { $result.add( $anno.result ); } )* )?
+     RIGHT_CURLY
+  ;
+
+
+
+conditionalOrExpression returns [BaseDescr result]
+  : left=conditionalAndExpression  { if( buildDescr ) { $result = $left.result; } }
+  ( DOUBLE_PIPE
+        {  if ( isNotEOF() ) helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR );  }
+        args=fullAnnotation[null]? right=conditionalAndExpression
+         { if( buildDescr  ) {
+               ConstraintConnectiveDescr descr = ConstraintConnectiveDescr.newOr();
+               descr.addOrMerge( $result );
+               descr.addOrMerge( $right.result );
+               if ( args != null ) { descr.addAnnotation( $args.result ); }
+               $result = descr;
+           }
+         }
+  )*
+  ;
+
+conditionalAndExpression returns [BaseDescr result]
+  : left=inclusiveOrExpression { if( buildDescr  ) { $result = $left.result; } }
+  ( DOUBLE_AMPER
+         { if ( isNotEOF() ) helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR ); }
+        args=fullAnnotation[null]? right=inclusiveOrExpression
+         { if( buildDescr  ) {
+               ConstraintConnectiveDescr descr = ConstraintConnectiveDescr.newAnd();
+               descr.addOrMerge( $result );
+               descr.addOrMerge( $right.result );
+               if ( args != null ) { descr.addAnnotation( $args.result ); }
+               $result = descr;
+           }
+         }
+  )*
+  ;
+
+inclusiveOrExpression returns [BaseDescr result]
+  : left=exclusiveOrExpression { if( buildDescr  ) { $result = $left.result; } }
+  ( PIPE right=exclusiveOrExpression
+         { if( buildDescr  ) {
+               ConstraintConnectiveDescr descr = ConstraintConnectiveDescr.newIncOr();
+               descr.addOrMerge( $result );
+               descr.addOrMerge( $right.result );
+               $result = descr;
+           }
+         }
+  )*
+  ;
+
+exclusiveOrExpression returns [BaseDescr result]
+  : left=andExpression { if( buildDescr  ) { $result = $left.result; } }
+  ( XOR right=andExpression
+         { if( buildDescr  ) {
+               ConstraintConnectiveDescr descr = ConstraintConnectiveDescr.newXor();
+               descr.addOrMerge( $result );
+               descr.addOrMerge( $right.result );
+               $result = descr;
+           }
+         }
+  )*
+  ;
+
+andExpression returns [BaseDescr result]
+  : left=equalityExpression { if( buildDescr  ) { $result = $left.result; } }
+  ( AMPER right=equalityExpression
+         { if( buildDescr  ) {
+               ConstraintConnectiveDescr descr = ConstraintConnectiveDescr.newIncAnd();
+               descr.addOrMerge( $result );
+               descr.addOrMerge( $right.result );
+               $result = descr;
+           }
+         }
+  )*
+  ;
+
+equalityExpression returns [BaseDescr result]
+  : left=instanceOfExpression { if( buildDescr  ) { $result = $left.result; } }
+  ( ( op=EQUALS | op=NOT_EQUALS )
+    {  helper.setHasOperator( true );
+       if( input.LA( 1 ) != DRL6Lexer.EOF ) helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT ); }
+    right=instanceOfExpression
+         { if( buildDescr  ) {
+               $result = new RelationalExprDescr( $op.text, false, null, $left.result, $right.result );
+           }
+         }
+  )*
+  ;
+
+instanceOfExpression returns [BaseDescr result]
+  : left=inExpression { if( buildDescr  ) { $result = $left.result; } }
+  ( op=instanceof_key
+    {  helper.setHasOperator( true );
+       if( input.LA( 1 ) != DRL6Lexer.EOF ) helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT ); }
+    right=type
+         { if( buildDescr  ) {
+               $result = new RelationalExprDescr( $op.text, false, null, $left.result, new AtomicExprDescr($right.text) );
+           }
+         }
+  )?
+  ;
+
+inExpression returns [BaseDescr result]
+@init { ConstraintConnectiveDescr descr = null; BaseDescr leftDescr = null; BindingDescr binding = null; }
+@after { if( binding != null && descr != null ) descr.addOrMerge( binding ); }
+  : left=relationalExpression
+    { if( buildDescr  ) { $result = $left.result; }
+      if( $left.result instanceof BindingDescr ) {
+          binding = (BindingDescr)$left.result;
+          leftDescr = new AtomicExprDescr( binding.getExpression() );
+      } else {
+          leftDescr = $left.result;
+      }
+    }
+    ((not_key in_key)=> not_key in=in_key LEFT_PAREN
+        {   helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT ); }
+        e1=expression
+        {   descr = ConstraintConnectiveDescr.newAnd();
+            RelationalExprDescr rel = new RelationalExprDescr( "!=", false, null, leftDescr, $e1.result );
+            descr.addOrMerge( rel );
+            $result = descr;
+        }
+      (COMMA e2=expression
+        {   RelationalExprDescr rel = new RelationalExprDescr( "!=", false, null, leftDescr, $e2.result );
+            descr.addOrMerge( rel );
+        }
+      )* RIGHT_PAREN
+    { helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_END ); }
+    | in=in_key LEFT_PAREN
+        {   helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT ); }
+        e1=expression
+        {   descr = ConstraintConnectiveDescr.newOr();
+            RelationalExprDescr rel = new RelationalExprDescr( "==", false, null, leftDescr, $e1.result );
+            descr.addOrMerge( rel );
+            $result = descr;
+        }
+      (COMMA e2=expression
+        {   RelationalExprDescr rel = new RelationalExprDescr( "==", false, null, leftDescr, $e2.result );
+            descr.addOrMerge( rel );
+        }
+      )* RIGHT_PAREN
+    { helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_END ); }
+    )?
+  ;
+
+relationalExpression returns [BaseDescr result]
+scope { BaseDescr lsd; }
+@init { $relationalExpression::lsd = null; }
+  : left=shiftExpression
+    { if( buildDescr  ) {
+          if ( $left.result == null ) {
+            $result = new AtomicExprDescr( $left.text );
+          } else if ( $left.result instanceof AtomicExprDescr ) {
+            if ( $left.text.equals(((AtomicExprDescr)$left.result).getExpression()) ) {
+              $result = $left.result;
+            } else {
+              $result = new AtomicExprDescr( $left.text ) ;
+            }
+          } else if ( $left.result instanceof BindingDescr ) {
+              if ( $left.text.equals(((BindingDescr)$left.result).getExpression()) ) {
+                $result = $left.result;
+              } else {
+                BindingDescr bind = (BindingDescr) $left.result;
+                int offset = bind.isUnification() ? 2 : 1;
+                String fullExpression = $left.text.substring( $left.text.indexOf( ":" ) + offset ).trim();
+                $result = new BindingDescr( bind.getVariable(), bind.getExpression(), fullExpression, bind.isUnification() );
+              }
+          } else {
+              $result = $left.result;
+          }
+          $relationalExpression::lsd = $result;
+      }
+    }
+  ( ( operator | LEFT_PAREN )=> right=orRestriction
+         { if( buildDescr  ) {
+               $result = $right.result;
+               $relationalExpression::lsd = $result;
+           }
+         }
+  )*
+  ;
+
+orRestriction returns [BaseDescr result]
+  : left=andRestriction { if( buildDescr  ) { $result = $left.result; } }
+    ( (DOUBLE_PIPE fullAnnotation[null]? andRestriction)=>lop=DOUBLE_PIPE args=fullAnnotation[null]? right=andRestriction
+         { if( buildDescr ) {
+               ConstraintConnectiveDescr descr = ConstraintConnectiveDescr.newOr();
+               descr.addOrMerge( $result );
+               descr.addOrMerge( $right.result );
+               if ( args != null ) { descr.addAnnotation( $args.result ); }
+               $result = descr;
+           }
+         }
+   )* EOF?
+  ;
+
+andRestriction returns [BaseDescr result]
+  : left=singleRestriction { if( buildDescr  ) { $result = $left.result; } }
+  ( (DOUBLE_AMPER fullAnnotation[null]? operator)=>lop=DOUBLE_AMPER
+  	    { if ( isNotEOF() ) helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_OPERATOR ); }
+        args=fullAnnotation[null]?right=singleRestriction
+         { if( buildDescr  ) {
+               ConstraintConnectiveDescr descr = ConstraintConnectiveDescr.newAnd();
+               descr.addOrMerge( $result );
+               descr.addOrMerge( $right.result );
+               if ( args != null ) { descr.addAnnotation( $args.result ); }
+               $result = descr;
+           }
+         }
+  )*
+  ;
+
+singleRestriction returns [BaseDescr result]
+  :  op=operator
+         { helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_ARGUMENT ); }
+     ( (squareArguments shiftExpression)=> sa=squareArguments value=shiftExpression
+       | value=shiftExpression
+     )
+         { if( buildDescr  ) {
+               BaseDescr descr = ( $value.result != null &&
+                                 ( (!($value.result instanceof AtomicExprDescr)) ||
+                                   ($value.text.equals(((AtomicExprDescr)$value.result).getExpression())) )) ?
+		                    $value.result :
+		                    new AtomicExprDescr( $value.text ) ;
+               $result = new RelationalExprDescr( $op.opr, $op.negated, $sa.args, $relationalExpression::lsd, descr );
+	       if( $relationalExpression::lsd instanceof BindingDescr ) {
+	           $relationalExpression::lsd = new AtomicExprDescr( ((BindingDescr)$relationalExpression::lsd).getExpression() );
+	       }
+           }
+           helper.emit( Location.LOCATION_LHS_INSIDE_CONDITION_END );
+         }
+  |  LEFT_PAREN or=orRestriction RIGHT_PAREN  { $result = $or.result; }
+  ;
+
+
+
+shiftExpression returns [BaseDescr result]
+  : left=additiveExpression { if( buildDescr  ) { $result = $left.result; } }
+    ( (shiftOp)=>shiftOp additiveExpression )*
+  ;
+
+shiftOp
+    :	( LESS LESS
+        | GREATER GREATER GREATER
+        | GREATER GREATER  )
+    ;
+
+additiveExpression returns [BaseDescr result]
+    :   left=multiplicativeExpression { if( buildDescr  ) { $result = $left.result; } }
+        ( (PLUS|MINUS)=> (PLUS | MINUS) multiplicativeExpression )*
+    ;
+
+multiplicativeExpression returns [BaseDescr result]
+    :   left=unaryExpression { if( buildDescr  ) { $result = $left.result; } }
+      ( ( STAR | DIV | MOD ) unaryExpression )*
+    ;
+
+unaryExpression returns [BaseDescr result]
+    :   PLUS ue=unaryExpression
+        { if( buildDescr ) {
+            $result = $ue.result;
+            if( $result instanceof AtomicExprDescr ) {
+                ((AtomicExprDescr)$result).setExpression( "+" + ((AtomicExprDescr)$result).getExpression() );
+            }
+        } }
+    |	MINUS ue=unaryExpression
+        { if( buildDescr ) {
+            $result = $ue.result;
+            if( $result instanceof AtomicExprDescr ) {
+                ((AtomicExprDescr)$result).setExpression( "-" + ((AtomicExprDescr)$result).getExpression() );
+            }
+        } }
+    |   INCR primary
+    |   DECR primary
+    |   left=unaryExpressionNotPlusMinus { if( buildDescr ) { $result = $left.result; } }
+    ;
+
+unaryExpressionNotPlusMinus returns [BaseDescr result]
+@init { boolean isLeft = false; BindingDescr bind = null;}
+    :   TILDE unaryExpression
+    | 	NEGATION ue=unaryExpression
+        {
+            if( buildDescr && ue != null ) {
+                $result = ue.negate();
+            }
+        }
+    |   (castExpression)=>castExpression
+    |   (backReferenceExpression)=>backReferenceExpression
+    |   { isLeft = helper.getLeftMostExpr() == null;}
+        ( ({inMap == 0 && ternOp == 0 && input.LA(2) == DRL6Lexer.COLON}? (var=ID COLON
+                { hasBindings = true; helper.emit($var, DroolsEditorType.IDENTIFIER_VARIABLE); helper.emit($COLON, DroolsEditorType.SYMBOL); if( buildDescr ) { bind = new BindingDescr($var.text, null, false); helper.setStart( bind, $var ); } } ))
+        | ({inMap == 0 && ternOp == 0 && input.LA(2) == DRL6Lexer.UNIFY}? (var=ID UNIFY 
+                { hasBindings = true; helper.emit($var, DroolsEditorType.IDENTIFIER_VARIABLE); helper.emit($UNIFY, DroolsEditorType.SYMBOL); if( buildDescr ) { bind = new BindingDescr($var.text, null, true); helper.setStart( bind, $var ); } } ))
+        )?
+
+        ( (xpathSeparator ID)=>left2=xpathPrimary { if( buildDescr ) { $result = $left2.result; } }
+          | left1=primary { if( buildDescr ) { $result = $left1.result; } }
+        )
+
+        ((selector)=>selector)*
+        {
+            if( buildDescr ) {
+                String expr = $unaryExpressionNotPlusMinus.text;
+                if( isLeft ) {
+                    helper.setLeftMostExpr( expr );
+                }
+                if( bind != null ) {
+                    if( bind.isUnification() ) {
+                        expr = expr.substring( expr.indexOf( ":=" ) + 2 ).trim();
+                    } else {
+                        expr = expr.substring( expr.indexOf( ":" ) + 1 ).trim();
+                    }
+                    bind.setExpressionAndBindingField( expr );
+                    helper.setEnd( bind );
+                    $result = bind;
+                }
+            }
+        }
+        ((INCR|DECR)=> (INCR|DECR))?
+    ;
+
+castExpression
+    :  (LEFT_PAREN primitiveType) => LEFT_PAREN primitiveType RIGHT_PAREN expr=unaryExpression
+    |  (LEFT_PAREN type) => LEFT_PAREN type RIGHT_PAREN unaryExpressionNotPlusMinus
+    ;
+
+backReferenceExpression
+    :  (DOT DOT DIV) => (DOT DOT DIV)+ unaryExpressionNotPlusMinus
+    ;
+
+primitiveType
+    :   boolean_key
+    |	char_key
+    |	byte_key
+    |	short_key
+    |	int_key
+    |	long_key
+    |	float_key
+    |	double_key
+    ;
+
+xpathSeparator
+    :   DIV
+    |	QUESTION_DIV
+    ;
+
+xpathPrimary returns [BaseDescr result]
+    : xpathChunk ({notStartWithNewline()}? xpathChunk)*
+    ;
+
+xpathChunk returns [BaseDescr result]
+    : (xpathSeparator ID)=> xpathSeparator ID (DOT ID)* (HASH ID)? (LEFT_SQUARE xpathExpressionList RIGHT_SQUARE)?
+    ;
+
+xpathExpressionList returns [java.util.List<String> exprs]
+@init { $exprs = new java.util.ArrayList<String>();}
+  :   f=expression { $exprs.add( $f.text ); }
+      (COMMA s=expression { $exprs.add( $s.text ); })*
+  ;
+
+primary returns [BaseDescr result]
+    :	(LEFT_PAREN)=> expr=parExpression {  if( buildDescr  ) { $result = $expr.result; }  }
+    |   (nonWildcardTypeArguments)=> nonWildcardTypeArguments (explicitGenericInvocationSuffix | this_key arguments)
+    |   (literal)=> literal { if( buildDescr  ) { $result = new AtomicExprDescr( $literal.text, true ); }  }
+    //|   this_key ({!helper.validateSpecialID(2)}?=> DOT ID)* ({helper.validateIdentifierSufix()}?=> identifierSuffix)?
+    |   (super_key)=> super_key superSuffix
+    |   (new_key)=> new_key creator
+    |   (primitiveType)=> primitiveType (LEFT_SQUARE RIGHT_SQUARE)* DOT class_key
+    //|   void_key DOT class_key
+    |   (inlineMapExpression)=> inlineMapExpression
+    |   (inlineListExpression)=> inlineListExpression
+    |   (ID)=>i1=ID { helper.emit($i1, DroolsEditorType.IDENTIFIER); }
+        (
+            ( (DOT ID)=>d=DOT i2=ID { helper.emit($d, DroolsEditorType.SYMBOL); helper.emit($i2, DroolsEditorType.IDENTIFIER); } )
+            |
+            ( ((DOT|NULL_SAFE_DOT) LEFT_PAREN)=>d=(DOT|NULL_SAFE_DOT) LEFT_PAREN { helper.emit($d, DroolsEditorType.SYMBOL); helper.emit($LEFT_PAREN, DroolsEditorType.SYMBOL); }
+                                    expression (COMMA { helper.emit($COMMA, DroolsEditorType.SYMBOL); } expression)*
+                                    RIGHT_PAREN { helper.emit($RIGHT_PAREN, DroolsEditorType.SYMBOL); }
+            )
+            |
+            ( (HASH ID)=>h=HASH i2=ID { helper.emit($h, DroolsEditorType.SYMBOL); helper.emit($i2, DroolsEditorType.IDENTIFIER); } )
+            |
+            ( (NULL_SAFE_DOT ID)=>n=NULL_SAFE_DOT i2=ID { helper.emit($n, DroolsEditorType.SYMBOL); helper.emit($i2, DroolsEditorType.IDENTIFIER); } )
+        )* ((identifierSuffix)=>identifierSuffix)?
+    ;
+
+inlineListExpression
+    :   LEFT_SQUARE expressionList? RIGHT_SQUARE
+    ;
+
+inlineMapExpression
+@init{ inMap++; }
+    :	LEFT_SQUARE mapExpressionList RIGHT_SQUARE
+    ;
+finally { inMap--; }
+
+mapExpressionList
+    :	mapEntry (COMMA mapEntry)*
+    ;
+
+mapEntry
+    :	expression COLON expression
+    ;
+
+parExpression returns [BaseDescr result]
+    :	LEFT_PAREN expr=expression RIGHT_PAREN
+        {  if( buildDescr  ) {
+               $result = $expr.result;
+               if( $result instanceof AtomicExprDescr ) {
+                   ((AtomicExprDescr)$result).setExpression("(" +((AtomicExprDescr)$result).getExpression() + ")" );
+               }
+           }
+        }
+    ;
+
+identifierSuffix
+    :	(LEFT_SQUARE RIGHT_SQUARE)=>(LEFT_SQUARE { helper.emit($LEFT_SQUARE, DroolsEditorType.SYMBOL); }
+                                     RIGHT_SQUARE { helper.emit($RIGHT_SQUARE, DroolsEditorType.SYMBOL); } )+
+                                     DOT { helper.emit($DOT, DroolsEditorType.SYMBOL); } class_key
+    |	((LEFT_SQUARE) => LEFT_SQUARE { helper.emit($LEFT_SQUARE, DroolsEditorType.SYMBOL); }
+                          expression
+                          RIGHT_SQUARE { helper.emit($RIGHT_SQUARE, DroolsEditorType.SYMBOL); } )+ // can also be matched by selector, but do here
+    |   arguments
+//    |   DOT class_key
+//    |   DOT explicitGenericInvocation
+//    |   DOT this_key
+//    |   DOT super_key arguments
+//    |   DOT new_key (nonWildcardTypeArguments)? innerCreator
+    ;
+
+creator
+    :	nonWildcardTypeArguments? createdName
+        (arrayCreatorRest | classCreatorRest)
+    ;
+
+createdName
+    :	ID typeArguments?
+        ( DOT ID typeArguments?)*
+        |	primitiveType
+    ;
+
+innerCreator
+    :	{!(helper.validateIdentifierKey(DroolsSoftKeywords.INSTANCEOF))}?=> ID classCreatorRest
+    ;
+
+arrayCreatorRest
+    :   LEFT_SQUARE
+    (   RIGHT_SQUARE (LEFT_SQUARE RIGHT_SQUARE)* arrayInitializer
+        |   expression RIGHT_SQUARE ({!helper.validateLT(2,"]")}?=>LEFT_SQUARE expression RIGHT_SQUARE)* ((LEFT_SQUARE RIGHT_SQUARE)=> LEFT_SQUARE RIGHT_SQUARE)*
+        )
+    ;
+
+variableInitializer
+    :	arrayInitializer
+        |   expression
+    ;
+
+arrayInitializer
+    :	LEFT_CURLY (variableInitializer (COMMA variableInitializer)* (COMMA)? )? RIGHT_CURLY
+    ;
+
+classCreatorRest
+    :	arguments //classBody?		//sotty:  restored classBody to allow for inline, anonymous classes
+    ;
+
+explicitGenericInvocation
+    :	nonWildcardTypeArguments arguments
+    ;
+
+nonWildcardTypeArguments
+    :	LESS typeList GREATER
+    ;
+
+explicitGenericInvocationSuffix
+    :	super_key superSuffix
+    |   	ID arguments
+    ;
+
+selector
+    :   (DOT super_key)=>DOT { helper.emit($DOT, DroolsEditorType.SYMBOL); } super_key superSuffix
+    |   (DOT new_key)=>DOT { helper.emit($DOT, DroolsEditorType.SYMBOL); } new_key (nonWildcardTypeArguments)? innerCreator
+    |   (DOT ID)=>DOT { helper.emit($DOT, DroolsEditorType.SYMBOL); }
+                  ID { helper.emit($ID, DroolsEditorType.IDENTIFIER); }
+                  ((LEFT_PAREN) => arguments)?
+    |   (NULL_SAFE_DOT ID)=>NULL_SAFE_DOT { helper.emit($NULL_SAFE_DOT, DroolsEditorType.SYMBOL); }
+                  ID { helper.emit($ID, DroolsEditorType.IDENTIFIER); }
+                  ((LEFT_PAREN) => arguments)?
+    //|   DOT this_key
+    |   (LEFT_SQUARE)=>LEFT_SQUARE { helper.emit($LEFT_SQUARE, DroolsEditorType.SYMBOL); }
+                       expression
+                       RIGHT_SQUARE { helper.emit($RIGHT_SQUARE, DroolsEditorType.SYMBOL); }
+    ;
+
+superSuffix
+    :	arguments
+    |   	DOT ID ((LEFT_PAREN) => arguments)?
+    ;
+
+squareArguments returns [java.util.List<String> args]
+    : LEFT_SQUARE (el=expressionList { $args = $el.exprs; })? RIGHT_SQUARE
+    ;
+
+arguments
+    :	LEFT_PAREN { helper.emit($LEFT_PAREN, DroolsEditorType.SYMBOL); }
+        expressionList?
+        RIGHT_PAREN { helper.emit($RIGHT_PAREN, DroolsEditorType.SYMBOL); }
+    ;
+
+expressionList returns [java.util.List<String> exprs]
+@init { $exprs = new java.util.ArrayList<String>();}
+  :   f=expression { $exprs.add( $f.text ); }
+      (COMMA s=expression { $exprs.add( $s.text ); })*
+  ;
+
+assignmentOperator
+    :   EQUALS_ASSIGN
+  |   PLUS_ASSIGN
+  |   MINUS_ASSIGN
+  |   MULT_ASSIGN
+  |   DIV_ASSIGN
+  |   AND_ASSIGN
+  |   OR_ASSIGN
+  |   XOR_ASSIGN
+  |   MOD_ASSIGN
+  |   LESS LESS EQUALS_ASSIGN
+  |   (GREATER GREATER GREATER)=> GREATER GREATER GREATER EQUALS_ASSIGN
+  |   (GREATER GREATER)=> GREATER GREATER EQUALS_ASSIGN
+    ;
+
+// --------------------------------------------------------
+//                      KEYWORDS
+// --------------------------------------------------------
+extends_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.EXTENDS))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+super_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.SUPER))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+instanceof_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.INSTANCEOF))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+boolean_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.BOOLEAN))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+char_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.CHAR))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+byte_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.BYTE))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+short_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.SHORT))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+int_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.INT))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+float_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.FLOAT))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+long_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.LONG))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+double_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.DOUBLE))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+void_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.VOID))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+this_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.THIS))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+class_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.CLASS))}?=> id=ID  { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+new_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.NEW))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+not_key
+    :      {(helper.validateIdentifierKey(DroolsSoftKeywords.NOT))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+    ;
+
+in_key
+  :      {(helper.validateIdentifierKey(DroolsSoftKeywords.IN))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+  ;
+
+operator_key
+  :      {(helper.isPluggableEvaluator(false))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+  ;
+
+neg_operator_key
+  :      {(helper.isPluggableEvaluator(true))}?=> id=ID { helper.emit($ID, DroolsEditorType.KEYWORD); }
+  ;
diff --git a/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLExpressions.java b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLExpressions.java
new file mode 100644
index 00000000000..ba811347b29
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DRLExpressions.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.drools.parser;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.antlr.runtime.Parser;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.RecognizerSharedState;
+import org.antlr.runtime.TokenStream;
+import org.drools.drl.ast.descr.BaseDescr;
+import org.drools.drl.parser.DroolsParserException;
+
+public abstract class DRLExpressions extends Parser {
+    public DRLExpressions(TokenStream input, RecognizerSharedState state) {
+        super(input, state);
+    }
+
+    public abstract void setBuildDescr( boolean build );
+    public abstract boolean isBuildDescr();
+
+    public abstract void setLeftMostExpr( String value );
+    public abstract String getLeftMostExpr();
+
+    public abstract void setHasBindings( boolean value );
+    public abstract boolean hasBindings();
+
+    public abstract BaseDescr conditionalOrExpression() throws RecognitionException;
+
+    public abstract ParserHelper getHelper();
+    public abstract boolean hasErrors();
+    public abstract List<DroolsParserException> getErrors();
+    public abstract List<String> getErrorMessages();
+    public abstract void enableEditorInterface();
+    public abstract void disableEditorInterface();
+    public abstract LinkedList<DroolsSentence> getEditorInterface();
+}
diff --git a/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DrlExprParser.java b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DrlExprParser.java
new file mode 100644
index 00000000000..7d624224cb5
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DrlExprParser.java
@@ -0,0 +1,88 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.drools.parser;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.RecognizerSharedState;
+import org.drools.drl.ast.descr.BaseDescr;
+import org.drools.drl.ast.descr.ConstraintConnectiveDescr;
+import org.drools.drl.parser.lang.ParserHelper;
+import org.kie.internal.builder.conf.LanguageLevelOption;
+
+/**
+ * This is a helper class that provides helper methods to parse expressions
+ * using both the DRLExpressions parser and the DRLExprTree parser.
+ */
+public class DrlExprParser {
+
+    private ParserHelper helper = null;
+
+    private final LanguageLevelOption languageLevel;
+
+    public DrlExprParser(LanguageLevelOption languageLevel) {
+        this.languageLevel = languageLevel;
+    }
+
+    /** Parse an expression from text */
+    public ConstraintConnectiveDescr parse( final String text ) {
+        ConstraintConnectiveDescr constraint = null;
+        try {
+            DRLLexer lexer = DRLFactory.getDRLLexer(new ANTLRStringStream(text), languageLevel);
+            CommonTokenStream input = new CommonTokenStream( lexer );
+            RecognizerSharedState state = new RecognizerSharedState();
+            helper = new ParserHelper( input, state, languageLevel );
+            DRLExpressions parser = DRLFactory.getDRLExpressions(input, state, helper, languageLevel);
+            parser.setBuildDescr( true );
+            parser.setLeftMostExpr( null ); // setting initial value just in case
+            BaseDescr expr = parser.conditionalOrExpression();
+            if ( expr != null && !parser.hasErrors() ) {
+                constraint = ConstraintConnectiveDescr.newAnd();
+                constraint.addOrMerge( expr );
+            }
+        } catch ( RecognitionException e ) {
+            helper.reportError( e );
+        }
+        return constraint;
+    }
+
+    public String getLeftMostExpr() {
+        return helper != null ? helper.getLeftMostExpr() : null;
+    }
+
+    /**
+     * @return true if there were parser errors.
+     */
+    public boolean hasErrors() {
+        return helper != null && helper.hasErrors();
+    }
+
+    /**
+     * @return a list of errors found while parsing.
+     */
+    @SuppressWarnings("unchecked")
+    public List<DroolsParserException> getErrors() {
+        return helper != null ? helper.getErrors() : Collections.EMPTY_LIST;
+    }
+
+}
diff --git a/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DroolsParserExceptionFactory.java b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DroolsParserExceptionFactory.java
new file mode 100644
index 00000000000..f94eab73ccc
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/DroolsParserExceptionFactory.java
@@ -0,0 +1,380 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.drools.parser;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.antlr.runtime.BitSet;
+import org.antlr.runtime.EarlyExitException;
+import org.antlr.runtime.FailedPredicateException;
+import org.antlr.runtime.MismatchedNotSetException;
+import org.antlr.runtime.MismatchedSetException;
+import org.antlr.runtime.MismatchedTokenException;
+import org.antlr.runtime.MismatchedTreeNodeException;
+import org.antlr.runtime.NoViableAltException;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.drools.drl.parser.DRLFactory;
+import org.drools.drl.parser.DroolsParserException;
+import org.kie.internal.builder.conf.LanguageLevelOption;
+
+/**
+ * Helper class that generates DroolsParserException with user friendly error
+ * messages.
+ *
+ * @see DroolsParserException
+ */
+public class DroolsParserExceptionFactory {
+    public final static String                        MISMATCHED_TOKEN_MESSAGE_COMPLETE       = "Line %1$d:%2$d mismatched input '%3$s' expecting '%4$s'%5$s";
+    public final static String                        MISMATCHED_TOKEN_MESSAGE_PART           = "Line %1$d:%2$d mismatched input '%3$s'%4$s";
+    public final static String                        MISMATCHED_TREE_NODE_MESSAGE_COMPLETE   = "Line %1$d:%2$d mismatched tree node '%3$s' expecting '%4$s'%5$s";
+    public final static String                        MISMATCHED_TREE_NODE_MESSAGE_PART       = "Line %1$d:%2$d mismatched tree node '%3$s'%4$s";
+    public final static String                        NO_VIABLE_ALT_MESSAGE                   = "Line %1$d:%2$d no viable alternative at input '%3$s'%4$s";
+    public final static String                        EARLY_EXIT_MESSAGE                      = "Line %1$d:%2$d required (...)+ loop did not match anything at input '%3$s'%4$s";
+    public final static String                        MISMATCHED_SET_MESSAGE                  = "Line %1$d:%2$d mismatched input '%3$s' expecting one of the following tokens: '%4$s'%5$s.";
+    public final static String                        MISMATCHED_NOT_SET_MESSAGE              = "Line %1$d:%2$d mismatched input '%3$s' not expecting any of the following tokens: '%4$s'%5$s";
+    public final static String                        FAILED_PREDICATE_MESSAGE                = "Line %1$d:%2$d rule '%3$s' failed predicate: {%4$s}?%5$s";
+    public final static String                        TRAILING_SEMI_COLON_NOT_ALLOWED_MESSAGE = "Line %1$d:%2$d trailing semi-colon not allowed%3$s";
+    public final static String                        PARSER_LOCATION_MESSAGE_COMPLETE        = " in %1$s %2$s";
+    public final static String                        PARSER_LOCATION_MESSAGE_PART            = " in %1$s";
+    public final static String                        UNEXPECTED_EXCEPTION                    = "Line %1$d:%2$d unexpected exception at input '%3$s'. Exception: %4$s. Stack trace:\n %5$s";
+
+    private final Collection<Map<DroolsParaphraseTypes, String>> paraphrases;
+
+    // TODO: need to deal with this array
+    private String[]                                  tokenNames                              = null;
+
+    private final LanguageLevelOption languageLevel;
+
+    /**
+     * DroolsParserErrorMessages constructor.
+     *
+     * @param tokenNames
+     *            tokenNames generated by ANTLR
+     * @param paraphrases
+     *            paraphrases parser structure
+     */
+    public DroolsParserExceptionFactory(Collection<Map<DroolsParaphraseTypes, String>> paraphrases,
+            LanguageLevelOption languageLevel) {
+        this.paraphrases = paraphrases;
+        this.languageLevel = languageLevel;
+    }
+
+    /**
+     * This method creates a DroolsParserException for trailing semicolon
+     * exception, full of information.
+     *
+     * @param line
+     *            line number
+     * @param column
+     *            column position
+     * @param offset
+     *            char offset
+     * @return DroolsParserException filled.
+     */
+    public DroolsParserException createTrailingSemicolonException( int line,
+                                                                   int column,
+                                                                   int offset ) {
+        String message = String
+                .format(
+                         TRAILING_SEMI_COLON_NOT_ALLOWED_MESSAGE,
+                         line,
+                         column,
+                         formatParserLocation() );
+
+        return new DroolsParserException( "ERR 104",
+                                          message,
+                                          line,
+                                          column,
+                                          offset,
+                                          null );
+    }
+
+    /**
+     * This method creates a DroolsParserException full of information.
+     *
+     * @param e
+     *            original exception
+     * @return DroolsParserException filled.
+     */
+    public DroolsParserException createDroolsException( RecognitionException e ) {
+        List<String> codeAndMessage = createErrorMessage( e );
+        return new DroolsParserException( codeAndMessage.get( 1 ),
+                                          codeAndMessage
+                                                  .get( 0 ),
+                                          e.line,
+                                          e.charPositionInLine,
+                                          e.index,
+                                          e );
+    }
+
+    /**
+     * This will take a RecognitionException, and create a sensible error
+     * message out of it
+     */
+    private List<String> createErrorMessage( RecognitionException e ) {
+        List<String> codeAndMessage = new ArrayList<>( 2 );
+        String message;
+        if ( e instanceof MismatchedTokenException ) {
+            MismatchedTokenException mte = (MismatchedTokenException) e;
+            String expecting = mte instanceof DroolsMismatchedTokenException ? ((DroolsMismatchedTokenException)mte).getTokenText() : getBetterToken( mte.expecting );
+            if ( tokenNames != null && mte.expecting >= 0 && mte.expecting < tokenNames.length ) {
+                message = String
+                        .format(
+                                 MISMATCHED_TOKEN_MESSAGE_COMPLETE,
+                                 e.line,
+                                 e.charPositionInLine,
+                                 getBetterToken( e.token ),
+                                 expecting,
+                                 formatParserLocation() );
+                codeAndMessage.add( message );
+                codeAndMessage.add( "ERR 102" );
+            } else {
+                message = String
+                        .format(
+                                 MISMATCHED_TOKEN_MESSAGE_PART,
+                                 e.line,
+                                 e.charPositionInLine,
+                                 getBetterToken( e.token ),
+                                 formatParserLocation() );
+                codeAndMessage.add( message );
+                codeAndMessage.add( "ERR 102" );
+            }
+        } else if ( e instanceof MismatchedTreeNodeException ) {
+            MismatchedTreeNodeException mtne = (MismatchedTreeNodeException) e;
+            if ( mtne.expecting >= 0 && mtne.expecting < tokenNames.length ) {
+                message = String
+                        .format(
+                                 MISMATCHED_TREE_NODE_MESSAGE_COMPLETE,
+                                 e.line,
+                                 e.charPositionInLine,
+                                 getBetterToken( e.token ),
+                                 getBetterToken( mtne.expecting ),
+                                 formatParserLocation() );
+                codeAndMessage.add( message );
+                codeAndMessage.add( "ERR 106" );
+            } else {
+                message = String
+                        .format(
+                                 MISMATCHED_TREE_NODE_MESSAGE_PART,
+                                 e.line,
+                                 e.charPositionInLine,
+                                 getBetterToken( e.token ),
+                                 formatParserLocation() );
+                codeAndMessage.add( message );
+                codeAndMessage.add( "ERR 106" );
+            }
+        } else if ( e instanceof NoViableAltException ) {
+            // NoViableAltException nvae = (NoViableAltException) e;
+            message = String.format(
+                                     NO_VIABLE_ALT_MESSAGE,
+                                     e.line,
+                                     e.charPositionInLine,
+                                     getBetterToken( e.token ),
+                                     formatParserLocation() );
+            codeAndMessage.add( message );
+            codeAndMessage.add( "ERR 101" );
+        } else if ( e instanceof EarlyExitException ) {
+            // EarlyExitException eee = (EarlyExitException) e;
+            message = String.format(
+                                     EARLY_EXIT_MESSAGE,
+                                     e.line,
+                                     e.charPositionInLine,
+                                     getBetterToken( e.token ),
+                                     formatParserLocation() );
+            codeAndMessage.add( message );
+            codeAndMessage.add( "ERR 105" );
+        } else if ( e instanceof MismatchedSetException ) {
+            MismatchedSetException mse = (MismatchedSetException) e;
+            String expected = expectedTokensAsString( mse.expecting );
+            message = String.format(
+                                     MISMATCHED_SET_MESSAGE,
+                                     e.line,
+                                     e.charPositionInLine,
+                                     getBetterToken( e.token ),
+                                     expected,
+                                     formatParserLocation() );
+            codeAndMessage.add( message );
+            codeAndMessage.add( "ERR 107" );
+        } else if ( e instanceof DroolsMismatchedSetException ) {
+            DroolsMismatchedSetException mse = (DroolsMismatchedSetException) e;
+            String expected = Arrays.asList( mse.getTokenText() ).toString();
+            message = String.format(
+                                     MISMATCHED_SET_MESSAGE,
+                                     e.line,
+                                     e.charPositionInLine,
+                                     getBetterToken( e.token ),
+                                     expected,
+                                     formatParserLocation() );
+            codeAndMessage.add( message );
+            codeAndMessage.add( "ERR 107" );
+        } else if ( e instanceof MismatchedNotSetException ) {
+            MismatchedNotSetException mse = (MismatchedNotSetException) e;
+            String expected = expectedTokensAsString( mse.expecting );
+            message = String.format(
+                                     MISMATCHED_NOT_SET_MESSAGE,
+                                     e.line,
+                                     e.charPositionInLine,
+                                     getBetterToken( e.token ),
+                                     expected,
+                                     formatParserLocation() );
+            codeAndMessage.add( message );
+            codeAndMessage.add( "ERR 108" );
+        } else if ( e instanceof FailedPredicateException ) {
+            FailedPredicateException fpe = (FailedPredicateException) e;
+            message = String.format(
+                                     FAILED_PREDICATE_MESSAGE,
+                                     e.line,
+                                     e.charPositionInLine,
+                                     fpe.ruleName,
+                                     fpe.predicateText,
+                                     formatParserLocation() );
+            codeAndMessage.add( message );
+            codeAndMessage.add( "ERR 103" );
+        }
+        if ( codeAndMessage.get( 0 ).length() == 0 ) {
+            codeAndMessage.add( "?????" );
+        }
+        return codeAndMessage;
+    }
+
+    public DroolsParserException createDroolsException( Exception e,
+                                                        Token token ) {
+        StringWriter sw = new StringWriter();
+        e.printStackTrace( new PrintWriter(sw) );
+        return new DroolsParserException( String.format(
+                                                         DroolsParserExceptionFactory.UNEXPECTED_EXCEPTION,
+                                                         token.getLine(),
+                                                         token.getCharPositionInLine(),
+                                                         getBetterToken( token ),
+                                                         e.toString(),
+                                                         sw.toString() ),
+                                          e );
+
+    }
+
+    private String expectedTokensAsString( BitSet set ) {
+        StringBuilder buf = new StringBuilder();
+        buf.append( "{ " );
+        int i = 0;
+        for ( int token : set.toArray() ) {
+            if ( i > 0 ) buf.append( ", " );
+            buf.append( getBetterToken( token ) );
+            i++;
+        }
+        buf.append( " }" );
+        return buf.toString();
+    }
+
+    /**
+     * This will take Paraphrases stack, and create a sensible location
+     */
+    private String formatParserLocation() {
+        StringBuilder sb = new StringBuilder();
+        if ( paraphrases != null ) {
+            for ( Map<DroolsParaphraseTypes, String> map : paraphrases ) {
+                for ( Entry<DroolsParaphraseTypes, String> activeEntry : map.entrySet() ) {
+                    if ( activeEntry.getValue().length() == 0 ) {
+                        String kStr = getLocationName( activeEntry.getKey() );
+                        if( kStr.length() > 0 ){
+                            sb.append( String.format( PARSER_LOCATION_MESSAGE_PART, kStr ) );
+                        }
+                    } else {
+                        sb.append( String.format( PARSER_LOCATION_MESSAGE_COMPLETE,
+                                                  getLocationName( activeEntry.getKey() ),
+                                                  activeEntry.getValue() ) );
+                    }
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Returns a string based on Paraphrase Type
+     *
+     * @param type
+     *            Paraphrase Type
+     * @return a string representing the
+     */
+    private String getLocationName( DroolsParaphraseTypes type ) {
+        switch ( type ) {
+            case PACKAGE :
+                return "package";
+            case IMPORT :
+                return "import";
+            case FUNCTION_IMPORT :
+                return "function import";
+            case ACCUMULATE_IMPORT :
+                return "accumulate import";
+            case GLOBAL :
+                return "global";
+            case FUNCTION :
+                return "function";
+            case QUERY :
+                return "query";
+            case TEMPLATE :
+                return "template";
+            case RULE :
+                return "rule";
+            case RULE_ATTRIBUTE :
+                return "rule attribute";
+            case PATTERN :
+                return "pattern";
+            case EVAL :
+                return "eval";
+            default :
+                return "";
+        }
+    }
+
+    /**
+     * Helper method that creates a user friendly token definition
+     *
+     * @param token
+     *            token
+     * @return user friendly token definition
+     */
+    private String getBetterToken( Token token ) {
+        if ( token == null ) {
+            return "";
+        }
+        return DRLFactory.getBetterToken(token.getType(), token.getText(), languageLevel);
+    }
+
+    /**
+     * Helper method that creates a user friendly token definition
+     *
+     * @param tokenType
+     *            token type
+     * @return user friendly token definition
+     */
+    private String getBetterToken( int tokenType ) {
+        return DRLFactory.getBetterToken( tokenType, null, languageLevel );
+    }
+
+
+}
diff --git a/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/ParserHelper.java b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/ParserHelper.java
new file mode 100644
index 00000000000..94e5e2f76ce
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/src/main/java/org/drools/parser/ParserHelper.java
@@ -0,0 +1,672 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+/*
+ * 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.
+ */
+package org.drools.parser;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.RecognizerSharedState;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.drools.drl.ast.descr.AttributeDescr;
+import org.drools.drl.ast.descr.BaseDescr;
+import org.drools.drl.ast.dsl.AbstractClassTypeDeclarationBuilder;
+import org.drools.drl.ast.dsl.AccumulateDescrBuilder;
+import org.drools.drl.ast.dsl.AccumulateImportDescrBuilder;
+import org.drools.drl.ast.dsl.AttributeDescrBuilder;
+import org.drools.drl.ast.dsl.AttributeSupportBuilder;
+import org.drools.drl.ast.dsl.BehaviorDescrBuilder;
+import org.drools.drl.ast.dsl.CEDescrBuilder;
+import org.drools.drl.ast.dsl.CollectDescrBuilder;
+import org.drools.drl.ast.dsl.ConditionalBranchDescrBuilder;
+import org.drools.drl.ast.dsl.DeclareDescrBuilder;
+import org.drools.drl.ast.dsl.DescrBuilder;
+import org.drools.drl.ast.dsl.DescrFactory;
+import org.drools.drl.ast.dsl.EntryPointDeclarationDescrBuilder;
+import org.drools.drl.ast.dsl.EnumDeclarationDescrBuilder;
+import org.drools.drl.ast.dsl.EnumLiteralDescrBuilder;
+import org.drools.drl.ast.dsl.EvalDescrBuilder;
+import org.drools.drl.ast.dsl.FieldDescrBuilder;
+import org.drools.drl.ast.dsl.ForallDescrBuilder;
+import org.drools.drl.ast.dsl.FunctionDescrBuilder;
+import org.drools.drl.ast.dsl.GlobalDescrBuilder;
+import org.drools.drl.ast.dsl.GroupByDescrBuilder;
+import org.drools.drl.ast.dsl.ImportDescrBuilder;
+import org.drools.drl.ast.dsl.NamedConsequenceDescrBuilder;
+import org.drools.drl.ast.dsl.PackageDescrBuilder;
+import org.drools.drl.ast.dsl.PatternContainerDescrBuilder;
+import org.drools.drl.ast.dsl.PatternDescrBuilder;
+import org.drools.drl.ast.dsl.QueryDescrBuilder;
+import org.drools.drl.ast.dsl.RuleDescrBuilder;
+import org.drools.drl.ast.dsl.TypeDeclarationDescrBuilder;
+import org.drools.drl.ast.dsl.UnitDescrBuilder;
+import org.drools.drl.ast.dsl.WindowDeclarationDescrBuilder;
+import org.drools.drl.parser.DroolsParserException;
+import org.kie.internal.builder.conf.LanguageLevelOption;
+
+/**
+ * This is a class to hold all the helper functions/methods used
+ * by the DRL parser
+ */
+public class ParserHelper {
+    public final String[]                             statementKeywords        = new String[]{
+                                                                               DroolsSoftKeywords.PACKAGE,
+                                                                               DroolsSoftKeywords.UNIT,
+                                                                               DroolsSoftKeywords.IMPORT,
+                                                                               DroolsSoftKeywords.GLOBAL,
+                                                                               DroolsSoftKeywords.DECLARE,
+                                                                               DroolsSoftKeywords.FUNCTION,
+                                                                               DroolsSoftKeywords.RULE,
+                                                                               DroolsSoftKeywords.QUERY
+                                                                               };
+
+    public List<DroolsParserException>                errors                   = new ArrayList<>();
+    public LinkedList<DroolsSentence>                 editorInterface          = null;
+    public boolean                                    isEditorInterfaceEnabled = false;
+    private Deque<Map<DroolsParaphraseTypes, String>> paraphrases         = new ArrayDeque<>();
+
+    // parameters from parser
+    private DroolsParserExceptionFactory              errorMessageFactory      = null;
+    private TokenStream                               input                    = null;
+    private RecognizerSharedState                     state                    = null;
+
+    private String                                    leftMostExpr             = null;
+
+    // helper attribute
+    private boolean                                   hasOperator              = false;
+
+    private final LanguageLevelOption                 languageLevel;
+
+    public ParserHelper(TokenStream input,
+                        RecognizerSharedState state,
+                        LanguageLevelOption languageLevel) {
+        this.errorMessageFactory = new DroolsParserExceptionFactory( paraphrases, languageLevel );
+        this.input = input;
+        this.state = state;
+        this.languageLevel = languageLevel;
+    }
+
+    public LinkedList<DroolsSentence> getEditorInterface() {
+        return editorInterface;
+    }
+
+    public void setLeftMostExpr( String value ) {
+        this.leftMostExpr = value;
+    }
+
+    public String getLeftMostExpr() {
+        return this.leftMostExpr;
+    }
+
+    public void enableEditorInterface() {
+        isEditorInterfaceEnabled = true;
+    }
+
+    public void disableEditorInterface() {
+        isEditorInterfaceEnabled = false;
+    }
+
+    public void setHasOperator( boolean hasOperator ) {
+        this.hasOperator = hasOperator;
+    }
+
+    public boolean getHasOperator() {
+        return hasOperator;
+    }
+
+    public void beginSentence( DroolsSentenceType sentenceType ) {
+        if ( isEditorInterfaceEnabled ) {
+            if ( null == editorInterface ) {
+                editorInterface = new LinkedList<>();
+            }
+            if (editorInterface.isEmpty()){
+                DroolsSentence sentence = new DroolsSentence();
+                sentence.setType( sentenceType );
+                editorInterface.add( sentence );
+            }
+        }
+    }
+
+    public DroolsSentence getActiveSentence() {
+        return editorInterface.getLast();
+    }
+
+    public void emit( List< ? > tokens,
+                      DroolsEditorType editorType ) {
+        if ( isEditorInterfaceEnabled && tokens != null ) {
+            for ( Object activeObject : tokens ) {
+                emit( (Token) activeObject,
+                      editorType );
+            }
+        }
+    }
+
+    public void emit( Token token,
+                      DroolsEditorType editorType ) {
+        if ( isEditorInterfaceEnabled && token != null && editorType != null ) {
+            ((DroolsToken) token).setEditorType( editorType );
+            getActiveSentence().addContent( (DroolsToken) token );
+        }
+    }
+
+    public void emit( int activeContext ) {
+        if ( isEditorInterfaceEnabled ) {
+            getActiveSentence().addContent( activeContext );
+        }
+    }
+
+    public DroolsToken getLastTokenOnList( LinkedList< ? > list ) {
+        DroolsToken lastToken = null;
+        for ( Object object : list ) {
+            if ( object instanceof DroolsToken ) {
+                lastToken = (DroolsToken) object;
+            }
+        }
+        return lastToken;
+    }
+
+    public String retrieveLT( int LTNumber ) {
+        if ( null == input ) return null;
+        if ( null == input.LT( LTNumber ) ) return null;
+        if ( null == input.LT( LTNumber ).getText() ) return null;
+
+        return input.LT( LTNumber ).getText();
+    }
+
+    public boolean validateLT( int LTNumber,
+                               String text ) {
+        String text2Validate = retrieveLT( LTNumber );
+        return validateText( text, text2Validate );
+    }
+
+    private boolean validateText( String text, String text2Validate ) {
+        return text2Validate != null && text2Validate.equals( text );
+    }
+
+    public boolean isPluggableEvaluator( int offset,
+                                         boolean negated ) {
+        String text2Validate = retrieveLT( offset );
+        return text2Validate != null && DroolsSoftKeywords.isOperator(text2Validate, negated);
+    }
+
+    public boolean isPluggableEvaluator( boolean negated ) {
+        return isPluggableEvaluator( 1,
+                                     negated );
+    }
+
+    public boolean validateIdentifierKey( String text ) {
+        return validateLT( 1,
+                           text );
+    }
+
+    public boolean validateCEKeyword( int index ) {
+        String text2Validate = retrieveLT( index );
+        return validateText( text2Validate,
+                             DroolsSoftKeywords.NOT ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.EXISTS ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.FORALL ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.AND ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.OR ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.COLLECT ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.FROM ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.END ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.EVAL ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.OVER ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.THEN );
+    }
+
+    public boolean validateStatement( int index ) {
+        boolean ret = false;
+        String text2Validate = retrieveLT( index );
+        for ( String st : statementKeywords ) {
+            if ( validateText( text2Validate,
+                               st ) ) {
+                ret = true;
+                break;
+            }
+        }
+        return ret || validateAttribute( index );
+    }
+
+    public boolean validateAttribute( int index ) {
+        String text2Validate = retrieveLT( index );
+        return validateText( text2Validate,
+                             DroolsSoftKeywords.SALIENCE ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.ENABLED ) ||
+               (validateText( text2Validate,
+                              DroolsSoftKeywords.NO ) &&
+                 validateLT( index + 1,
+                             "-" ) &&
+                 validateLT( index + 2,
+                             DroolsSoftKeywords.LOOP )) ||
+               (validateText( text2Validate,
+                              DroolsSoftKeywords.AUTO ) &&
+                 validateLT( index + 1,
+                             "-" ) &&
+                 validateLT( index + 2,
+                             DroolsSoftKeywords.FOCUS )) ||
+               (validateText( text2Validate,
+                              DroolsSoftKeywords.LOCK ) &&
+                 validateLT( index + 1,
+                             "-" ) &&
+                 validateLT( index + 2,
+                             DroolsSoftKeywords.ON ) &&
+                 validateLT( index + 3,
+                             "-" ) &&
+                 validateLT( index + 4,
+                             DroolsSoftKeywords.ACTIVE )) ||
+               (validateText( text2Validate,
+                              DroolsSoftKeywords.AGENDA ) &&
+                 validateLT( index + 1,
+                             "-" ) &&
+                 validateLT( index + 2,
+                             DroolsSoftKeywords.GROUP )) ||
+               (validateText( text2Validate,
+                              DroolsSoftKeywords.ACTIVATION ) &&
+                 validateLT( index + 1,
+                             "-" ) &&
+                 validateLT( index + 2,
+                             DroolsSoftKeywords.GROUP )) ||
+               (validateText( text2Validate,
+                              DroolsSoftKeywords.RULEFLOW ) &&
+                 validateLT( index + 1,
+                             "-" ) &&
+                 validateLT( index + 2,
+                             DroolsSoftKeywords.GROUP )) ||
+               (validateText( text2Validate,
+                              DroolsSoftKeywords.DATE ) &&
+                 validateLT( index + 1,
+                             "-" ) &&
+                 validateLT( index + 2,
+                             DroolsSoftKeywords.EFFECTIVE )) ||
+               (validateText( text2Validate,
+                              DroolsSoftKeywords.DATE ) &&
+                 validateLT( index + 1,
+                             "-" ) &&
+                 validateLT( index + 2,
+                             DroolsSoftKeywords.EXPIRES )) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.DIALECT ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.CALENDARS ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.TIMER ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.DURATION ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.REFRACT ) ||
+               validateText( text2Validate,
+                             DroolsSoftKeywords.DIRECT );
+    }
+
+    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 ( state.errorRecovery ) {
+            return;
+        }
+        state.errorRecovery = true;
+
+        errors.add( errorMessageFactory.createDroolsException( ex ) );
+    }
+
+    public void reportError( Exception e ) {
+        try {
+            errors.add( errorMessageFactory.createDroolsException( e,
+                                                                   input.LT( 1 ) ) );
+        } catch (Exception ignored) {
+            errors.add(new DroolsParserException( "Unexpected error: " + e.getMessage(), e ));
+        }
+    }
+
+    /** return the raw DroolsParserException errors */
+    public List<DroolsParserException> getErrors() {
+        return errors;
+    }
+
+    /** Return a list of pretty strings summarising the errors */
+    public List<String> getErrorMessages() {
+        List<String> messages = new ArrayList<>( errors.size() );
+
+        for ( DroolsParserException activeException : errors ) {
+            messages.add( activeException.getMessage() );
+        }
+
+        return messages;
+    }
+
+    /** return true if any parser errors were accumulated */
+    public boolean hasErrors() {
+        return !errors.isEmpty();
+    }
+
+    /**
+     * Method that adds a paraphrase type into paraphrases stack.
+     *
+     * @param type
+     *            paraphrase type
+     */
+    public void pushParaphrases( DroolsParaphraseTypes type ) {
+        Map<DroolsParaphraseTypes, String> activeMap = new HashMap<>();
+        activeMap.put( type,
+                       "" );
+        paraphrases.push( activeMap );
+    }
+
+    public Map<DroolsParaphraseTypes, String> popParaphrases() {
+        return paraphrases.pop();
+    }
+
+    /**
+     * Method that sets paraphrase value for a type into paraphrases stack.
+     *
+     * @param type
+     *            paraphrase type
+     * @param value
+     *            paraphrase value
+     */
+    public void setParaphrasesValue( DroolsParaphraseTypes type,
+                                     String value ) {
+        paraphrases.peek().put( type,
+                                value );
+    }
+
+    void setStart( DescrBuilder< ? , ? > db ) {
+        setStart( db,
+                  input.LT( 1 ) );
+    }
+
+    void setStart( DescrBuilder< ? , ? > db,
+                   Token first ) {
+        if ( db != null && first != null ) {
+            db.startCharacter( ((CommonToken) first).getStartIndex() ).startLocation( first.getLine(),
+                                                                                      first.getCharPositionInLine() );
+        }
+    }
+
+    void setStart( BaseDescr descr,
+                   Token first ) {
+        if ( descr != null && first != null ) {
+            descr.setLocation( first.getLine(),
+                               first.getCharPositionInLine() );
+            descr.setStartCharacter( ((CommonToken) first).getStartIndex() );
+        }
+    }
+
+    void setEnd( BaseDescr descr ) {
+        Token last = input.LT( -1 );
+        if ( descr != null && last != null ) {
+            int endLocation = last.getText() != null ? last.getCharPositionInLine() + last.getText().length() - 1 : last.getCharPositionInLine();
+            descr.setEndCharacter( ((CommonToken) last).getStopIndex() + 1 );
+            descr.setEndLocation( last.getLine(),
+                                  endLocation );
+        }
+    }
+
+    void setEnd( DescrBuilder< ? , ? > db ) {
+        Token last = input.LT( -1 );
+        if ( db != null && last != null ) {
+            int endLocation = last.getText() != null ? last.getCharPositionInLine() + last.getText().length() - 1 : last.getCharPositionInLine();
+            db.endCharacter( ((CommonToken) last).getStopIndex() + 1 ).endLocation( last.getLine(),
+                                                                                    endLocation );
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends DescrBuilder< ? , ? >> T start( DescrBuilder< ? , ? > ctxBuilder,
+                                                      Class<T> clazz,
+                                                      String param ) {
+        if ( state.backtracking == 0 ) {
+            if ( PackageDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                pushParaphrases( DroolsParaphraseTypes.PACKAGE );
+                beginSentence( DroolsSentenceType.PACKAGE );
+                setStart( ctxBuilder );
+            } else if ( ImportDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                ImportDescrBuilder imp;
+                if ( validateLT( 2,
+                                 DroolsSoftKeywords.FUNCTION ) ||
+                     validateLT( 2,
+                                 DroolsSoftKeywords.STATIC ) ) {
+                    imp = ctxBuilder == null ?
+                          DescrFactory.newPackage().newFunctionImport() :
+                          ((PackageDescrBuilder) ctxBuilder).newFunctionImport();
+                } else {
+                    imp = ctxBuilder == null ?
+                          DescrFactory.newPackage().newImport() :
+                          ((PackageDescrBuilder) ctxBuilder).newImport();
+                }
+                pushParaphrases( DroolsParaphraseTypes.IMPORT );
+                beginSentence( DroolsSentenceType.IMPORT_STATEMENT );
+                setStart( imp );
+                return (T) imp;
+            } else if ( UnitDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                UnitDescrBuilder imp = ctxBuilder == null ?
+                          DescrFactory.newPackage().newUnit() :
+                          ((PackageDescrBuilder) ctxBuilder).newUnit();
+                pushParaphrases( DroolsParaphraseTypes.UNIT );
+                beginSentence( DroolsSentenceType.UNIT );
+                setStart( imp );
+                return (T) imp;
+            } else if ( AccumulateImportDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                AccumulateImportDescrBuilder imp = ctxBuilder == null ?
+                          DescrFactory.newPackage().newAccumulateImport() :
+                          ((PackageDescrBuilder) ctxBuilder).newAccumulateImport();
+                pushParaphrases( DroolsParaphraseTypes.ACCUMULATE_IMPORT );
+                beginSentence( DroolsSentenceType.ACCUMULATE_IMPORT_STATEMENT );
+                setStart( imp );
+                return (T) imp;
+            } else if ( GlobalDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                GlobalDescrBuilder global = ctxBuilder == null ?
+                                            DescrFactory.newPackage().newGlobal() :
+                                            ((PackageDescrBuilder) ctxBuilder).newGlobal();
+                pushParaphrases( DroolsParaphraseTypes.GLOBAL );
+                beginSentence( DroolsSentenceType.GLOBAL );
+                setStart( global );
+                return (T) global;
+            } else if ( DeclareDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                DeclareDescrBuilder declare = ctxBuilder == null ?
+                                              DescrFactory.newPackage().newDeclare() :
+                                              ((PackageDescrBuilder) ctxBuilder).newDeclare();
+                return (T) declare;
+            } else if ( TypeDeclarationDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                TypeDeclarationDescrBuilder declare = ctxBuilder == null ?
+                                                      DescrFactory.newPackage().newDeclare().type() :
+                                                      ((DeclareDescrBuilder) ctxBuilder).type();
+                pushParaphrases( DroolsParaphraseTypes.TYPE_DECLARE );
+                beginSentence( DroolsSentenceType.TYPE_DECLARATION );
+                setStart( declare );
+                return (T) declare;
+            } else if ( EnumDeclarationDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                EnumDeclarationDescrBuilder declare = ctxBuilder == null ?
+                        DescrFactory.newPackage().newDeclare().enumerative() :
+                        ((DeclareDescrBuilder) ctxBuilder).enumerative();
+                pushParaphrases( DroolsParaphraseTypes.ENUM_DECLARE );
+                beginSentence( DroolsSentenceType.ENUM_DECLARATION );
+                setStart( declare );
+                return (T) declare;
+            }else if ( EntryPointDeclarationDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                EntryPointDeclarationDescrBuilder declare = ctxBuilder == null ?
+                        DescrFactory.newPackage().newDeclare().entryPoint() :
+                        ((DeclareDescrBuilder) ctxBuilder).entryPoint();
+                pushParaphrases( DroolsParaphraseTypes.ENTRYPOINT_DECLARE );
+                beginSentence( DroolsSentenceType.ENTRYPOINT_DECLARATION );
+                setStart( declare );
+                return (T) declare;
+            } else if ( WindowDeclarationDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                WindowDeclarationDescrBuilder declare = ctxBuilder == null ?
+                                                            DescrFactory.newPackage().newDeclare().window() :
+                                                            ((DeclareDescrBuilder) ctxBuilder).window();
+                pushParaphrases( DroolsParaphraseTypes.WINDOW_DECLARE );
+                beginSentence( DroolsSentenceType.WINDOW_DECLARATION );
+                setStart( declare );
+                return (T) declare;
+            } else if ( FieldDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                FieldDescrBuilder field = ((AbstractClassTypeDeclarationBuilder) ctxBuilder).newField( param );
+                setStart( field );
+                return (T) field;
+            } else if ( EnumLiteralDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                EnumLiteralDescrBuilder literal = ((EnumDeclarationDescrBuilder) ctxBuilder).newEnumLiteral( param );
+                setStart( literal );
+                return (T) literal;
+            } else if ( FunctionDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                FunctionDescrBuilder function;
+                if ( ctxBuilder == null ) {
+                    function = DescrFactory.newPackage().newFunction();
+                } else {
+                    PackageDescrBuilder pkg = (PackageDescrBuilder) ctxBuilder;
+                    function = pkg.newFunction().namespace( pkg.getDescr().getName() );
+                    AttributeDescr attribute = pkg.getDescr().getAttribute( "dialect" );
+                    if ( attribute != null ) {
+                        function.dialect( attribute.getValue() );
+                    }
+                }
+                pushParaphrases( DroolsParaphraseTypes.FUNCTION );
+                beginSentence( DroolsSentenceType.FUNCTION );
+                setStart( function );
+                return (T) function;
+            } else if ( RuleDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                RuleDescrBuilder rule = ctxBuilder == null ?
+                                        DescrFactory.newPackage().newRule() :
+                                        ((PackageDescrBuilder) ctxBuilder).newRule();
+                pushParaphrases( DroolsParaphraseTypes.RULE );
+                beginSentence( DroolsSentenceType.RULE );
+                setStart( rule );
+                return (T) rule;
+            } else if ( QueryDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                QueryDescrBuilder query = ctxBuilder == null ?
+                                        DescrFactory.newPackage().newQuery() :
+                                        ((PackageDescrBuilder) ctxBuilder).newQuery();
+                pushParaphrases( DroolsParaphraseTypes.QUERY );
+                beginSentence( DroolsSentenceType.QUERY );
+                setStart( query );
+                return (T) query;
+            } else if ( AttributeDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                AttributeDescrBuilder< ? > attribute = ((AttributeSupportBuilder< ? >) ctxBuilder).attribute(param);
+                setStart( attribute );
+                return (T) attribute;
+            } else if ( EvalDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                EvalDescrBuilder< ? > eval = ((CEDescrBuilder< ? , ? >) ctxBuilder).eval();
+                pushParaphrases( DroolsParaphraseTypes.EVAL );
+                beginSentence( DroolsSentenceType.EVAL );
+                setStart( eval );
+                return (T) eval;
+            } else if ( ForallDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                ForallDescrBuilder< ? > forall = ((CEDescrBuilder< ? , ? >) ctxBuilder).forall();
+                setStart( forall );
+                return (T) forall;
+            } else if ( CEDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                setStart( ctxBuilder );
+                return (T) ctxBuilder;
+            } else if ( PatternDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                PatternDescrBuilder< ? > pattern = ((PatternContainerDescrBuilder< ? , ? >) ctxBuilder).pattern();
+                pushParaphrases( DroolsParaphraseTypes.PATTERN );
+                setStart( pattern );
+                return (T) pattern;
+            } else if ( CollectDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                CollectDescrBuilder< ? > collect = ((PatternDescrBuilder< ? >) ctxBuilder).from().collect();
+                setStart( collect );
+                return (T) collect;
+            } else if ( GroupByDescrBuilder.class.isAssignableFrom(clazz) ) {
+                // GroupBy extends Accumulate and thus need to be before it
+                GroupByDescrBuilder< ? > groupBy = ((PatternDescrBuilder< ? >) ctxBuilder).from().groupBy();
+                setStart( groupBy );
+                return (T) groupBy;
+            } else if ( AccumulateDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                AccumulateDescrBuilder< ? > accumulate = ((PatternDescrBuilder< ? >) ctxBuilder).from().accumulate();
+                setStart( accumulate );
+                return (T) accumulate;
+            } else if ( BehaviorDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                BehaviorDescrBuilder< ? > behavior = ((PatternDescrBuilder< ? >) ctxBuilder).behavior();
+                setStart( behavior );
+                return (T) behavior;
+            } else if ( NamedConsequenceDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                NamedConsequenceDescrBuilder< ? > namedConsequence = ((CEDescrBuilder< ? , ? >) ctxBuilder).namedConsequence();
+                setStart( namedConsequence );
+                return (T) namedConsequence;
+            } else if ( ConditionalBranchDescrBuilder.class.isAssignableFrom( clazz ) ) {
+                ConditionalBranchDescrBuilder< ? > conditionalBranch = ((CEDescrBuilder< ? , ? >) ctxBuilder).conditionalBranch();
+                setStart( conditionalBranch );
+                return (T) conditionalBranch;
+            }
+        }
+        return null;
+    }
+
+    @SuppressWarnings("unchecked")
+    public <T extends DescrBuilder< ? , ? >> T end( Class<T> clazz,
+                                                    DescrBuilder< ? , ? > builder ) {
+        if ( state.backtracking == 0 ) {
+            if ( !(FieldDescrBuilder.class.isAssignableFrom( clazz ) ||
+                   AttributeDescrBuilder.class.isAssignableFrom( clazz ) ||
+                   CEDescrBuilder.class.isAssignableFrom( clazz ) ||
+                   CollectDescrBuilder.class.isAssignableFrom( clazz ) ||
+                   AccumulateDescrBuilder.class.isAssignableFrom( clazz ) ||
+                   ForallDescrBuilder.class.isAssignableFrom( clazz ) ||
+                   BehaviorDescrBuilder.class.isAssignableFrom( clazz ) ||
+                   ConditionalBranchDescrBuilder.class.isAssignableFrom( clazz ) ||
+                   NamedConsequenceDescrBuilder.class.isAssignableFrom( clazz )) ) {
+                popParaphrases();
+            }
+
+            if (RuleDescrBuilder.class.isAssignableFrom(clazz)) {
+                RuleDescrBuilder ruleDescrBuilder = (RuleDescrBuilder)builder;
+                ruleDescrBuilder.end().getDescr().afterRuleAdded(ruleDescrBuilder.getDescr());
+            }
+
+            setEnd( builder );
+            return (T) builder;
+        }
+        return null;
+    }
+
+    public String[] getStatementKeywords() {
+        return statementKeywords;
+    }
+}
diff --git a/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/DRLExprParserTest.java b/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/DRLExprParserTest.java
new file mode 100644
index 00000000000..a7672090cc8
--- /dev/null
+++ b/drools-drl/drools-drl10-parser/src/test/java/org/drools/parser/DRLExprParserTest.java
@@ -0,0 +1,270 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.drools.parser;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.drools.compiler.builder.impl.EvaluatorRegistry;
+import org.drools.drl.ast.descr.AtomicExprDescr;
+import org.drools.drl.ast.descr.BindingDescr;
+import org.drools.drl.ast.descr.ConnectiveType;
+import org.drools.drl.ast.descr.ConstraintConnectiveDescr;
+import org.drools.drl.ast.descr.RelationalExprDescr;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.kie.internal.builder.conf.LanguageLevelOption;
+
+/**
+ * DRLExprTreeTest
+ */
+public class DRLExprParserTest {
+
+    DrlExprParser parser;
+
+    @Before
+    public void setUp() throws Exception {
+        new EvaluatorRegistry();
+        this.parser = new DrlExprParser(LanguageLevelOption.DRL6);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        this.parser = null;
+    }
+
+    @Test
+    public void testSimpleExpression() throws Exception {
+        String source = "a > b";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(1);
+
+        RelationalExprDescr expr = (RelationalExprDescr) result.getDescrs().get( 0 );
+        assertThat(expr.getOperator()).isEqualTo(">");
+
+        AtomicExprDescr left = (AtomicExprDescr) expr.getLeft();
+        AtomicExprDescr right = (AtomicExprDescr) expr.getRight();
+
+        assertThat(left.getExpression()).isEqualTo("a");
+        assertThat(right.getExpression()).isEqualTo("b");
+    }
+
+    @Test
+    public void testAndConnective() throws Exception {
+        String source = "a > b && 10 != 20";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(2);
+
+        RelationalExprDescr expr = (RelationalExprDescr) result.getDescrs().get( 0 );
+        assertThat(expr.getOperator()).isEqualTo(">");
+        AtomicExprDescr left = (AtomicExprDescr) expr.getLeft();
+        AtomicExprDescr right = (AtomicExprDescr) expr.getRight();
+        assertThat(left.getExpression()).isEqualTo("a");
+        assertThat(right.getExpression()).isEqualTo("b");
+
+        expr = (RelationalExprDescr) result.getDescrs().get( 1 );
+        assertThat(expr.getOperator()).isEqualTo("!=");
+        left = (AtomicExprDescr) expr.getLeft();
+        right = (AtomicExprDescr) expr.getRight();
+        assertThat(left.getExpression()).isEqualTo("10");
+        assertThat(right.getExpression()).isEqualTo("20");
+    }
+
+    @Test
+    public void testConnective2() throws Exception {
+        String source = "(a > b || 10 != 20) && someMethod(10) == 20";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(2);
+
+        ConstraintConnectiveDescr or = (ConstraintConnectiveDescr) result.getDescrs().get( 0 );
+        assertThat(or.getConnective()).isEqualTo(ConnectiveType.OR);
+        assertThat(or.getDescrs().size()).isEqualTo(2);
+
+        RelationalExprDescr expr = (RelationalExprDescr) or.getDescrs().get( 0 );
+        assertThat(expr.getOperator()).isEqualTo(">");
+        AtomicExprDescr left = (AtomicExprDescr) expr.getLeft();
+        AtomicExprDescr right = (AtomicExprDescr) expr.getRight();
+        assertThat(left.getExpression()).isEqualTo("a");
+        assertThat(right.getExpression()).isEqualTo("b");
+
+        expr = (RelationalExprDescr) or.getDescrs().get( 1 );
+        assertThat(expr.getOperator()).isEqualTo("!=");
+        left = (AtomicExprDescr) expr.getLeft();
+        right = (AtomicExprDescr) expr.getRight();
+        assertThat(left.getExpression()).isEqualTo("10");
+        assertThat(right.getExpression()).isEqualTo("20");
+
+        expr = (RelationalExprDescr) result.getDescrs().get( 1 );
+        assertThat(expr.getOperator()).isEqualTo("==");
+        left = (AtomicExprDescr) expr.getLeft();
+        right = (AtomicExprDescr) expr.getRight();
+        assertThat(left.getExpression()).isEqualTo("someMethod(10)");
+        assertThat(right.getExpression()).isEqualTo("20");
+
+    }
+
+    @Test
+    public void testBinding() throws Exception {
+        String source = "$x : property";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(1);
+
+        BindingDescr bind = (BindingDescr) result.getDescrs().get( 0 );
+        assertThat(bind.getVariable()).isEqualTo("$x");
+        assertThat(bind.getExpression()).isEqualTo("property");
+    }
+
+    @Test
+    public void testBindingConstraint() throws Exception {
+        String source = "$x : property > value";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(1);
+
+        RelationalExprDescr rel = (RelationalExprDescr) result.getDescrs().get( 0 );
+        assertThat(rel.getOperator()).isEqualTo(">");
+
+        BindingDescr bind = (BindingDescr) rel.getLeft();
+        assertThat(bind.getVariable()).isEqualTo("$x");
+        assertThat(bind.getExpression()).isEqualTo("property");
+
+        AtomicExprDescr right = (AtomicExprDescr) rel.getRight();
+        assertThat(right.getExpression()).isEqualTo("value");
+    }
+
+    @Test
+    public void testBindingWithRestrictions() throws Exception {
+        String source = "$x : property > value && < 20";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(2);
+
+        RelationalExprDescr rel = (RelationalExprDescr) result.getDescrs().get( 0 );
+        assertThat(rel.getOperator()).isEqualTo(">");
+
+        BindingDescr bind = (BindingDescr) rel.getLeft();
+        assertThat(bind.getVariable()).isEqualTo("$x");
+        assertThat(bind.getExpression()).isEqualTo("property");
+
+        AtomicExprDescr right = (AtomicExprDescr) rel.getRight();
+        assertThat(right.getExpression()).isEqualTo("value");
+
+        rel = (RelationalExprDescr) result.getDescrs().get( 1 );
+        assertThat(rel.getOperator()).isEqualTo("<");
+
+        AtomicExprDescr left = (AtomicExprDescr) rel.getLeft();
+        assertThat(left.getExpression()).isEqualTo("property");
+
+        right = (AtomicExprDescr) rel.getRight();
+        assertThat(right.getExpression()).isEqualTo("20");
+    }
+
+    @Test
+    public void testDoubleBinding() throws Exception {
+        String source = "$x : x.m( 1, a ) && $y : y[z].foo";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(2);
+
+        BindingDescr bind = (BindingDescr) result.getDescrs().get( 0 );
+        assertThat(bind.getVariable()).isEqualTo("$x");
+        assertThat(bind.getExpression()).isEqualTo("x.m( 1, a )");
+
+        bind = (BindingDescr) result.getDescrs().get( 1 );
+        assertThat(bind.getVariable()).isEqualTo("$y");
+        assertThat(bind.getExpression()).isEqualTo("y[z].foo");
+    }
+
+    @Test
+    public void testDeepBinding() throws Exception {
+        String source = "($a : a > $b : b[10].prop || 10 != 20) && $x : someMethod(10) == 20";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(2);
+
+        ConstraintConnectiveDescr or = (ConstraintConnectiveDescr) result.getDescrs().get( 0 );
+        assertThat(or.getConnective()).isEqualTo(ConnectiveType.OR);
+        assertThat(or.getDescrs().size()).isEqualTo(2);
+
+        RelationalExprDescr expr = (RelationalExprDescr) or.getDescrs().get( 0 );
+        assertThat(expr.getOperator()).isEqualTo(">");
+        BindingDescr leftBind = (BindingDescr) expr.getLeft();
+        BindingDescr rightBind = (BindingDescr) expr.getRight();
+        assertThat(leftBind.getVariable()).isEqualTo("$a");
+        assertThat(leftBind.getExpression()).isEqualTo("a");
+        assertThat(rightBind.getVariable()).isEqualTo("$b");
+        assertThat(rightBind.getExpression()).isEqualTo("b[10].prop");
+
+        expr = (RelationalExprDescr) or.getDescrs().get( 1 );
+        assertThat(expr.getOperator()).isEqualTo("!=");
+        AtomicExprDescr leftExpr = (AtomicExprDescr) expr.getLeft();
+        AtomicExprDescr rightExpr = (AtomicExprDescr) expr.getRight();
+        assertThat(leftExpr.getExpression()).isEqualTo("10");
+        assertThat(rightExpr.getExpression()).isEqualTo("20");
+
+        expr = (RelationalExprDescr) result.getDescrs().get( 1 );
+        assertThat(expr.getOperator()).isEqualTo("==");
+        leftBind = (BindingDescr) expr.getLeft();
+        rightExpr = (AtomicExprDescr) expr.getRight();
+        assertThat(leftBind.getVariable()).isEqualTo("$x");
+        assertThat(leftBind.getExpression()).isEqualTo("someMethod(10)");
+        assertThat(rightExpr.getExpression()).isEqualTo("20");
+
+    }
+
+    @Test(timeout = 10000L)
+    public void testNestedExpression() throws Exception {
+        // DROOLS-982
+        String source = "(((((((((((((((((((((((((((((((((((((((((((((((((( a > b ))))))))))))))))))))))))))))))))))))))))))))))))))";
+        ConstraintConnectiveDescr result = parser.parse( source );
+        assertThat(parser.hasErrors()).as(parser.getErrors().toString()).isFalse();
+
+        assertThat(result.getConnective()).isEqualTo(ConnectiveType.AND);
+        assertThat(result.getDescrs().size()).isEqualTo(1);
+
+        RelationalExprDescr expr = (RelationalExprDescr) result.getDescrs().get( 0 );
+        assertThat(expr.getOperator()).isEqualTo(">");
+
+        AtomicExprDescr left = (AtomicExprDescr) expr.getLeft();
+        AtomicExprDescr right = (AtomicExprDescr) expr.getRight();
+
+        assertThat(left.getExpression()).isEqualTo("a");
+        assertThat(right.getExpression()).isEqualTo("b");
+    }
+}