Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/FeatureMatchExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/FeatureMatchExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/FeatureMatchExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/FeatureMatchExpression.java
 Wed Jan 16 11:45:02 2019
@@ -21,17 +21,23 @@ package org.apache.uima.ruta.expression.
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 
+import org.apache.uima.cas.ArrayFS;
 import org.apache.uima.cas.CAS;
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.ruta.RutaStream;
 import org.apache.uima.ruta.expression.IRutaExpression;
 import org.apache.uima.ruta.expression.MatchReference;
 import org.apache.uima.ruta.expression.RutaExpression;
+import org.apache.uima.ruta.expression.annotation.IAnnotationExpression;
+import org.apache.uima.ruta.expression.annotation.IAnnotationListExpression;
 import org.apache.uima.ruta.expression.bool.IBooleanExpression;
 import org.apache.uima.ruta.expression.number.INumberExpression;
 import org.apache.uima.ruta.expression.string.IStringExpression;
@@ -71,51 +77,56 @@ public class FeatureMatchExpression exte
 
   public boolean checkFeatureValue(FeatureStructure fs, MatchContext context, 
RutaStream stream) {
     Feature feature = getFeature(context, stream);
+    if (feature instanceof LazyFeature) {
+      LazyFeature lazyFeature = (LazyFeature) feature;
+      feature = lazyFeature.initialize(fs);
+    }
     return checkFeatureValue(fs, feature, context, stream);
   }
 
   public boolean checkFeatureValue(FeatureStructure fs, Feature feature, 
MatchContext context,
           RutaStream stream) {
-    String rn = null;
-    if(feature instanceof CoveredTextFeature) {
-      rn = CAS.TYPE_NAME_STRING;
-    } else if (feature != null){
-      rn = feature.getRange().getName();
+    Type featureRangeType = null;
+    TypeSystem typeSystem = stream.getCas().getTypeSystem();
+    if (feature instanceof CoveredTextFeature) {
+      featureRangeType = typeSystem.getType(CAS.TYPE_NAME_STRING);
+    } else if (feature != null) {
+      featureRangeType = feature.getRange();
     }
-    
-    if (rn.equals(CAS.TYPE_NAME_BOOLEAN)) {
+    String rangeName = featureRangeType.getName();
+    if (rangeName.equals(CAS.TYPE_NAME_BOOLEAN)) {
       Boolean v1 = fs.getBooleanValue(feature);
       if (getArg() instanceof IBooleanExpression) {
         IBooleanExpression expr = (IBooleanExpression) getArg();
         Boolean v2 = expr.getBooleanValue(context, stream);
         return compare(v1, v2);
       }
-    } else if (rn.equals(CAS.TYPE_NAME_INTEGER) || 
rn.equals(CAS.TYPE_NAME_BYTE)
-            || rn.equals(CAS.TYPE_NAME_SHORT) || 
rn.equals(CAS.TYPE_NAME_LONG)) {
+    } else if (rangeName.equals(CAS.TYPE_NAME_INTEGER) || 
rangeName.equals(CAS.TYPE_NAME_BYTE)
+            || rangeName.equals(CAS.TYPE_NAME_SHORT) || 
rangeName.equals(CAS.TYPE_NAME_LONG)) {
       Integer v1 = fs.getIntValue(feature);
       if (getArg() instanceof INumberExpression) {
         INumberExpression expr = (INumberExpression) getArg();
         Integer v2 = expr.getIntegerValue(context, stream);
         return compare(v1, v2);
       }
-    } else if (rn.equals(CAS.TYPE_NAME_DOUBLE)) {
+    } else if (rangeName.equals(CAS.TYPE_NAME_DOUBLE)) {
       Double v1 = fs.getDoubleValue(feature);
       if (getArg() instanceof INumberExpression) {
         INumberExpression expr = (INumberExpression) getArg();
         Double v2 = expr.getDoubleValue(context, stream);
         return compare(v1, v2);
       }
-    } else if (rn.equals(CAS.TYPE_NAME_FLOAT)) {
+    } else if (rangeName.equals(CAS.TYPE_NAME_FLOAT)) {
       Float v1 = fs.getFloatValue(feature);
       if (getArg() instanceof INumberExpression) {
         INumberExpression expr = (INumberExpression) getArg();
         Float v2 = expr.getFloatValue(context, stream);
         return compare(v1, v2);
       }
-    } else if (rn.equals(CAS.TYPE_NAME_STRING)) {
+    } else if (typeSystem.subsumes(typeSystem.getType(CAS.TYPE_NAME_STRING), 
featureRangeType)) {
       String v1 = null;
       // null is possibly coveredText
-      if(feature instanceof CoveredTextFeature && fs instanceof AnnotationFS) {
+      if (feature instanceof CoveredTextFeature && fs instanceof AnnotationFS) 
{
         v1 = ((AnnotationFS) fs).getCoveredText();
       } else if (feature != null) {
         v1 = fs.getStringValue(feature);
@@ -125,13 +136,27 @@ public class FeatureMatchExpression exte
         String v2 = expr.getStringValue(context, stream);
         return compare(v1, v2);
       }
-    } else if (!feature.getRange().isPrimitive() && getArg() instanceof 
FeatureExpression) {
-      FeatureExpression fe = (FeatureExpression) getArg();
-      List<FeatureStructure> list = new ArrayList<>(1);
-      list.add(fs);
-      Collection<? extends FeatureStructure> featureAnnotations = 
fe.getFeatureStructures(list, false, context,
-              stream);
-      return compare(fs.getFeatureValue(feature), featureAnnotations);
+    } else {
+      FeatureStructure featureValue = fs.getFeatureValue(feature);
+      if (!feature.getRange().isPrimitive() && getArg() instanceof 
FeatureExpression) {
+        FeatureExpression fe = (FeatureExpression) getArg();
+        List<FeatureStructure> list = new ArrayList<>(1);
+        list.add(fs);
+        Collection<? extends FeatureStructure> featureAnnotations = 
fe.getFeatureStructures(list,
+                false, context, stream);
+        return compare(featureValue, featureAnnotations);
+      } else if (!feature.getRange().isPrimitive() && getArg() instanceof 
IAnnotationExpression) {
+        IAnnotationExpression ae = (IAnnotationExpression) getArg();
+        AnnotationFS compareAnnotation = ae.getAnnotation(context, stream);
+        return compare(featureValue, compareAnnotation);
+      } else if (!feature.getRange().isPrimitive()
+              && 
typeSystem.subsumes(typeSystem.getType(CAS.TYPE_NAME_FS_ARRAY), 
featureRangeType)
+              && getArg() instanceof IAnnotationListExpression) {
+        ArrayFS fsArray = (ArrayFS) featureValue;
+        IAnnotationListExpression ale = (IAnnotationListExpression) getArg();
+        List<AnnotationFS> annotationList = ale.getAnnotationList(context, 
stream);
+        return compare(Arrays.asList(fsArray.toArray()), annotationList);
+      }
     }
     return false;
   }
@@ -188,13 +213,13 @@ public class FeatureMatchExpression exte
   @Override
   public String toString() {
     String result = super.toString();
-    if(op != null) {
+    if (op != null) {
       result += op;
     }
-    if(arg != null) {
+    if (arg != null) {
       result += arg.toString();
     }
     return result;
   }
-  
+
 }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/LazyFeature.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/LazyFeature.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/LazyFeature.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/LazyFeature.java
 Wed Jan 16 11:45:02 2019
@@ -21,6 +21,7 @@ package org.apache.uima.ruta.expression.
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.FeatureStructure;
 import org.apache.uima.cas.Type;
+import org.apache.uima.ruta.block.RutaBlock;
 
 public class LazyFeature implements Feature {
 
@@ -30,9 +31,12 @@ public class LazyFeature implements Feat
 
   private String initializedWith;
 
-  public LazyFeature(String featureName) {
+  private RutaBlock parent;
+
+  public LazyFeature(String featureName, RutaBlock parent) {
     super();
     this.featureName = featureName;
+    this.parent = parent;
   }
 
   public Feature initialize(FeatureStructure featureStructure) {
@@ -94,7 +98,8 @@ public class LazyFeature implements Feat
   private void checkDelegate() {
     if (delegate == null) {
       throw new RuntimeException("Feature with name '" + featureName
-              + "' has not yet been resolved. Most likely, it is not defined 
for the given type: " + initializedWith);
+              + "' has not yet been resolved in script " + parent.getName()
+              + ". Most likely, it is not defined for the given type: " + 
initializedWith);
     }
 
   }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/SimpleFeatureExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/SimpleFeatureExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/SimpleFeatureExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/feature/SimpleFeatureExpression.java
 Wed Jan 16 11:45:02 2019
@@ -6,9 +6,9 @@
  * 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
@@ -43,24 +43,28 @@ public class SimpleFeatureExpression ext
   private MatchReference mr;
 
   public SimpleFeatureExpression(MatchReference mr) {
+
     super();
     this.mr = mr;
   }
 
   @Override
   public Feature getFeature(MatchContext context, RutaStream stream) {
-    List<Feature> features = getFeatures(context, stream);
+
+    List<Feature> features = this.getFeatures(context, stream);
     if (features != null && !features.isEmpty()) {
       Feature feature = features.get(features.size() - 1);
       if (feature instanceof LazyFeature) {
         LazyFeature lazyFeature = (LazyFeature) feature;
         AnnotationFS annotation = context.getAnnotation();
-        List<AnnotationFS> targetAnnotation = getTargetAnnotation(annotation, 
this, context,
+        List<AnnotationFS> targetAnnotation = 
this.getTargetAnnotation(annotation, this, context,
                 stream);
         if (targetAnnotation != null && !targetAnnotation.isEmpty()) {
           annotation = targetAnnotation.get(0);
         }
-        feature = lazyFeature.initialize(annotation);
+        if (features.size() == 1) {
+          feature = lazyFeature.initialize(annotation);
+        }
       }
       return feature;
     } else {
@@ -70,24 +74,25 @@ public class SimpleFeatureExpression ext
 
   @Override
   public List<Feature> getFeatures(MatchContext context, RutaStream stream) {
+
     List<Feature> result = new ArrayList<Feature>();
-    Type type = getInitialType(context, stream);
+    Type type = this.getInitialType(context, stream);
     Feature feature = null;
-    for (String each : getFeatureStringList(context, stream)) {
+    for (String each : this.getFeatureStringList(context, stream)) {
       IndexedReference indexedReference = 
ParsingUtils.parseIndexedReference(each);
       if (indexedReference.index != -1) {
         Feature delegate = 
type.getFeatureByBaseName(indexedReference.reference);
         if (delegate != null) {
           feature = new IndexedFeature(delegate, indexedReference.index);
         } else {
-          throw new IllegalArgumentException(
-                  "Not able to access feature " + each + " of type " + 
type.getName());
+          throw new IllegalArgumentException("Not able to access feature " + 
each + " of type "
+                  + type.getName() + "in script " + 
context.getParent().getName());
         }
       } else if (StringUtils.equals(each, UIMAConstants.FEATURE_COVERED_TEXT)
               || StringUtils.equals(each, 
UIMAConstants.FEATURE_COVERED_TEXT_SHORT)) {
         if (type != null) {
           feature = type.getFeatureByBaseName(each);
-          if(feature == null) {
+          if (feature == null) {
             // there is no explicit feature for coveredText
             feature = new CoveredTextFeature();
           }
@@ -97,12 +102,12 @@ public class SimpleFeatureExpression ext
         }
       } else if (type == null || type.isArray()) {
         // lazy check of range
-        feature = new LazyFeature(each);
+        feature = new LazyFeature(each, context.getParent());
       } else {
         feature = type.getFeatureByBaseName(each);
         if (feature == null) {
           // type maybe not specific enough
-          feature = new LazyFeature(each);
+          feature = new LazyFeature(each, context.getParent());
         }
       }
       result.add(feature);
@@ -117,17 +122,19 @@ public class SimpleFeatureExpression ext
 
   @Override
   public Type getInitialType(MatchContext context, RutaStream stream) {
-    ITypeExpression typeExpression = mr.getTypeExpression(context, stream);
-    IAnnotationExpression annotationExpression = 
mr.getAnnotationExpression(context, stream);
-    IAnnotationExpression annotationListExpression = 
mr.getAnnotationExpression(context, stream);
-    if (typeExpression!= null) {
+
+    ITypeExpression typeExpression = this.mr.getTypeExpression(context, 
stream);
+    IAnnotationExpression annotationExpression = 
this.mr.getAnnotationExpression(context, stream);
+    IAnnotationExpression annotationListExpression = 
this.mr.getAnnotationExpression(context,
+            stream);
+    if (typeExpression != null) {
       return typeExpression.getType(context, stream);
-    } else if(annotationExpression != null) {
-        AnnotationFS annotation = annotationExpression.getAnnotation(context, 
stream);
-        if (annotation != null) {
-          return annotation.getType();
-        }
-    } else if(annotationListExpression != null) {
+    } else if (annotationExpression != null) {
+      AnnotationFS annotation = annotationExpression.getAnnotation(context, 
stream);
+      if (annotation != null) {
+        return annotation.getType();
+      }
+    } else if (annotationListExpression != null) {
       AnnotationFS annotation = 
annotationListExpression.getAnnotation(context, stream);
       if (annotation != null) {
         return annotation.getType();
@@ -138,7 +145,8 @@ public class SimpleFeatureExpression ext
 
   @Override
   public List<String> getFeatureStringList(MatchContext context, RutaStream 
stream) {
-    return mr.getFeatureList();
+
+    return this.mr.getFeatureList();
   }
 
   @Override
@@ -147,13 +155,13 @@ public class SimpleFeatureExpression ext
           MatchContext context, RutaStream stream) {
 
     Collection<AnnotationFS> result = new ArrayList<>();
-    List<Feature> features = getFeatures(context, stream);
+    List<Feature> features = this.getFeatures(context, stream);
     if (features != null && !features.isEmpty()) {
-      collectFeatureStructures(featureStructures, features, 
checkOnFeatureValue, true, result,
+      this.collectFeatureStructures(featureStructures, features, 
checkOnFeatureValue, true, result,
               stream, context);
       return result;
     } else {
-      return filterAnnotations(featureStructures);
+      return this.filterAnnotations(featureStructures);
     }
   }
 
@@ -161,10 +169,11 @@ public class SimpleFeatureExpression ext
   public Collection<? extends FeatureStructure> getFeatureStructures(
           Collection<? extends FeatureStructure> featureStructures, boolean 
checkOnFeatureValue,
           MatchContext context, RutaStream stream) {
+
     Collection<FeatureStructure> result = new ArrayList<>();
-    List<Feature> features = getFeatures(context, stream);
+    List<Feature> features = this.getFeatures(context, stream);
     if (features != null && !features.isEmpty()) {
-      collectFeatureStructures(featureStructures, features, 
checkOnFeatureValue, false, result,
+      this.collectFeatureStructures(featureStructures, features, 
checkOnFeatureValue, false, result,
               stream, context);
       return result;
     } else {
@@ -172,25 +181,28 @@ public class SimpleFeatureExpression ext
     }
   }
 
-  private <T> void collectFeatureStructures(Collection<? extends 
FeatureStructure> featureStructures,
-          List<Feature> features, boolean checkOnFeatureValue, boolean 
onlyAnnotations,
-          Collection<T> result, RutaStream stream, MatchContext context) {
+  private <T> void collectFeatureStructures(
+          Collection<? extends FeatureStructure> featureStructures, 
List<Feature> features,
+          boolean checkOnFeatureValue, boolean onlyAnnotations, Collection<T> 
result,
+          RutaStream stream, MatchContext context) {
+
     for (FeatureStructure each : featureStructures) {
-      collectFeatureStructures(each, features, checkOnFeatureValue, 
onlyAnnotations, null, result,
-              stream, context);
+      this.collectFeatureStructures(each, features, checkOnFeatureValue, 
onlyAnnotations, null,
+              result, stream, context);
     }
   }
 
   @SuppressWarnings("unchecked")
-  private <T> void collectFeatureStructures(FeatureStructure featureStructure, 
List<Feature> features,
-          boolean checkOnFeatureValue, boolean collectOnlyAnnotations,
-          T lastValidFeatureStructure, Collection<T> result,
-          RutaStream stream, MatchContext context) {
+  private <T> void collectFeatureStructures(FeatureStructure featureStructure,
+          List<Feature> features, boolean checkOnFeatureValue, boolean 
collectOnlyAnnotations,
+          T lastValidFeatureStructure, Collection<T> result, RutaStream stream,
+          MatchContext context) {
+
     if (featureStructure == null) {
       return;
     }
     if (!collectOnlyAnnotations) {
-      if(!featureStructure.getType().isArray()) {
+      if (!featureStructure.getType().isArray()) {
         lastValidFeatureStructure = (T) featureStructure;
       }
     } else if (featureStructure instanceof AnnotationFS) {
@@ -207,7 +219,8 @@ public class SimpleFeatureExpression ext
         Feature delegate = lazyFeature.initialize(featureStructure);
         if (delegate == null) {
           throw new RuntimeException("Invalid feature! Feature '" + 
lazyFeature.getFeatureName()
-                  + "' is not defined for type '" + featureStructure.getType() 
+ "'.");
+                  + "' is not defined for type '" + featureStructure.getType() 
+ "' in script "
+                  + context.getParent().getName() + ".");
         } else {
           currentFeature = delegate;
         }
@@ -231,15 +244,15 @@ public class SimpleFeatureExpression ext
         result.add(lastValidFeatureStructure);
       }
     } else {
-      collectFeatureStructures(featureStructure, currentFeature, tail, 
checkOnFeatureValue,
+      this.collectFeatureStructures(featureStructure, currentFeature, tail, 
checkOnFeatureValue,
               collectOnlyAnnotations, lastValidFeatureStructure, result, 
stream, context);
     }
   }
 
-  private <T> void collectFeatureStructures(FeatureStructure featureStructure, 
Feature currentFeature,
-          List<Feature> tail, boolean checkOnFeatureValue, boolean 
collectOnlyAnnotations,
-          T lastValidFeatureStructure, Collection<T> result, RutaStream stream,
-          MatchContext context) {
+  private <T> void collectFeatureStructures(FeatureStructure featureStructure,
+          Feature currentFeature, List<Feature> tail, boolean 
checkOnFeatureValue,
+          boolean collectOnlyAnnotations, T lastValidFeatureStructure, 
Collection<T> result,
+          RutaStream stream, MatchContext context) {
 
     // stop early for match expressions
     if (this instanceof FeatureMatchExpression && (tail == null || 
tail.isEmpty())) {
@@ -264,7 +277,7 @@ public class SimpleFeatureExpression ext
     FeatureStructure value = featureStructure.getFeatureValue(currentFeature);
     if (value instanceof AnnotationFS) {
       AnnotationFS next = (AnnotationFS) value;
-      collectFeatureStructures(next, tail, checkOnFeatureValue, 
collectOnlyAnnotations,
+      this.collectFeatureStructures(next, tail, checkOnFeatureValue, 
collectOnlyAnnotations,
               lastValidFeatureStructure, result, stream, context);
     } else if (value instanceof FSArray && index >= 0) {
       FSArray array = (FSArray) value;
@@ -272,7 +285,7 @@ public class SimpleFeatureExpression ext
         FeatureStructure fs = array.get(index);
         if (fs instanceof AnnotationFS) {
           AnnotationFS next = (AnnotationFS) fs;
-          collectFeatureStructures(next, tail, checkOnFeatureValue, 
collectOnlyAnnotations,
+          this.collectFeatureStructures(next, tail, checkOnFeatureValue, 
collectOnlyAnnotations,
                   lastValidFeatureStructure, result, stream, context);
         }
       }
@@ -280,12 +293,12 @@ public class SimpleFeatureExpression ext
       FSArray array = (FSArray) value;
       for (int i = 0; i < array.size(); i++) {
         FeatureStructure fs = array.get(i);
-        collectFeatureStructures(fs, tail, checkOnFeatureValue, 
collectOnlyAnnotations,
+        this.collectFeatureStructures(fs, tail, checkOnFeatureValue, 
collectOnlyAnnotations,
                 lastValidFeatureStructure, result, stream, context);
       }
     } else if (value != null && !value.getType().isPrimitive()) {
       // feature structure feature values
-      collectFeatureStructures(value, tail, checkOnFeatureValue, 
collectOnlyAnnotations,
+      this.collectFeatureStructures(value, tail, checkOnFeatureValue, 
collectOnlyAnnotations,
               lastValidFeatureStructure, result, stream, context);
     } else if (value != null) {
       // primitive? -> return last annotation for further processing
@@ -296,16 +309,19 @@ public class SimpleFeatureExpression ext
   }
 
   public MatchReference getMatchReference() {
-    return mr;
+
+    return this.mr;
   }
 
   @Override
   public String toString() {
-    return mr.getMatch();
+
+    return this.mr.getMatch();
   }
 
   private Collection<AnnotationFS> filterAnnotations(
           Collection<? extends FeatureStructure> featureStructures) {
+
     Collection<AnnotationFS> result = new 
ArrayList<>(featureStructures.size());
 
     for (FeatureStructure featureStructure : featureStructures) {

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/number/NumberFeatureExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/number/NumberFeatureExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/number/NumberFeatureExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/number/NumberFeatureExpression.java
 Wed Jan 16 11:45:02 2019
@@ -29,6 +29,7 @@ import org.apache.uima.cas.Type;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.ruta.RutaStream;
 import org.apache.uima.ruta.expression.feature.FeatureExpression;
+import org.apache.uima.ruta.expression.feature.LazyFeature;
 import org.apache.uima.ruta.rule.MatchContext;
 
 public class NumberFeatureExpression extends AbstractNumberExpression {
@@ -70,12 +71,16 @@ public class NumberFeatureExpression ext
             false, context, stream);
     if (!featureStructures.isEmpty()) {
       Feature feature = this.fe.getFeature(context, stream);
-      Type range = feature.getRange();
       FeatureStructure next = featureStructures.iterator().next();
-      if (next instanceof AnnotationFS && 
!next.getType().equals(annotation.getType())) {
-        feature = this.fe.getFeature(new MatchContext((AnnotationFS) next, 
context.getElement(),
-                context.getRuleMatch(), context.getDirection()), stream);
+      if (feature instanceof LazyFeature) {
+        LazyFeature lazyFeature = (LazyFeature) feature;
+        feature = lazyFeature.initialize(next);
       }
+      Type range = feature.getRange();
+//      if (next instanceof AnnotationFS && 
!next.getType().equals(annotation.getType())) {
+//        feature = this.fe.getFeature(new MatchContext((AnnotationFS) next, 
context.getElement(),
+//                context.getRuleMatch(), context.getDirection()), stream);
+//      }
       if (CAS.TYPE_NAME_BYTE.equals(range.getName())) {
         result = next.getByteValue(feature);
       } else if (CAS.TYPE_NAME_DOUBLE.equals(range.getName())) {

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/number/NumberListFeatureExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/number/NumberListFeatureExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/number/NumberListFeatureExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/number/NumberListFeatureExpression.java
 Wed Jan 16 11:45:02 2019
@@ -34,6 +34,7 @@ import org.apache.uima.cas.IntArrayFS;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.ruta.RutaStream;
 import org.apache.uima.ruta.expression.feature.FeatureExpression;
+import org.apache.uima.ruta.expression.feature.LazyFeature;
 import org.apache.uima.ruta.rule.MatchContext;
 
 /**
@@ -64,9 +65,13 @@ public class NumberListFeatureExpression
     List<Number> result = new ArrayList<>();
 
     for (FeatureStructure each : featureStructures) {
-      if (each instanceof AnnotationFS && 
!each.getType().equals(annotation.getType())) {
-        feature = this.fe.getFeature(new MatchContext((AnnotationFS) each, 
context.getElement(),
-                context.getRuleMatch(), context.getDirection()), stream);
+//      if (each instanceof AnnotationFS && 
!each.getType().equals(annotation.getType())) {
+//        feature = this.fe.getFeature(new MatchContext((AnnotationFS) each, 
context.getElement(),
+//                context.getRuleMatch(), context.getDirection()), stream);
+//      }
+      if (feature instanceof LazyFeature) {
+        LazyFeature lazyFeature = (LazyFeature) feature;
+        feature = lazyFeature.initialize(each);
       }
       FeatureStructure featureValue = each.getFeatureValue(feature);
       if (featureValue instanceof IntArrayFS) {

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/ComposedStringExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/ComposedStringExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/ComposedStringExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/ComposedStringExpression.java
 Wed Jan 16 11:45:02 2019
@@ -26,15 +26,22 @@ import org.apache.uima.ruta.rule.MatchCo
 
 public class ComposedStringExpression extends LiteralStringExpression {
 
-  private final List<IStringExpression> epxressions;
+  private final List<IStringExpression> expressions;
 
   public ComposedStringExpression(List<IStringExpression> expressions) {
     super();
-    this.epxressions = expressions;
+    this.expressions = expressions;
   }
 
   @Override
   public String getStringValue(MatchContext context, RutaStream stream) {
+    if (expressions == null) {
+      return null;
+    }
+    if (expressions.size() == 1) {
+      IStringExpression stringExpression = expressions.get(0);
+      return stringExpression.getStringValue(context, stream);
+    }
     StringBuilder result = new StringBuilder();
     for (IStringExpression each : getExpressions()) {
       result.append(each.getStringValue(context, stream));
@@ -43,7 +50,7 @@ public class ComposedStringExpression ex
   }
 
   public List<IStringExpression> getExpressions() {
-    return epxressions;
+    return expressions;
   }
 
 }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/RemoveFunction.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/RemoveFunction.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/RemoveFunction.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/RemoveFunction.java
 Wed Jan 16 11:45:02 2019
@@ -44,9 +44,11 @@ public class RemoveFunction extends Stri
     String value = parent.getEnvironment().getVariableValue(var, String.class, 
stream);
     for (IStringExpression each : list) {
       String string = each.getStringValue(context, stream);
-      String[] split = value.split(string);
-      for (String r : split) {
-        result.append(r);
+      if (string != null) {
+        String[] split = value.split(string);
+        for (String r : split) {
+          result.append(r);
+        }
       }
     }
     return result.toString();

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/StringFeatureExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/StringFeatureExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/StringFeatureExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/StringFeatureExpression.java
 Wed Jan 16 11:45:02 2019
@@ -28,6 +28,7 @@ import org.apache.uima.cas.text.Annotati
 import org.apache.uima.ruta.RutaStream;
 import org.apache.uima.ruta.expression.feature.CoveredTextFeature;
 import org.apache.uima.ruta.expression.feature.FeatureExpression;
+import org.apache.uima.ruta.expression.feature.LazyFeature;
 import org.apache.uima.ruta.rule.MatchContext;
 
 public class StringFeatureExpression extends AbstractStringExpression {
@@ -35,6 +36,7 @@ public class StringFeatureExpression ext
   private FeatureExpression fe;
 
   public StringFeatureExpression(FeatureExpression fe) {
+
     super();
     this.fe = fe;
   }
@@ -49,9 +51,13 @@ public class StringFeatureExpression ext
             false, context, stream);
     if (!featureStructures.isEmpty()) {
       FeatureStructure next = featureStructures.iterator().next();
-      if (next instanceof AnnotationFS && 
!next.getType().equals(annotation.getType())) {
-        feature = this.fe.getFeature(new MatchContext((AnnotationFS) next, 
context.getElement(),
-                context.getRuleMatch(), context.getDirection()), stream);
+      // if (next instanceof AnnotationFS && 
!next.getType().equals(annotation.getType())) {
+      // feature = this.fe.getFeature(new MatchContext((AnnotationFS) next, 
context.getElement(),
+      // context.getRuleMatch(), context.getDirection()), stream);
+      // }
+      if (feature instanceof LazyFeature) {
+        LazyFeature lazyFeature = (LazyFeature) feature;
+        feature = lazyFeature.initialize(next);
       }
       if (next instanceof AnnotationFS && feature instanceof 
CoveredTextFeature) {
         return ((AnnotationFS) next).getCoveredText();

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/StringListFeatureExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/StringListFeatureExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/StringListFeatureExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/string/StringListFeatureExpression.java
 Wed Jan 16 11:45:02 2019
@@ -32,6 +32,7 @@ import org.apache.uima.cas.StringArrayFS
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.ruta.RutaStream;
 import org.apache.uima.ruta.expression.feature.FeatureExpression;
+import org.apache.uima.ruta.expression.feature.LazyFeature;
 import org.apache.uima.ruta.rule.MatchContext;
 
 /**
@@ -63,9 +64,13 @@ public class StringListFeatureExpression
     List<String> result = new ArrayList<>();
 
     for (FeatureStructure each : featureStructures) {
-      if (each instanceof AnnotationFS && 
!each.getType().equals(annotation.getType())) {
-        feature = this.fe.getFeature(new MatchContext((AnnotationFS) each, 
context.getElement(),
-                context.getRuleMatch(), context.getDirection()), stream);
+//      if (each instanceof AnnotationFS && 
!each.getType().equals(annotation.getType())) {
+//        feature = this.fe.getFeature(new MatchContext((AnnotationFS) each, 
context.getElement(),
+//                context.getRuleMatch(), context.getDirection()), stream);
+//      }
+      if (feature instanceof LazyFeature) {
+        LazyFeature lazyFeature = (LazyFeature) feature;
+        feature = lazyFeature.initialize(each);
       }
       FeatureStructure featureValue = each.getFeatureValue(feature);
       if (featureValue instanceof StringArrayFS) {

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/ITypeListExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/ITypeListExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/ITypeListExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/ITypeListExpression.java
 Wed Jan 16 11:45:02 2019
@@ -23,10 +23,11 @@ import java.util.List;
 
 import org.apache.uima.cas.Type;
 import org.apache.uima.ruta.RutaStream;
+import org.apache.uima.ruta.expression.string.IStringExpression;
 import org.apache.uima.ruta.rule.MatchContext;
 
-public interface ITypeListExpression {
-  
+public interface ITypeListExpression extends IStringExpression {
+
   List<Type> getTypeList(MatchContext context, RutaStream stream);
-  
+
 }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/SimpleTypeExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/SimpleTypeExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/SimpleTypeExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/SimpleTypeExpression.java
 Wed Jan 16 11:45:02 2019
@@ -45,7 +45,8 @@ public class SimpleTypeExpression extend
     RutaBlock parent = context.getParent();
     Type type = parent.getEnvironment().getType(typeString);
     if (type == null) {
-      throw new IllegalArgumentException("Not able to resolve type: " + 
typeString);
+      throw new IllegalArgumentException("Not able to resolve type: " + 
typeString +
+              " in script "+context.getParent().getName());
     }
     return type;
   }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/TypeListVariableExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/TypeListVariableExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/TypeListVariableExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/TypeListVariableExpression.java
 Wed Jan 16 11:45:02 2019
@@ -52,7 +52,8 @@ public class TypeListVariableExpression
         if(type != null) {
           result.add(type);
         } else {
-          throw new IllegalArgumentException("Not able to resolve type: " + 
each);
+          throw new IllegalArgumentException("Not able to resolve type: " + 
each + 
+                  " in script " +context.getParent().getName());
         }
       }
     }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/TypeVariableExpression.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/TypeVariableExpression.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/TypeVariableExpression.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/TypeVariableExpression.java
 Wed Jan 16 11:45:02 2019
@@ -53,9 +53,6 @@ public class TypeVariableExpression exte
   public Type getType(MatchContext context, RutaStream stream) {
     RutaBlock parent = context.getParent();
     Type type = parent.getEnvironment().getVariableValue(var, Type.class, 
stream);
-    if (type == null) {
-      throw new IllegalArgumentException("Not able to resolve type variable: " 
+ var);
-    }
     return type;
   }
 

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/AnonymousWordList.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/AnonymousWordList.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/AnonymousWordList.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/AnonymousWordList.java
 Wed Jan 16 11:45:02 2019
@@ -54,12 +54,11 @@ public class AnonymousWordList implement
     List<AnnotationFS> result = new ArrayList<AnnotationFS>();
     for (String each : list) {
       stream.moveToFirst();
-      while (stream.isValid()) {
-        RutaBasic next = (RutaBasic) stream.get();
+      while (stream.hasNext()) {
+        RutaBasic next = (RutaBasic) stream.next();
         if (each.equals(next.getCoveredText())) {
           result.add(next);
         }
-        stream.moveToNext();
       }
     }
     return result;

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/CSVTable.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/CSVTable.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/CSVTable.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/CSVTable.java
 Wed Jan 16 11:45:02 2019
@@ -29,6 +29,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Scanner;
+import java.util.regex.Pattern;
 
 import org.apache.uima.ruta.block.RutaBlock;
 import org.apache.uima.ruta.engine.RutaEngine;
@@ -36,18 +37,25 @@ import org.springframework.core.io.FileS
 import org.springframework.core.io.Resource;
 
 public class CSVTable implements RutaTable {
+  public static final String DEFAULT_CSV_SEPARATOR = ";";
 
   private List<List<String>> tableData;
 
   private Map<Integer, RutaWordList> columnWordLists = new HashMap<Integer, 
RutaWordList>(2);
 
+  private final String separator;
+
   /**
    * @param table
    *          A CSV table.
+   * @param selectedSeparator
+   *         The separator that should be used to splitup between columns in 
the CSV file
+   *
    * @throws IOException
    *           When there is a problem opening, reading or closing the table.
    */
-  public CSVTable(Resource table) throws IOException {
+  public CSVTable(Resource table, String selectedSeparator) throws IOException 
{
+    separator = selectedSeparator;
     InputStream stream = null;
     try {
       stream = table.getInputStream();
@@ -59,12 +67,13 @@ public class CSVTable implements RutaTab
     }
   }
 
-  public CSVTable(String location) throws IOException {
-    this(new FileSystemResource(location));
+  public CSVTable(String location, String selectedSeparator) throws 
IOException {
+    this(new FileSystemResource(location), selectedSeparator);
   }
 
-  public CSVTable(InputStream stream) throws IOException {
+  public CSVTable(InputStream stream, String selectedSeparator) throws 
IOException {
     super();
+    separator = selectedSeparator;
     buildTable(stream);
   }
 
@@ -74,8 +83,11 @@ public class CSVTable implements RutaTab
     tableData = new ArrayList<List<String>>();
     while (sc.hasNext()) {
       String line = sc.next().trim();
-      line = line.replaceAll(";;", "; ;");
-      String[] lineElements = line.split(";");
+      // Quote separator to ignore special characters in regex
+      String quotedSeparator = Pattern.quote(separator);
+      // add spacer between 2 followed separators without any other characters
+      line = line.replaceAll(quotedSeparator + quotedSeparator, separator + " 
" + separator);
+      String[] lineElements = line.split(quotedSeparator);
       List<String> row = Arrays.asList(lineElements);
       tableData.add(row);
     }
@@ -117,22 +129,23 @@ public class CSVTable implements RutaTab
   }
 
   @Override
-  public List<String> getRowWhere(int column, String value) {
+  public List<String> getRowWhere(int column, String lookupValue, boolean 
ignoreCase) {
     List<String> columnData = getColumnData(column);
     int i = 0;
-    for (String string : columnData) {
-      if (string.toLowerCase().equals(value.toLowerCase())) {
+    for (String tableValue : columnData) {
+      if (ignoreCase ? tableValue.equalsIgnoreCase(lookupValue) : 
tableValue.equals(lookupValue)) {
         return tableData.get(i);
       }
       i++;
     }
     i = 0;
-    for (String string : columnData) {
-      if (string.toLowerCase().replaceAll("\\s", 
"").equals(value.toLowerCase())) {
+    for (String tableValue : columnData) {
+      String tableValueWithoutSpacers = tableValue.replaceAll("\\s", "");
+      if (ignoreCase ? tableValueWithoutSpacers.equalsIgnoreCase(lookupValue) 
: tableValueWithoutSpacers.equals(lookupValue)) {
         return tableData.get(i);
       }
       i++;
     }
-    return new ArrayList<String>();
+    return new ArrayList<>();
   }
 }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/MultiTreeWordList.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/MultiTreeWordList.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/MultiTreeWordList.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/MultiTreeWordList.java
 Wed Jan 16 11:45:02 2019
@@ -38,9 +38,9 @@ import java.util.Set;
 
 import org.apache.commons.io.IOUtils;
 import org.apache.uima.cas.CAS;
-import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.Feature;
 import org.apache.uima.cas.Type;
+import org.apache.uima.cas.TypeSystem;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.ruta.RutaStream;
 import org.apache.uima.ruta.type.RutaBasic;
@@ -66,7 +66,9 @@ public class MultiTreeWordList implement
 
   /**
    * Default constructor.
-   * @throws IOException - should not happen but required by called constructor
+   * 
+   * @throws IOException
+   *           - should not happen but required by called constructor
    */
   public MultiTreeWordList() throws IOException {
     this(new String[] {}, null);
@@ -80,7 +82,7 @@ public class MultiTreeWordList implement
    * @param base
    *          the relative base
    * @throws IOException
-   *          When there is a problem reading pathname.
+   *           When there is a problem reading pathname.
    */
   public MultiTreeWordList(String pathname, File base) throws IOException {
     this(new FileSystemResource(pathname));
@@ -143,7 +145,8 @@ public class MultiTreeWordList implement
    * 
    * @param pathnames
    *          path of the file to create a TextWordList from
-   * @param base - the relative base
+   * @param base
+   *          - the relative base
    * @throws IOException
    *           When there is a problem reading a path.
    */
@@ -157,9 +160,12 @@ public class MultiTreeWordList implement
   }
 
   /**
-   * @param files - the input files
-   * @param base - the relative base
-   * @throws IOException - When there is a problem reading the files.
+   * @param files
+   *          - the input files
+   * @param base
+   *          - the relative base
+   * @throws IOException
+   *           - When there is a problem reading the files.
    */
   public MultiTreeWordList(List<File> files, File base) throws IOException {
     this.root = new MultiTextNode();
@@ -215,7 +221,8 @@ public class MultiTreeWordList implement
       } else if (name.endsWith(".mtwl")) {
         persistence.readMTWL(root, stream, "UTF-8");
       } else {
-        throw new IllegalArgumentException("File name should end with .mtwl or 
.txt, found " + name);
+        throw new IllegalArgumentException(
+                "File name should end with .mtwl or .txt, found " + name);
       }
     } finally {
       IOUtils.closeQuietly(stream);
@@ -225,8 +232,10 @@ public class MultiTreeWordList implement
   /**
    * Creates a new Tree in the existing treeWordList from a file with path 
pathname
    * 
-   * @param stream - Input stream for the file containing the words for the 
treeWordList
-   * @param name - Associated name for the file
+   * @param stream
+   *          - Input stream for the file containing the words for the 
treeWordList
+   * @param name
+   *          - Associated name for the file
    * @throws IOException
    *           When there is a problem reading the inputstream.
    */
@@ -573,8 +582,8 @@ public class MultiTreeWordList implement
     Map<String, Set<String>> resultMap = null;
 
     if (!edit) {
-      return recursiveContains2(root, string, 0, ignoreCase && string.length() 
> ignoreLength,
-              true, ignoreToken.toCharArray(), ignoreLength);
+      return recursiveContains2(root, string, 0, ignoreCase && string.length() 
> ignoreLength, true,
+              ignoreToken.toCharArray(), ignoreLength);
     } else {
       if (string.length() >= ignoreLength && ignoreCase) {
         resultMap = editDistance(string, (int) distance, true, ignoreToken, 
true);
@@ -798,7 +807,7 @@ public class MultiTreeWordList implement
 
     Collection<AnnotationFS> results = new HashSet<AnnotationFS>();
     stream.moveToFirst();
-    FSIterator<AnnotationFS> streamPointer = stream.copy().getCurrentIt();
+    RutaStream streamPointer = stream.copy();
 
     while (stream.isValid()) {
       RutaBasic anchorBasic = (RutaBasic) stream.get();
@@ -823,8 +832,8 @@ public class MultiTreeWordList implement
           }
           List<String> types = null;
           if (!skip) {
-            types = containsFragment(candidate.toString(), ignoreCase, 
ignoreLength, edit,
-                    distance, ignoreToken);
+            types = containsFragment(candidate.toString(), ignoreCase, 
ignoreLength, edit, distance,
+                    ignoreToken);
           }
           if (skip || types != null) {
             streamPointer.moveToNext();
@@ -909,7 +918,7 @@ public class MultiTreeWordList implement
               int end = basicsToAdd.get(basicsToAdd.size() - 1).getEnd();
               AnnotationFS newFS = stream.getCas().createAnnotation(type, 
begin, end);
               Feature feature = type.getFeatureByBaseName(featureString);
-              setFeatureValue(newFS, feature, value);
+              setFeatureValue(newFS, feature, value, stream);
               results.add(newFS);
             }
           }
@@ -920,11 +929,14 @@ public class MultiTreeWordList implement
     }
   }
 
-  private void setFeatureValue(AnnotationFS annotationFS, Feature feature, 
Object o) {
+  private void setFeatureValue(AnnotationFS annotationFS, Feature feature, 
Object o,
+          RutaStream stream) {
+    TypeSystem typeSystem = stream.getCas().getTypeSystem();
     if (feature != null && o != null) {
       Type range = feature.getRange();
       String rangeName = range.getName();
-      if (rangeName.equals(CAS.TYPE_NAME_STRING) && o instanceof String) {
+      if (typeSystem.subsumes(typeSystem.getType(CAS.TYPE_NAME_STRING), range)
+              && o instanceof String) {
         annotationFS.setStringValue(feature, (String) o);
       } else if (rangeName.equals(CAS.TYPE_NAME_INTEGER) && o instanceof 
Number) {
         annotationFS.setIntValue(feature, ((Number) o).intValue());
@@ -940,12 +952,13 @@ public class MultiTreeWordList implement
         annotationFS.setLongValue(feature, ((Number) o).longValue());
       } else if (rangeName.equals(CAS.TYPE_NAME_BOOLEAN) && o instanceof 
Boolean) {
         annotationFS.setBooleanValue(feature, (Boolean) o);
-      } else if (rangeName.equals(CAS.TYPE_NAME_STRING) & o instanceof Type) {
+      } else if (typeSystem.subsumes(typeSystem.getType(CAS.TYPE_NAME_STRING), 
range)
+              & o instanceof Type) {
         annotationFS.setStringValue(feature, ((Type) o).getName());
       }
     } else {
-      throw new IllegalArgumentException("Not able to assign feature value: " 
+ o + " -> "
-              + feature);
+      throw new IllegalArgumentException(
+              "Not able to assign feature value: " + o + " -> " + feature);
     }
   }
 
@@ -953,8 +966,10 @@ public class MultiTreeWordList implement
    * Returns a map with all strings with a specified edit distance to the 
string query as keys and
    * the files they belong to as values.
    * 
-   * @param query - The query string.
-   * @param distance - The specified edit distance.
+   * @param query
+   *          - The query string.
+   * @param distance
+   *          - The specified edit distance.
    * @return A map with all strings with a specified edit distance to the 
string query as keys and
    *         the files they belong to as values.
    */
@@ -966,10 +981,14 @@ public class MultiTreeWordList implement
    * Returns a map with all strings with a specified edit distance to the 
string query as keys and
    * the files they belong to as values.
    * 
-   * @param query - The query string.
-   * @param distance - The specified edit distance.
-   * @param ignoreCase - Indicates whether we search case sensitive or not.
-   * @param ignoreToken - Indicates the characters to ignore
+   * @param query
+   *          - The query string.
+   * @param distance
+   *          - The specified edit distance.
+   * @param ignoreCase
+   *          - Indicates whether we search case sensitive or not.
+   * @param ignoreToken
+   *          - Indicates the characters to ignore
    * @return A map with all strings with a specified edit distance to the 
string query as keys and
    *         the files they belong to as values.
    */
@@ -982,11 +1001,16 @@ public class MultiTreeWordList implement
    * Returns a map with all strings with a specified edit distance to the 
string query as keys and
    * the files they belong to as values.
    * 
-   * @param query - The query string.
-   * @param distance - The specified edit distance.
-   * @param ignoreCase - Indicates whether we search case sensitive or not.
-   * @param ignoreToken - the characters to ignore
-   * @param fragment - Indicates whether we search for fragments of the query 
string or not.
+   * @param query
+   *          - The query string.
+   * @param distance
+   *          - The specified edit distance.
+   * @param ignoreCase
+   *          - Indicates whether we search case sensitive or not.
+   * @param ignoreToken
+   *          - the characters to ignore
+   * @param fragment
+   *          - Indicates whether we search for fragments of the query string 
or not.
    * @return A map with all strings with a specified edit distance to the 
string query as keys and
    *         the files they belong to as values.
    */
@@ -1013,7 +1037,8 @@ public class MultiTreeWordList implement
       result = editDistanceClever(root, query.toLowerCase(), "", distance, 0, 
true, fragment, edcm,
               false, false);
     } else {
-      result = editDistanceClever(root, query, "", distance, 0, false, 
fragment, edcm, false, false);
+      result = editDistanceClever(root, query, "", distance, 0, false, 
fragment, edcm, false,
+              false);
     }
 
     // Restoring of the old insert costs.
@@ -1028,16 +1053,26 @@ public class MultiTreeWordList implement
    * Returns a map with all strings with a specified edit distance to the 
string query as keys and
    * the files they belong to as values.
    * 
-   * @param node - The MultiTextNode which is under consideration at the 
moment.
-   * @param query - The query string.
-   * @param result - The result which matched until now.
-   * @param distance - The remaining edit distance.
-   * @param index - The index of the query string at the moment.
-   * @param ignoreCase - Indicates whether we search case sensitive or not.
-   * @param fragment - Indicates whether we search for fragments of the query 
string or not.
-   * @param edm - The edit distance cost map we are using.
-   * @param lastActionInsert - Indicates whether the last action was an insert 
action.
-   * @param lastActionDelete - Indicates whether the last action was a delete 
action.
+   * @param node
+   *          - The MultiTextNode which is under consideration at the moment.
+   * @param query
+   *          - The query string.
+   * @param result
+   *          - The result which matched until now.
+   * @param distance
+   *          - The remaining edit distance.
+   * @param index
+   *          - The index of the query string at the moment.
+   * @param ignoreCase
+   *          - Indicates whether we search case sensitive or not.
+   * @param fragment
+   *          - Indicates whether we search for fragments of the query string 
or not.
+   * @param edm
+   *          - The edit distance cost map we are using.
+   * @param lastActionInsert
+   *          - Indicates whether the last action was an insert action.
+   * @param lastActionDelete
+   *          - Indicates whether the last action was a delete action.
    * @return A map with all strings with a specified edit distance to the 
string query as keys and
    *         the files they belong to as values.
    */
@@ -1094,8 +1129,8 @@ public class MultiTreeWordList implement
 
       if (index < query.length()) {
         if (ignoreCase) {
-          if (Character.toLowerCase(tempNode.getValue()) == 
Character.toLowerCase(query
-                  .charAt(index))) {
+          if (Character.toLowerCase(tempNode.getValue()) == Character
+                  .toLowerCase(query.charAt(index))) {
             resultMap.putAll(editDistanceClever(tempNode, query, result + 
tempNode.getValue(),
                     distance, index + 1, ignoreCase, fragment, edm, false, 
false));
           }
@@ -1110,9 +1145,9 @@ public class MultiTreeWordList implement
       if (distance - edm.getReplaceCosts(node.getValue(), tempNode.getValue()) 
>= 0) {
 
         // Substitute.
-        resultMap.putAll(editDistanceClever(tempNode, query, result + 
tempNode.getValue(), distance
-                - edm.getReplaceCosts(node.getValue(), tempNode.getValue()), 
index + 1, ignoreCase,
-                fragment, edm, false, false));
+        resultMap.putAll(editDistanceClever(tempNode, query, result + 
tempNode.getValue(),
+                distance - edm.getReplaceCosts(node.getValue(), 
tempNode.getValue()), index + 1,
+                ignoreCase, fragment, edm, false, false));
       }
 
       if (!lastActionDelete) {
@@ -1131,19 +1166,27 @@ public class MultiTreeWordList implement
   /**
    * Checks if a string is contained by the MultiTreeWordList.
    * 
-   * @param node - The MultiTextNode which is under consideration at the 
moment.
-   * @param query - The query string.
-   * @param result - The result which matched until now.
-   * @param distance - The remaining edit distance.
-   * @param index - The index of the query string at the moment.
-   * @param ignoreCase - Indicates whether we search case sensitive or not.
-   * @param fragment - Indicates whether we search for fragments of the query 
string or not.
-   * @param edm - The edit distance cost map we are using.
+   * @param node
+   *          - The MultiTextNode which is under consideration at the moment.
+   * @param query
+   *          - The query string.
+   * @param result
+   *          - The result which matched until now.
+   * @param distance
+   *          - The remaining edit distance.
+   * @param index
+   *          - The index of the query string at the moment.
+   * @param ignoreCase
+   *          - Indicates whether we search case sensitive or not.
+   * @param fragment
+   *          - Indicates whether we search for fragments of the query string 
or not.
+   * @param edm
+   *          - The edit distance cost map we are using.
    * @return A map with all strings with a specified edit distance to the 
string query as keys and
    *         the files they belong to as values.
    */
-  private boolean editDistanceBool(MultiTextNode node, String query, String 
result,
-          double distance, int index, boolean ignoreCase, boolean fragment, 
EditDistanceCostMap edm) {
+  private boolean editDistanceBool(MultiTextNode node, String query, String 
result, double distance,
+          int index, boolean ignoreCase, boolean fragment, EditDistanceCostMap 
edm) {
 
     boolean deletion = false;
     boolean insertion = false;
@@ -1188,8 +1231,8 @@ public class MultiTreeWordList implement
 
       if (index < query.length()) {
         if (ignoreCase) {
-          if (Character.toLowerCase(tempNode.getValue()) == 
Character.toLowerCase(query
-                  .charAt(index))) {
+          if (Character.toLowerCase(tempNode.getValue()) == Character
+                  .toLowerCase(query.charAt(index))) {
             noop = editDistanceBool(tempNode, query, result + 
tempNode.getValue(), distance,
                     index + 1, ignoreCase, fragment, edm);
           }
@@ -1208,9 +1251,9 @@ public class MultiTreeWordList implement
       if (distance - edm.getReplaceCosts(node.getValue(), tempNode.getValue()) 
>= 0) {
 
         // Substitute.
-        substitution = editDistanceBool(tempNode, query, result + 
tempNode.getValue(), distance
-                - edm.getReplaceCosts(node.getValue(), tempNode.getValue()), 
index + 1, ignoreCase,
-                fragment, edm);
+        substitution = editDistanceBool(tempNode, query, result + 
tempNode.getValue(),
+                distance - edm.getReplaceCosts(node.getValue(), 
tempNode.getValue()), index + 1,
+                ignoreCase, fragment, edm);
 
         if (substitution) {
           return true;
@@ -1233,7 +1276,6 @@ public class MultiTreeWordList implement
     return false;
   }
 
-
   @Override
   public int hashCode() {
     final int prime = 31;

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/MultiTreeWordListPersistence.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/MultiTreeWordListPersistence.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/MultiTreeWordListPersistence.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/MultiTreeWordListPersistence.java
 Wed Jan 16 11:45:02 2019
@@ -32,10 +32,9 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 
-import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
 
+import org.apache.uima.ruta.utils.XmlUtils;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
@@ -90,18 +89,16 @@ public class MultiTreeWordListPersistenc
       }
       InputStreamReader streamReader = new InputStreamReader(is, encoding);
       TrieXMLEventHandler handler = new TrieXMLEventHandler(root);
-      SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
-      SAXParser saxParser = saxParserFactory.newSAXParser();
+      SAXParser saxParser = XmlUtils.createSaxParser();
       XMLReader reader = saxParser.getXMLReader();
-      // was:
-      // XMLReader reader = XMLReaderFactory.createXMLReader();
+      
reader.setFeature("http://xml.org/sax/features/external-general-entities";, 
false);
+      
reader.setFeature("http://xml.org/sax/features/external-parameter-entities";, 
false);
+      
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false);
       reader.setContentHandler(handler);
       reader.setErrorHandler(handler);
       reader.parse(new InputSource(streamReader));
     } catch (SAXException e) {
-      e.printStackTrace();
-    } catch (ParserConfigurationException e) {
-      e.printStackTrace();
+     throw new IllegalStateException(e);
     }
   }
 

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/RutaTable.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/RutaTable.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/RutaTable.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/RutaTable.java
 Wed Jan 16 11:45:02 2019
@@ -29,6 +29,6 @@ public interface RutaTable {
 
   String getEntry(int row, int column);
 
-  List<String> getRowWhere(int column, String value);
+  List<String> getRowWhere(int column, String value, boolean ignoreCase);
 
 }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/TreeWordList.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/TreeWordList.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/TreeWordList.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/resource/TreeWordList.java
 Wed Jan 16 11:45:02 2019
@@ -36,21 +36,18 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 
-import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
 
 import org.apache.commons.lang3.StringEscapeUtils;
-import org.apache.uima.cas.FSIterator;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.jcas.tcas.Annotation;
 import org.apache.uima.ruta.RutaStream;
 import org.apache.uima.ruta.type.RutaBasic;
+import org.apache.uima.ruta.utils.XmlUtils;
 import org.springframework.core.io.FileSystemResource;
 import org.springframework.core.io.Resource;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
 import org.xml.sax.XMLReader;
 
 public class TreeWordList implements RutaWordList {
@@ -70,10 +67,14 @@ public class TreeWordList implements Rut
   /**
    * Constructs a TreeWordList from a resource.
    * 
-   * @param resource - Resource to create a TextWordList from
-   * @param dictRemoveWS - option to remove whitespaces fromt he resource
-   * @throws IOException - when there is a problem reading the resource
-   * @throws IllegalArgumentException - for an invalid name or file ending
+   * @param resource
+   *          - Resource to create a TextWordList from
+   * @param dictRemoveWS
+   *          - option to remove whitespaces fromt he resource
+   * @throws IOException
+   *           - when there is a problem reading the resource
+   * @throws IllegalArgumentException
+   *           - for an invalid name or file ending
    */
   public TreeWordList(Resource resource, boolean dictRemoveWS) throws 
IOException {
     this.dictRemoveWS = dictRemoveWS;
@@ -102,9 +103,12 @@ public class TreeWordList implements Rut
   /**
    * Constructs a TreeWordList from a file with path = filename
    * 
-   * @param pathname - path of the file to create a TextWordList from
-   * @param dictRemoveWS - remove whitespaces    
-   * @throws IOException - when there is a problem reading the pathname
+   * @param pathname
+   *          - path of the file to create a TextWordList from
+   * @param dictRemoveWS
+   *          - remove whitespaces
+   * @throws IOException
+   *           - when there is a problem reading the pathname
    */
   public TreeWordList(String pathname, boolean dictRemoveWS) throws 
IOException {
     this(new FileSystemResource(pathname), dictRemoveWS);
@@ -115,9 +119,12 @@ public class TreeWordList implements Rut
    * 
    * @param stream
    *          path of the file to create a TextWordList from
-   * @param name - the name of the resource in the stream
-   * @param dictRemoveWS - remove whitespaces    
-   * @throws IOException - when there is a problem reading the stream
+   * @param name
+   *          - the name of the resource in the stream
+   * @param dictRemoveWS
+   *          - remove whitespaces
+   * @throws IOException
+   *           - when there is a problem reading the stream
    */
   public TreeWordList(InputStream stream, String name, boolean dictRemoveWS) 
throws IOException {
     this.dictRemoveWS = dictRemoveWS;
@@ -149,7 +156,8 @@ public class TreeWordList implements Rut
    * @param stream
    *          Open InputStream containing the word for the treeWordList, this 
method will close the
    *          stream.
-   * @throws IOException - when there is a problem reading the stream
+   * @throws IOException
+   *           - when there is a problem reading the stream
    */
   public void buildNewTree(InputStream stream) throws IOException {
     Scanner scan = new Scanner(stream, "UTF-8");
@@ -266,9 +274,11 @@ public class TreeWordList implements Rut
                 maxIgnoreChars, ignoreWS);
       } else {
         result |= recursiveContains(childNodeL, text, next, ignoreCase, 
fragment, ignoreChars,
-                maxIgnoreChars, ignoreWS)
-                | recursiveContains(childNodeU, text, next, ignoreCase, 
fragment, ignoreChars,
-                        maxIgnoreChars, ignoreWS);
+                maxIgnoreChars, ignoreWS);
+        if (childNodeL != childNodeU) { // Do not go into the same tree.
+          result |= recursiveContains(childNodeU, text, next, ignoreCase, 
fragment, ignoreChars,
+                  maxIgnoreChars, ignoreWS);
+        }
       }
     } else {
       TextNode wsNode = pointer.getChildNode(' ');
@@ -310,7 +320,7 @@ public class TreeWordList implements Rut
           char[] ignoreChars, int maxIgnoredChars, boolean ignoreWS) {
     ArrayList<AnnotationFS> results = new ArrayList<AnnotationFS>();
     stream.moveToFirst();
-    FSIterator<AnnotationFS> streamPointer = stream.copy().getCurrentIt();
+    RutaStream streamPointer = stream.copy();
     while (stream.isValid()) {
       RutaBasic anchorBasic = (RutaBasic) stream.get();
       streamPointer.moveTo(anchorBasic);
@@ -352,7 +362,8 @@ public class TreeWordList implements Rut
     return results;
   }
 
-  public List<AnnotationFS> find(RutaStream stream, boolean ignoreCase, int 
size, boolean ignoreWS) {
+  public List<AnnotationFS> find(RutaStream stream, boolean ignoreCase, int 
size,
+          boolean ignoreWS) {
     return find(stream, ignoreCase, size, null, 0, ignoreWS);
   }
 
@@ -362,8 +373,8 @@ public class TreeWordList implements Rut
     if (basicsToAdd.size() >= 1
             && contains(lastCandidate, ignoreCase, size, ignoreChars, 
maxIgnoredChars, ignoreWS)) {
 
-      results.add(new Annotation(stream.getJCas(), 
basicsToAdd.get(0).getBegin(), basicsToAdd.get(
-              basicsToAdd.size() - 1).getEnd()));
+      results.add(new Annotation(stream.getJCas(), 
basicsToAdd.get(0).getBegin(),
+              basicsToAdd.get(basicsToAdd.size() - 1).getEnd()));
     } else if (interResult != null) {
       results.add(interResult);
     }
@@ -380,25 +391,16 @@ public class TreeWordList implements Rut
       InputStreamReader streamReader = new InputStreamReader(is, encoding);
       this.root = new TextNode();
       XMLEventHandler handler = new XMLEventHandler(root);
-      SAXParserFactory factory = SAXParserFactory.newInstance();
-      SAXParser parser = factory.newSAXParser();
+      SAXParser parser = XmlUtils.createSaxParser();
       XMLReader reader = parser.getXMLReader();
-      // XMLReader reader = XMLReaderFactory.createXMLReader();
+      
reader.setFeature("http://xml.org/sax/features/external-general-entities";, 
false);
+      
reader.setFeature("http://xml.org/sax/features/external-parameter-entities";, 
false);
+      
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd";,
 false);
       reader.setContentHandler(handler);
       reader.setErrorHandler(handler);
       reader.parse(new InputSource(streamReader));
-    } catch (SAXParseException spe) {
-      StringBuffer sb = new StringBuffer(spe.toString());
-      sb.append("\n  Line number: " + spe.getLineNumber());
-      sb.append("\n Column number: " + spe.getColumnNumber());
-      sb.append("\n Public ID: " + spe.getPublicId());
-      sb.append("\n System ID: " + spe.getSystemId() + "\n");
-      System.out.println(sb.toString());
-    } catch (SAXException se) {
-      System.out.println("loadDOM threw " + se);
-      se.printStackTrace(System.out);
-    } catch (ParserConfigurationException e) {
-      e.printStackTrace();
+    } catch (SAXException e) {
+      throw new IllegalStateException(e);
     }
   }
 
@@ -451,8 +453,8 @@ public class TreeWordList implements Rut
 
   public void writeNode(Writer writer, TextNode node) throws IOException {
     String value = 
StringEscapeUtils.escapeXml11(String.valueOf(node.getValue()));
-    String output = "<node char=\"" + value + "\" isWordEnd=\""
-            + Boolean.toString(node.isWordEnd()) + "\">";
+    String output = "<node char=\"" + value + "\" isWordEnd=\"" + 
Boolean.toString(node.isWordEnd())
+            + "\">";
     writer.write(output);
     for (TextNode child : node.getChildren().values()) {
       writeNode(writer, child);
@@ -467,8 +469,8 @@ public class TreeWordList implements Rut
   }
 
   @Override
-  public List<AnnotationFS> find(RutaStream stream, Map<String, Object> 
typeMap,
-          boolean ignoreCase, int ignoreLength, boolean edit, double distance, 
String ignoreToken) {
+  public List<AnnotationFS> find(RutaStream stream, Map<String, Object> 
typeMap, boolean ignoreCase,
+          int ignoreLength, boolean edit, double distance, String ignoreToken) 
{
     return null;
   }
 

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java
 Wed Jan 16 11:45:02 2019
@@ -54,9 +54,9 @@ public abstract class AbstractRuleElemen
   @SuppressWarnings("unchecked")
   protected final InferenceCrowd emptyCrowd = new 
InferenceCrowd(Collections.EMPTY_LIST);
 
-  protected List<RutaStatement> inlinedConditionRules;
+  protected List<List<RutaStatement>> inlinedConditionRuleBlocks = new 
ArrayList<>();
 
-  protected List<RutaStatement> inlinedActionRules;
+  protected List<List<RutaStatement>> inlinedActionRuleBlocks = new 
ArrayList<>();
 
   public AbstractRuleElement(RuleElementQuantifier quantifier,
           List<AbstractRutaCondition> conditions, List<AbstractRutaAction> 
actions,
@@ -81,7 +81,7 @@ public abstract class AbstractRuleElemen
   protected void doneMatching(RuleMatch ruleMatch, RuleApply ruleApply, 
RutaStream stream,
           InferenceCrowd crowd) {
     if (!ruleMatch.isApplied()) {
-      ruleApply.add(ruleMatch);
+      ruleApply.add(ruleMatch, stream);
       if (ruleMatch.matchedCompletely()) {
         ruleMatch.getRule().getRoot().applyRuleElements(ruleMatch, stream, 
crowd);
       }
@@ -89,25 +89,25 @@ public abstract class AbstractRuleElemen
     }
   }
 
-  protected List<ScriptApply> processInlinedActionRules(RuleMatch ruleMatch, 
RutaStream stream,
+  protected List<List<ScriptApply>> processInlinedActionRules(RuleMatch 
ruleMatch, RutaStream stream,
           InferenceCrowd crowd) {
-    if (inlinedActionRules != null && !inlinedActionRules.isEmpty()) {
-      return processInlinedRules(inlinedActionRules, ruleMatch, stream, crowd);
+    if (inlinedActionRuleBlocks != null && !inlinedActionRuleBlocks.isEmpty()) 
{
+      return processInlinedRules(inlinedActionRuleBlocks, ruleMatch, stream, 
crowd);
     }
     return null;
   }
 
-  protected List<ScriptApply> processInlinedConditionRules(RuleMatch 
ruleMatch, RutaStream stream,
+  protected List<List<ScriptApply>> processInlinedConditionRules(RuleMatch 
ruleMatch, RutaStream stream,
           InferenceCrowd crowd) {
-    if (inlinedConditionRules != null && !inlinedConditionRules.isEmpty()) {
-      return processInlinedRules(inlinedConditionRules, ruleMatch, stream, 
crowd);
+    if (inlinedConditionRuleBlocks != null && 
!inlinedConditionRuleBlocks.isEmpty()) {
+      return processInlinedRules(inlinedConditionRuleBlocks, ruleMatch, 
stream, crowd);
     }
     return null;
   }
 
-  protected List<ScriptApply> processInlinedRules(List<RutaStatement> 
inlinedRules,
+  protected List<List<ScriptApply>> 
processInlinedRules(List<List<RutaStatement>> inlinedRuleBlocks,
           RuleMatch ruleMatch, RutaStream stream, InferenceCrowd crowd) {
-    List<ScriptApply> result = new ArrayList<ScriptApply>();
+    List<List<ScriptApply>> result = new ArrayList<>();
     List<AnnotationFS> matchedAnnotationsOf = 
ruleMatch.getMatchedAnnotationsOfElement(this);
     // TODO where to implement the explanation of inlined rules?
     // BlockApply blockApply = new BlockApply(this);
@@ -116,11 +116,15 @@ public abstract class AbstractRuleElemen
     // ruleMatch.addDelegateApply(this, blockApply);
     for (AnnotationFS annotationFS : matchedAnnotationsOf) {
       RutaStream windowStream = stream.getWindowStream(annotationFS, 
annotationFS.getType());
-      for (RutaStatement each : inlinedRules) {
-        ScriptApply apply = each.apply(windowStream, crowd);
-        // blockApply.add(apply);
-        ruleMatch.addDelegateApply(this, apply);
-        result.add(apply);
+      for (List<RutaStatement> inlinedRules : inlinedRuleBlocks) {
+        List<ScriptApply> blockResult = new ArrayList<>();
+        for (RutaStatement each : inlinedRules) {
+          ScriptApply apply = each.apply(windowStream, crowd);
+          // blockApply.add(apply);
+          ruleMatch.addDelegateApply(this, apply);
+          blockResult.add(apply);
+        }
+        result.add(blockResult);
       }
     }
     return result;
@@ -137,20 +141,29 @@ public abstract class AbstractRuleElemen
   }
 
   protected boolean matchInnerRules(RuleMatch ruleMatch, RutaStream stream, 
InferenceCrowd crowd) {
-    boolean inlinedRulesMatched = true;
-    List<ScriptApply> list = processInlinedConditionRules(ruleMatch, stream, 
crowd);
-    if (list != null) {
-      inlinedRulesMatched = false;
-      for (ScriptApply scriptApply : list) {
-        if (scriptApply instanceof RuleApply) {
-          RuleApply ra = (RuleApply) scriptApply;
-          if (ra.applied > 0) {
-            inlinedRulesMatched = true;
-          }
+
+    List<List<ScriptApply>> blockResults = 
processInlinedConditionRules(ruleMatch, stream, crowd);
+    if (blockResults == null) {
+      return true;
+    }
+    
+    boolean matched = true;
+    for (List<ScriptApply> list : blockResults) {
+      matched &= atLeastOneRuleMatched(list);
+    }
+    return matched;
+  }
+
+  private boolean atLeastOneRuleMatched(List<ScriptApply> list) {
+    for (ScriptApply scriptApply : list) {
+      if (scriptApply instanceof RuleApply) {
+        RuleApply ra = (RuleApply) scriptApply;
+        if (ra.applied > 0) {
+          return true;
         }
       }
     }
-    return inlinedRulesMatched;
+    return false;
   }
 
   protected List<RuleElementMatch> getMatch(RuleMatch ruleMatch,
@@ -210,7 +223,12 @@ public abstract class AbstractRuleElemen
     return false;
   }
 
-  private boolean isAlreadyCovered(AnnotationFS eachAnchor, RuleApply 
ruleApply, RutaStream stream) {
+  private boolean isAlreadyCovered(AnnotationFS eachAnchor, RuleApply 
ruleApply,
+          RutaStream stream) {
+    if (eachAnchor == null) {
+      return false;
+    }
+
     List<AbstractRuleMatch<? extends AbstractRule>> list = ruleApply.getList();
     Collections.reverse(list);
     for (AbstractRuleMatch<? extends AbstractRule> each : list) {
@@ -304,23 +322,23 @@ public abstract class AbstractRuleElemen
   }
 
   @Override
-  public void setInlinedConditionRules(List<RutaStatement> innerRules) {
-    this.inlinedConditionRules = innerRules;
+  public void addInlinedConditionRules(List<RutaStatement> innerRules) {
+    this.inlinedConditionRuleBlocks.add(innerRules);
   }
 
   @Override
-  public List<RutaStatement> getInlinedConditionRules() {
-    return inlinedConditionRules;
+  public List<List<RutaStatement>> getInlinedConditionRuleBlocks() {
+    return inlinedConditionRuleBlocks;
   }
 
   @Override
-  public void setInlinedActionRules(List<RutaStatement> innerRules) {
-    this.inlinedActionRules = innerRules;
+  public void addInlinedActionRules(List<RutaStatement> innerRules) {
+    this.inlinedActionRuleBlocks.add(innerRules);
   }
 
   @Override
-  public List<RutaStatement> getInlinedActionRules() {
-    return inlinedActionRules;
+  public List<List<RutaStatement>> getInlinedActionRuleBlocks() {
+    return inlinedActionRuleBlocks;
   }
 
 }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElement.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElement.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElement.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElement.java
 Wed Jan 16 11:45:02 2019
@@ -32,6 +32,7 @@ import java.util.TreeMap;
 
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.jcas.JCas;
+import org.apache.uima.ruta.RutaEnvironment;
 import org.apache.uima.ruta.RutaStream;
 import org.apache.uima.ruta.action.AbstractRutaAction;
 import org.apache.uima.ruta.block.RutaBlock;
@@ -552,7 +553,8 @@ public class ComposedRuleElement extends
             begin, end);
 
     MatchContext context = new MatchContext(annotation, this, ruleMatch, 
after);
-    context.getParent().getEnvironment().addMatchToVariable(ruleMatch, this, 
context, stream);
+    RutaEnvironment environment = context.getParent().getEnvironment();
+    environment.addMatchToVariable(ruleMatch, this, context, stream);
 
     List<EvaluatedCondition> evaluatedConditions = new 
ArrayList<EvaluatedCondition>(
             conditions.size());
@@ -567,8 +569,13 @@ public class ComposedRuleElement extends
     }
     match.setConditionInfo(evaluatedConditions);
     match.evaluateInnerMatches(true, stream);
-    boolean inlinedRulesMatched = matchInnerRules(ruleMatch, stream, crowd);
-    match.setInlinedRulesMatched(inlinedRulesMatched);
+    if (match.matched()) {
+      boolean inlinedRulesMatched = matchInnerRules(ruleMatch, stream, crowd);
+      match.setInlinedRulesMatched(inlinedRulesMatched);
+    } else {
+      // update label for failed match after evaluating conditions
+      environment.addAnnotationsToVariable(null, getLabel(), context);
+    }
   }
 
   @Override

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElementMatch.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElementMatch.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElementMatch.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ComposedRuleElementMatch.java
 Wed Jan 16 11:45:02 2019
@@ -29,6 +29,7 @@ import java.util.TreeMap;
 import java.util.TreeSet;
 
 import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.ruta.RutaProcessRuntimeException;
 import org.apache.uima.ruta.RutaStream;
 
 public class ComposedRuleElementMatch extends RuleElementMatch {
@@ -79,6 +80,11 @@ public class ComposedRuleElementMatch ex
       innerMatches.put(ruleElement, list);
     }
     list.add(ruleElementMatch);
+
+    if (list.size() > stream.getMaxRuleElementMatches()) {
+      throw new RutaProcessRuntimeException("Rule element exceeded the allowed 
amount of matches ("
+              + stream.getMaxRuleElementMatches() + "): " + 
ruleElement.toString());
+    }
     evaluateInnerMatches(included, stream);
     enforceUpdate();
   }

Modified: 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ConjunctRulesRuleElement.java
URL: 
http://svn.apache.org/viewvc/uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ConjunctRulesRuleElement.java?rev=1851430&r1=1851429&r2=1851430&view=diff
==============================================================================
--- 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ConjunctRulesRuleElement.java
 (original)
+++ 
uima/uv3/ruta-v3/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/ConjunctRulesRuleElement.java
 Wed Jan 16 11:45:02 2019
@@ -58,10 +58,10 @@ public class ConjunctRulesRuleElement ex
         }
       }
       allMatched &= oneMatched;
-      
+
       // only the matches that actually matched successfully
       for (RuleMatch eachRuleMatch : startMatch) {
-        if(eachRuleMatch.matched()) {
+        if (eachRuleMatch.matched()) {
           result.add(eachRuleMatch);
         }
       }
@@ -70,7 +70,7 @@ public class ConjunctRulesRuleElement ex
     for (RuleMatch each : result) {
       if (!each.isApplied()) {
         each.setMatched(allMatched);
-        ruleApply.add(each);
+        ruleApply.add(each, stream);
         if (each.matched() && allMatched) {
           each.getRule().getRoot().applyRuleElements(each, stream, crowd);
         }


Reply via email to