You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by pk...@apache.org on 2015/10/20 19:14:16 UTC

svn commit: r1709649 - in /uima/ruta/trunk: ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/ ruta-core/src/main/java/org/apache/uima/ruta/ ruta-core/src/main/java/org/apache/uima/ruta/action/ ruta-core/src/test/java/org/apache/uima/ruta/action/ r...

Author: pkluegl
Date: Tue Oct 20 17:14:15 2015
New Revision: 1709649

URL: http://svn.apache.org/viewvc?rev=1709649&view=rev
Log:
UIMA-4633
- initial implementation of action (first part)

Added:
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/SplitAction.java   (with props)
    uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/action/SplitTest.java   (with props)
Modified:
    uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g
    uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/ActionFactory.java
    uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g
    uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g

Modified: uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g?rev=1709649&r1=1709648&r2=1709649&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g (original)
+++ uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g Tue Oct 20 17:14:15 2015
@@ -252,6 +252,10 @@ SHIFT
 	:	'SHIFT'	 
 	;
 
+SPLIT   
+  : 'SPLIT'  
+  ;
+
 DYNAMICANCHORING 	
 	:	'DYNAMICANCHORING'	 
 	;

Modified: uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g?rev=1709649&r1=1709648&r2=1709649&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g (original)
+++ uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g Tue Oct 20 17:14:15 2015
@@ -1526,6 +1526,7 @@ action  returns [AbstractRutaAction resu
 	| a = actionMatchedText
 	| a = actionClear
 	| a = actionShift
+	| a = actionSplit
 	| a = actionConfigure
 	| a = actionDynamicAnchoring
 	| a = actionGreedyAnchoring
@@ -1724,6 +1725,25 @@ List<INumberExpression> list = new Array
     {action = ActionFactory.createMarkAction(null, type, list, $blockDeclaration::env);}
     ;
 
+actionSplit returns [AbstractRutaAction action = null]
+	:
+	SPLIT 
+	LPAREN
+	type = typeExpression
+	(
+	COMMA
+	complete = booleanExpression
+	(
+	COMMA
+	appendToBegin = booleanExpression
+	COMMA
+	appendToEnd = booleanExpression
+	)?
+	)? 
+	RPAREN
+	{action = ActionFactory.createSplitAction(type, complete, appendToBegin, appendToEnd, $blockDeclaration::env);}
+	;
+	
 actionShift returns [AbstractRutaAction action = null]
 @init {
 List<INumberExpression> list = new ArrayList<INumberExpression>();

Modified: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java?rev=1709649&r1=1709648&r2=1709649&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java (original)
+++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaStream.java Tue Oct 20 17:14:15 2015
@@ -229,7 +229,7 @@ public class RutaStream extends FSIterat
 
   public void addAnnotation(AnnotationFS annotation, boolean addToIndex,
           AbstractRuleMatch<? extends AbstractRule> creator) {
-    addAnnotation(annotation, true, true, creator);
+    addAnnotation(annotation, addToIndex, true, creator);
   }
 
   public void addAnnotation(AnnotationFS annotation,

Modified: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/ActionFactory.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/ActionFactory.java?rev=1709649&r1=1709648&r2=1709649&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/ActionFactory.java (original)
+++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/ActionFactory.java Tue Oct 20 17:14:15 2015
@@ -274,4 +274,10 @@ public class ActionFactory {
     return new GreedyAnchoringAction(active, active2);
   }
 
+  public static AbstractRutaAction createSplitAction(TypeExpression type,
+          IBooleanExpression complete, IBooleanExpression appendToBegin,
+          IBooleanExpression appendToEnd, RutaBlock env) {
+    return new SplitAction(type, complete, appendToBegin, appendToEnd);
+  }
+
 }

Added: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/SplitAction.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/SplitAction.java?rev=1709649&view=auto
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/SplitAction.java (added)
+++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/SplitAction.java Tue Oct 20 17:14:15 2015
@@ -0,0 +1,157 @@
+/*
+ * 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.apache.uima.ruta.action;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.jcas.tcas.Annotation;
+import org.apache.uima.ruta.RutaBlock;
+import org.apache.uima.ruta.RutaStream;
+import org.apache.uima.ruta.expression.bool.IBooleanExpression;
+import org.apache.uima.ruta.expression.bool.SimpleBooleanExpression;
+import org.apache.uima.ruta.expression.type.TypeExpression;
+import org.apache.uima.ruta.rule.RuleElement;
+import org.apache.uima.ruta.rule.RuleMatch;
+import org.apache.uima.ruta.type.RutaBasic;
+import org.apache.uima.ruta.visitor.InferenceCrowd;
+import org.apache.uima.util.CasCopier;
+
+public class SplitAction extends AbstractRutaAction {
+
+  private TypeExpression splitOnType;
+
+  private IBooleanExpression complete;
+
+  private IBooleanExpression appendToBegin;
+
+  private IBooleanExpression appendToEnd;
+
+  public SplitAction(TypeExpression splitOnType, IBooleanExpression complete,
+          IBooleanExpression appendToBegin, IBooleanExpression appendToEnd) {
+    super();
+    this.splitOnType = splitOnType;
+    this.complete = complete == null ? new SimpleBooleanExpression(true) : complete;
+    this.appendToBegin = appendToBegin == null ? new SimpleBooleanExpression(false) : appendToBegin;
+    this.appendToEnd = appendToEnd == null ? new SimpleBooleanExpression(false) : appendToEnd;
+  }
+
+  @Override
+  public void execute(RuleMatch match, RuleElement element, RutaStream stream, InferenceCrowd crowd) {
+    List<AnnotationFS> matchedAnnotationsOf = match.getMatchedAnnotationsOf(element);
+    RutaBlock parent = element.getParent();
+    Type typeToSplit = splitOnType.getType(parent);
+    boolean splitOnCompleteAnnotation = complete.getBooleanValue(parent, match, element, stream);
+    boolean addToBegin = appendToBegin.getBooleanValue(parent, match, element, stream);
+    boolean addToEnd = appendToEnd.getBooleanValue(parent, match, element, stream);
+    for (AnnotationFS annotation : matchedAnnotationsOf) {
+      splitAnnotation(annotation, typeToSplit, splitOnCompleteAnnotation, addToBegin, addToEnd,
+              match, stream);
+    }
+  }
+
+  private void splitAnnotation(AnnotationFS annotation, Type typeToSplit,
+          boolean splitOnCompleteAnnotation, boolean addToBegin, boolean addToEnd, RuleMatch match,
+          RutaStream stream) {
+
+    if (annotation instanceof Annotation) {
+
+      if (splitOnCompleteAnnotation) {
+        splitAnnotationOnComplete((Annotation) annotation, typeToSplit, addToBegin, addToEnd,
+                match, stream);
+      } else {
+        splitAnnotationOnBoundary((Annotation) annotation, typeToSplit, addToBegin, addToEnd,
+                match, stream);
+      }
+    }
+  }
+
+  private void splitAnnotationOnComplete(Annotation annotation, Type typeToSplit,
+          boolean addToBegin, boolean addToEnd, RuleMatch match, RutaStream stream) {
+    List<AnnotationFS> annotationsInWindow = stream.getAnnotationsInWindow(annotation, typeToSplit);
+    if (annotationsInWindow == null || annotationsInWindow.isEmpty()) {
+      return;
+    }
+
+    CAS cas = annotation.getCAS();
+    CasCopier cc = new CasCopier(cas, cas);
+
+    cas.removeFsFromIndexes(annotation);
+
+    int overallEnd = annotation.getEnd();
+    Annotation first = annotation;
+
+    for (AnnotationFS each : annotationsInWindow) {
+      int firstEnd = addToEnd ? each.getEnd() : each.getBegin();
+      first.setEnd(firstEnd);
+      boolean valid = trimInvisible(first, stream);
+      if (valid) {
+        stream.addAnnotation(first, true, true, match);
+      }
+
+      Annotation second = (Annotation) cc.copyFs(first);
+      int secondBegin = addToBegin ? each.getBegin() : each.getEnd();
+      second.setBegin(secondBegin);
+      second.setEnd(overallEnd);
+      valid = trimInvisible(second, stream);
+      if (valid) {
+        stream.addAnnotation(second, true, true, match);
+      }
+      first = second;
+    }
+
+  }
+
+  private void splitAnnotationOnBoundary(Annotation annotation, Type typeToSplit,
+          boolean addToBegin, boolean addToEnd, RuleMatch match, RutaStream stream) {
+    // TODO implement it
+  }
+
+  private boolean trimInvisible(Annotation annotation, RutaStream stream) {
+    List<RutaBasic> basics = new ArrayList<>(stream.getAllBasicsInWindow(annotation));
+    int min = annotation.getEnd();
+    int max = annotation.getBegin();
+    
+    for (RutaBasic each : basics) {
+      if (stream.isVisible(each)) {
+        min = Math.min(min, each.getBegin());
+        break;
+      }
+    }
+    Collections.reverse(basics);
+    for (RutaBasic each : basics) {
+      if (stream.isVisible(each)) {
+        max = Math.max(max, each.getEnd());
+        break;
+      }
+    }
+    if (min < max) {
+      annotation.setBegin(min);
+      annotation.setEnd(max);
+      return true;
+    }
+    return false;
+  }
+
+}

Propchange: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/SplitAction.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/action/SplitTest.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/action/SplitTest.java?rev=1709649&view=auto
==============================================================================
--- uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/action/SplitTest.java (added)
+++ uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/action/SplitTest.java Tue Oct 20 17:14:15 2015
@@ -0,0 +1,284 @@
+/*
+ * 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.apache.uima.ruta.action;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.FSIterator;
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.cas.text.AnnotationIndex;
+import org.apache.uima.ruta.engine.Ruta;
+import org.apache.uima.ruta.engine.RutaTestUtils;
+import org.apache.uima.ruta.engine.RutaTestUtils.TestFeature;
+import org.junit.Test;
+
+public class SplitTest {
+
+  @Test
+  public void testDefault() {
+    String document = "Some text. More text , with 1 , and more. even more text.";
+    String script = "PERIOD #{-> T1} PERIOD;";
+    script += " #{-> T1} PERIOD;";
+    script += "T1{CONTAINS(NUM)-> CREATE(Complex, \"number\"= NUM)};";
+    script += "Complex{-> SPLIT(COMMA)};";
+
+    Map<String, String> typeMap = new TreeMap<String, String>();
+    String typeName = "Complex";
+    typeMap.put(typeName, "uima.tcas.Annotation");
+
+    Map<String, List<TestFeature>> featureMap = new TreeMap<String, List<TestFeature>>();
+    List<TestFeature> list = new ArrayList<RutaTestUtils.TestFeature>();
+    featureMap.put(typeName, list);
+    String fn = "number";
+    list.add(new TestFeature(fn, "", "uima.tcas.Annotation"));
+
+    CAS cas = null;
+    try {
+      cas = RutaTestUtils.getCAS(document, typeMap, featureMap);
+      Ruta.apply(cas, script);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    Type t = null;
+    AnnotationIndex<AnnotationFS> ai = null;
+    FSIterator<AnnotationFS> iterator = null;
+
+    t = cas.getTypeSystem().getType(typeName);
+    Feature f1 = t.getFeatureByBaseName(fn);
+    ai = cas.getAnnotationIndex(t);
+       
+    assertEquals(3, ai.size());
+    iterator = ai.iterator();
+    AnnotationFS next = iterator.next();
+    assertEquals("More text", next.getCoveredText());
+    FeatureStructure featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    next = iterator.next();
+    assertEquals("with 1", next.getCoveredText());
+    featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    next = iterator.next();
+    assertEquals("and more", next.getCoveredText());
+    featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    if (cas != null) {
+      cas.release();
+    }
+
+  }
+  
+  @Test
+  public void testAddBegin() {
+    String document = "Some text. More text , with 1 , and more. even more text.";
+    String script = "PERIOD #{-> T1} PERIOD;";
+    script += " #{-> T1} PERIOD;";
+    script += "T1{CONTAINS(NUM)-> CREATE(Complex, \"number\"= NUM)};";
+    script += "Complex{-> SPLIT(COMMA, true, true, false)};";
+
+    Map<String, String> typeMap = new TreeMap<String, String>();
+    String typeName = "Complex";
+    typeMap.put(typeName, "uima.tcas.Annotation");
+
+    Map<String, List<TestFeature>> featureMap = new TreeMap<String, List<TestFeature>>();
+    List<TestFeature> list = new ArrayList<RutaTestUtils.TestFeature>();
+    featureMap.put(typeName, list);
+    String fn = "number";
+    list.add(new TestFeature(fn, "", "uima.tcas.Annotation"));
+
+    CAS cas = null;
+    try {
+      cas = RutaTestUtils.getCAS(document, typeMap, featureMap);
+      Ruta.apply(cas, script);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    Type t = null;
+    AnnotationIndex<AnnotationFS> ai = null;
+    FSIterator<AnnotationFS> iterator = null;
+
+    t = cas.getTypeSystem().getType(typeName);
+    Feature f1 = t.getFeatureByBaseName(fn);
+    ai = cas.getAnnotationIndex(t);
+       
+    assertEquals(3, ai.size());
+    iterator = ai.iterator();
+    AnnotationFS next = iterator.next();
+    assertEquals("More text", next.getCoveredText());
+    FeatureStructure featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    next = iterator.next();
+    assertEquals(", with 1", next.getCoveredText());
+    featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    next = iterator.next();
+    assertEquals(", and more", next.getCoveredText());
+    featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    if (cas != null) {
+      cas.release();
+    }
+
+  }
+  
+  @Test
+  public void testAddEnd() {
+    String document = "Some text. More text , with 1 , and more. even more text.";
+    String script = "PERIOD #{-> T1} PERIOD;";
+    script += " #{-> T1} PERIOD;";
+    script += "T1{CONTAINS(NUM)-> CREATE(Complex, \"number\"= NUM)};";
+    script += "Complex{-> SPLIT(COMMA, true, false, true)};";
+
+    Map<String, String> typeMap = new TreeMap<String, String>();
+    String typeName = "Complex";
+    typeMap.put(typeName, "uima.tcas.Annotation");
+
+    Map<String, List<TestFeature>> featureMap = new TreeMap<String, List<TestFeature>>();
+    List<TestFeature> list = new ArrayList<RutaTestUtils.TestFeature>();
+    featureMap.put(typeName, list);
+    String fn = "number";
+    list.add(new TestFeature(fn, "", "uima.tcas.Annotation"));
+
+    CAS cas = null;
+    try {
+      cas = RutaTestUtils.getCAS(document, typeMap, featureMap);
+      Ruta.apply(cas, script);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    Type t = null;
+    AnnotationIndex<AnnotationFS> ai = null;
+    FSIterator<AnnotationFS> iterator = null;
+
+    t = cas.getTypeSystem().getType(typeName);
+    Feature f1 = t.getFeatureByBaseName(fn);
+    ai = cas.getAnnotationIndex(t);
+       
+    assertEquals(3, ai.size());
+    iterator = ai.iterator();
+    AnnotationFS next = iterator.next();
+    assertEquals("More text ,", next.getCoveredText());
+    FeatureStructure featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    next = iterator.next();
+    assertEquals("with 1 ,", next.getCoveredText());
+    featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    next = iterator.next();
+    assertEquals("and more", next.getCoveredText());
+    featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    if (cas != null) {
+      cas.release();
+    }
+
+  }
+  
+  @Test
+  public void testAddBoth() {
+    String document = "Some text. More text , with 1 , and more. even more text.";
+    String script = "PERIOD #{-> T1} PERIOD;";
+    script += " #{-> T1} PERIOD;";
+    script += "T1{CONTAINS(NUM)-> CREATE(Complex, \"number\"= NUM)};";
+    script += "Complex{-> SPLIT(COMMA, true, true, true)};";
+
+    Map<String, String> typeMap = new TreeMap<String, String>();
+    String typeName = "Complex";
+    typeMap.put(typeName, "uima.tcas.Annotation");
+
+    Map<String, List<TestFeature>> featureMap = new TreeMap<String, List<TestFeature>>();
+    List<TestFeature> list = new ArrayList<RutaTestUtils.TestFeature>();
+    featureMap.put(typeName, list);
+    String fn = "number";
+    list.add(new TestFeature(fn, "", "uima.tcas.Annotation"));
+
+    CAS cas = null;
+    try {
+      cas = RutaTestUtils.getCAS(document, typeMap, featureMap);
+      Ruta.apply(cas, script);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    Type t = null;
+    AnnotationIndex<AnnotationFS> ai = null;
+    FSIterator<AnnotationFS> iterator = null;
+
+    t = cas.getTypeSystem().getType(typeName);
+    Feature f1 = t.getFeatureByBaseName(fn);
+    ai = cas.getAnnotationIndex(t);
+       
+    assertEquals(3, ai.size());
+    iterator = ai.iterator();
+    AnnotationFS next = iterator.next();
+    assertEquals("More text ,", next.getCoveredText());
+    FeatureStructure featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    next = iterator.next();
+    assertEquals(", with 1 ,", next.getCoveredText());
+    featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    next = iterator.next();
+    assertEquals(", and more", next.getCoveredText());
+    featureValue = next.getFeatureValue(f1);
+    assertNotNull(featureValue);
+    assertEquals("1", ((AnnotationFS) featureValue).getCoveredText());
+
+    if (cas != null) {
+      cas.release();
+    }
+
+  }
+  
+}

Propchange: uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/action/SplitTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g?rev=1709649&r1=1709648&r2=1709649&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g (original)
+++ uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g Tue Oct 20 17:14:15 2015
@@ -251,6 +251,10 @@ SHIFT
   : 'SHIFT'  
   ;
 
+SPLIT   
+  : 'SPLIT'  
+  ;
+
 DYNAMICANCHORING  
   : 'DYNAMICANCHORING'   
   ;

Modified: uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g?rev=1709649&r1=1709648&r2=1709649&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g (original)
+++ uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g Tue Oct 20 17:14:15 2015
@@ -1418,6 +1418,7 @@ result = ActionFactory.createEmptyAction
 	| a = actionMatchedText
 	| a = actionClear
 	| a = actionShift
+	| a = actionSplit
 	| a = actionConfigure
 	| a = actionDynamicAnchoring
 	| a = actionGreedyAnchoring
@@ -1472,6 +1473,7 @@ result = ActionFactory.createEmptyAction
 	| a = actionMatchedText
 	| a = actionClear
 	| a = actionShift
+	| a = actionSplit
 	| a = actionConfigure
 	| a = actionDynamicAnchoring
 	| a = actionGreedyAnchoring
@@ -1661,6 +1663,32 @@ List<Expression> list = new ArrayList<Ex
      RPAREN
     ;
 
+actionSplit returns [RutaAction action = null]
+@init {
+	List<Expression> list = new ArrayList<Expression>();
+}
+	:
+	name = SPLIT 
+	LPAREN
+	type = typeExpression
+	{list.add(type);}
+	(
+	COMMA
+	complete = booleanExpression
+	{list.add(complete);}
+	(
+	COMMA
+	appendToBegin = booleanExpression
+	{list.add(appendToBegin);}
+	COMMA
+	appendToEnd = booleanExpression
+	{list.add(appendToEnd);}
+	)?
+	)? 
+	RPAREN
+	{action = ActionFactory.createAction(name, list);}
+	;
+
 actionMarkScore returns [RutaAction action = null]
 @init {
 List<Expression> list = new ArrayList<Expression>();