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 2018/12/18 19:52:19 UTC

svn commit: r1849219 [1/3] - 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/main/java/org/apache/uima/ruta/con...

Author: pkluegl
Date: Tue Dec 18 19:52:18 2018
New Revision: 1849219

URL: http://svn.apache.org/viewvc?rev=1849219&view=rev
Log:
UIMA-5916 + UIMA-5884 + UIMA-5419: merged commit
- added new language elements with test
- extended IDE
- mentions in docs
- reimplemented method in RutaStream due to bug in wildcard

Added:
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaProcessRuntimeException.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaOptionalRuleElement.java
    uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/action/LabelAtActionTest.java
    uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/rule/RutaOptionalRuleElementTest.java
Modified:
    uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/   (props changed)
    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/RutaConstants.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaScriptFactory.java
    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/AbstractMarkAction.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/AbstractRutaAction.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/CreateAction.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/FillAction.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/GatherAction.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/ShiftAction.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/TransferAction.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/UnmarkAction.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/condition/PartOfCondition.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/condition/ScoreCondition.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/AnnotationTypeExpression.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/MatchReference.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/expression/type/ITypeListExpression.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/AbstractRuleElement.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaAnnotationTypeMatcher.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRule.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/rule/RutaRuleElement.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/verbalize/ScriptVerbalizer.java
    uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/visitor/DebugInfoFactory.java
    uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/action/CreateTest.java
    uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/engine/RutaEngineTest.java
    uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/expression/AnnotationTypeExpressionTest.java
    uima/ruta/trunk/ruta-core/src/test/java/org/apache/uima/ruta/rule/SidestepInComposedTest.java
    uima/ruta/trunk/ruta-docbook/src/docbook/tools.ruta.language.syntax.xml
    uima/ruta/trunk/ruta-docbook/src/docbook/tools.ruta.language.xml
    uima/ruta/trunk/ruta-ep-ide-ui/src/main/java/org/apache/uima/ruta/ide/validator/RuleElementLabelVisitor.java
    uima/ruta/trunk/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/   (props changed)
    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
    uima/ruta/trunk/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/RutaAction.java

Propchange: uima/ruta/trunk/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Dec 18 19:52:18 2018
@@ -0,0 +1 @@
+output

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=1849219&r1=1849218&r2=1849219&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 Dec 18 19:52:18 2018
@@ -389,6 +389,8 @@ ADDRESS_PREFIX
 
 STARTANCHOR 
 	:	 '@';
+	
+OPTIONAL	: '_' ;
 
 HexLiteral : '0' ('x'|'X') HexDigit+ IntegerTypeSuffix? ;
 
@@ -548,6 +550,8 @@ GREATEREQUAL	: '>=' ;
 
 WILDCARD	: '#' ;
 
+
+
 WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
     ;
 

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=1849219&r1=1849218&r2=1849219&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 Dec 18 19:52:18 2018
@@ -990,6 +990,7 @@ String label = null;
 	| re2 = ruleElementLiteral[container] {re = re2;}
 	| (ruleElementComposed[null])=>re3 = ruleElementComposed[container] {re = re3;}
 	| (ruleElementWildCard[null])=> re5 = ruleElementWildCard[container] {re = re5;}
+	| (ruleElementOptional[null])=> re5 = ruleElementOptional[container] {re = re5;}
 	)
 	{
 	re.setLabel(label);
@@ -1026,6 +1027,21 @@ ruleElementWildCard [RuleElementContaine
 	}
     ;
 
+ruleElementOptional [RuleElementContainer container] returns [AbstractRuleElement re = null]
+    :
+    
+    w = OPTIONAL 
+     {re = factory.createOptionalRuleElement(null, null, container, $blockDeclaration::env);} 
+        (LCURLY c = conditions? (THEN a = actions)? RCURLY)?
+   {
+	if(c!= null) {
+		re.setConditions(c);
+	}
+	if(a != null) {
+		re.setActions(a);
+	}
+	}
+    ;
 
 
 ruleElementComposed [RuleElementContainer container] returns [ComposedRuleElement re = null]
@@ -1712,7 +1728,11 @@ conditionSize returns [AbstractRutaCondi
     ;
 
 action  returns [AbstractRutaAction result = null]
+@init{
+  String label = null;
+}
 	:
+	(l = Identifier {label = l.getText();} COLON)?
 	(
 	a = actionColor
 	| a = actionDel
@@ -1764,7 +1784,11 @@ action  returns [AbstractRutaAction resu
 	| (typeExpression)=> te = typeExpression {a = actionFactory.createAction(te);}
 	
 //	| a = variableAction
-	) {result = a;}
+	) 
+	{
+	result = a;
+	result.setLabel(label);
+	}
 	;
 		
 	

Modified: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaConstants.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaConstants.java?rev=1849219&r1=1849218&r2=1849219&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaConstants.java (original)
+++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaConstants.java Tue Dec 18 19:52:18 2018
@@ -19,11 +19,13 @@
 package org.apache.uima.ruta;
 
 public class RutaConstants {
-  
+
   public static final String RUTA_VARIABLE_ANNOTATION = "ANNOTATION";
-  
+
   public static final String RUTA_VARIABLE_ANNOTATION_LIST = "ANNOTATIONLIST";
 
   public static final String RUTA_VARIABLE_TYPE = "TYPE";
 
+  public static final String RUTA_VARIABLE_TYPE_LIST = "TYPELIST";
+
 }

Modified: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java?rev=1849219&r1=1849218&r2=1849219&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java (original)
+++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaEnvironment.java Tue Dec 18 19:52:18 2018
@@ -86,1034 +86,1045 @@ import org.springframework.core.io.Resou
 
 public class RutaEnvironment {
 
-	private static final String DOCUMENT = "Document";
+  private static final String DOCUMENT = "Document";
 
-	private final Object annotationTypeDummy = new Object();
+  private final Object annotationTypeDummy = new Object();
 
-	private Map<String, Type> types;
+  private Map<String, Type> types;
 
-	private Map<String, RutaWordList> wordLists;
+  private Map<String, RutaWordList> wordLists;
 
-	private Map<String, RutaTable> tables;
-
-	private RutaBlock owner;
-
-	/**
-	 * Mapping from short type name (e.g. {@code W}) to their disambiguated long
-	 * type names (e.g. {@code org.apache.uima.ruta.type.W}).
-	 */
-	private Map<String, String> namespaces;
-
-	/**
-	 * Mapping from ambiguous short type names to all their possible long type
-	 * names.
-	 */
-	private Map<String, Set<String>> ambiguousTypeAlias;
-
-	/**
-	 * Set of imported typesystems.
-	 */
-	private Set<String> typesystems;
-
-	/**
-	 * Set of imported scripts.
-	 */
-	private Set<String> scripts;
-
-	/**
-	 * An alias from a long to a short name.
-	 */
-	private static class Alias {
-		final String longName;
-
-		final String shortName;
-
-		Alias(String longName, String shortName) {
-			this.longName = longName;
-			this.shortName = shortName;
-		}
-	}
-
-	/**
-	 * Types that are imported in the environment. Keys are type system
-	 * descriptors and values are aliased types.
-	 */
-	private Map<String, List<Alias>> typeImports;
-
-	/**
-	 * Packages that are imported in the environment without a typesystem
-	 * specification.
-	 *
-	 * Keys are package names and values are aliases. An empty string as alias
-	 * means that all types from the package should be imported in the default
-	 * namespace.
-	 */
-	private Map<String, List<String>> packageImports;
-
-	/**
-	 * Set of types that are declared in the script.
-	 */
-	private Set<String> declaredAnnotationTypes;
-
-	private Map<String, Object> variableValues;
-
-	private Map<String, Class<?>> variableTypes;
-
-	private Map<String, Class<?>> availableTypes;
-
-	private Map<String, Class<?>> variableGenericTypes;
-
-	private Map<String, Class<?>> availableListTypes;
-
-	private Map<String, Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>>> macroConditions;
-
-	private Map<String, Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>>> macroActions;
-
-	private String[] resourcePaths = null;
-
-	private CAS cas;
-
-	private Map<String, Object> initializedVariables;
-
-	private ResourceManager resourceManager;
-
-	private Map<String, String> variableAliases;
-
-	private RutaVerbalizer verbalizer = new RutaVerbalizer();
-
-	public RutaEnvironment(RutaBlock owner) {
-		super();
-		this.owner = owner;
-
-		types = new HashMap<String, Type>();
-		namespaces = new HashMap<String, String>();
-		ambiguousTypeAlias = new HashMap<String, Set<String>>();
-		typesystems = new HashSet<String>();
-		scripts = new HashSet<String>();
-		typeImports = new HashMap<String, List<Alias>>();
-		packageImports = new HashMap<String, List<String>>();
-		declaredAnnotationTypes = new HashSet<String>();
-		wordLists = new HashMap<String, RutaWordList>();
-		tables = new HashMap<String, RutaTable>();
-		variableValues = new HashMap<String, Object>();
-		variableTypes = new HashMap<String, Class<?>>();
-		variableGenericTypes = new HashMap<String, Class<?>>();
-		macroConditions = new HashMap<>();
-		macroActions = new HashMap<>();
-		availableTypes = new HashMap<String, Class<?>>();
-		availableTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION, AnnotationFS.class);
-		availableTypes.put("INT", Integer.class);
-		availableTypes.put("STRING", String.class);
-		availableTypes.put("DOUBLE", Double.class);
-		availableTypes.put("FLOAT", Float.class);
-		availableTypes.put("BOOLEAN", Boolean.class);
-		availableTypes.put("TYPE", Type.class);
-		availableTypes.put("CONDITION", AbstractRutaCondition.class);
-		availableTypes.put("ACTION", AbstractRutaAction.class);
-		availableTypes.put("WORDLIST", RutaWordList.class);
-		availableTypes.put("WORDTABLE", RutaTable.class);
-		availableTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION_LIST, List.class);
-		availableTypes.put("BOOLEANLIST", List.class);
-		availableTypes.put("INTLIST", List.class);
-		availableTypes.put("DOUBLELIST", List.class);
-		availableTypes.put("FLOATLIST", List.class);
-		availableTypes.put("STRINGLIST", List.class);
-		availableTypes.put("TYPELIST", List.class);
-		availableListTypes = new HashMap<String, Class<?>>();
-		availableListTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION_LIST, AnnotationFS.class);
-		availableListTypes.put("BOOLEANLIST", Boolean.class);
-		availableListTypes.put("INTLIST", Integer.class);
-		availableListTypes.put("DOUBLELIST", Double.class);
-		availableListTypes.put("FLOATLIST", Float.class);
-		availableListTypes.put("STRINGLIST", String.class);
-		availableListTypes.put("TYPELIST", Type.class);
-		resourcePaths = getResourcePaths();
-		initializedVariables = new HashMap<String, Object>();
-		variableAliases = new HashMap<>();
-
-		// Always import BasicTypeSystem
-		addTypeSystem("org.apache.uima.ruta.engine.BasicTypeSystem");
-	}
-
-	/**
-	 * Import short type names.
-	 *
-	 * @param cas
-	 *            Cas to initialize the types for.
-	 * @param strictImport
-	 *            Specify whether all types should be imported (false) or only
-	 *            types
-	 */
-	public void initializeTypes(CAS cas, boolean strictImport) {
-		this.cas = cas;
-		try {
-			if (strictImport) {
-				importDeclaredTypes(cas.getTypeSystem());
-				importDeclaredTypesystems(cas.getTypeSystem());
-				importTypeAliases(cas.getTypeSystem());
-				importPackageAliases(cas.getTypeSystem());
-				importDeclaredScripts(cas.getTypeSystem());
-			} else {
-				// import all types known to the cas
-				importAllTypes(cas.getTypeSystem());
-				importTypeAliases(cas.getTypeSystem());
-				importPackageAliases(cas.getTypeSystem());
-			}
-
-			ambiguousTypeAlias.remove(DOCUMENT);
-			namespaces.remove(DOCUMENT);
-			Type documentType = cas.getTypeSystem().getType(CAS.TYPE_NAME_DOCUMENT_ANNOTATION);
-			addType(DOCUMENT, documentType);
-			addType(documentType.getShortName(), documentType);
-
-			Type annotationType = cas.getJCas().getCasType(org.apache.uima.jcas.tcas.Annotation.type);
-			addType("Annotation", annotationType);
-		} catch (CASException e) {
-			UIMAFramework.getLogger(getClass()).log(SEVERE, "Cannot initialize types.", e);
-		} catch (InvalidXMLException e) {
-			UIMAFramework.getLogger(getClass()).log(SEVERE, "Cannot initialize types.", e);
-		}
-
-	}
-
-	/**
-	 * Imports all types that are known to a type system.
-	 *
-	 * @param ts
-	 *            Type system to import.
-	 * @throws CASException
-	 */
-	private void importAllTypes(TypeSystem ts) throws CASException {
-		Type topType = ts.getTopType();
-		if (topType != null) {
-			List<Type> list = ts.getProperlySubsumedTypes(topType);
-			for (Type type : list) {
-				addType(type);
-			}
-		}
-	}
-
-	/**
-	 * Import all types that are declared by the script.
-	 *
-	 * @param casTS
-	 *            Type system containing all known types.
-	 * @throws InvalidXMLException
-	 *             When import cannot be resolved.
-	 */
-	private void importDeclaredTypes(TypeSystem casTS) throws InvalidXMLException {
-		for (String name : declaredAnnotationTypes) {
-			Type type = casTS.getType(name);
-			if (type != null) {
-				addType(type);
-			} else {
-				throw new RuntimeException("Type '" + name + "' not found");
-			}
-		}
-	}
-
-	/**
-	 * Import all typesystems that are imported in the script.
-	 *
-	 * @param casTS
-	 *            Type system containing all known types.
-	 * @throws InvalidXMLException
-	 *             When import cannot be resolved.
-	 */
-	private void importDeclaredTypesystems(TypeSystem casTS) throws InvalidXMLException {
-		String[] descriptors = typesystems.toArray(new String[typesystems.size()]);
-		TypeSystemDescription ts = TypeSystemDescriptionFactory.createTypeSystemDescription(descriptors);
-		ts.resolveImports(getResourceManager());
-		for (TypeDescription td : ts.getTypes()) {
-			Type type = casTS.getType(td.getName());
-			if (type != null) {
-				addType(type);
-			} else {
-				throw new RuntimeException("Type '" + td.getName() + "' not found");
-			}
-		}
-	}
-
-	/**
-	 * Import all already initialized types of imported scripts.
-	 *
-	 * @param casTS
-	 *            Type system containing all known types.
-	 * @throws InvalidXMLException
-	 *             When import cannot be resolved.
-	 */
-	private void importDeclaredScripts(TypeSystem casTS) throws InvalidXMLException {
-
-		RutaModule script = owner.getScript();
-		for (String eachImportedScript : scripts) {
-			RutaModule importedModule = script.getScript(eachImportedScript);
-			RutaEnvironment importedEnvironment = importedModule.getRootBlock().getEnvironment();
-			Map<String, Type> importedTypeMap = importedEnvironment.getTypes();
-			Map<String, String> importedNamespaces = importedEnvironment.getNamespaces();
-			Set<Entry<String, String>> entrySet = importedNamespaces.entrySet();
-			for (Entry<String, String> entry : entrySet) {
-				if (!ownsType(entry.getValue()) && !StringUtils.equals(entry.getKey(), DOCUMENT)) {
-					Type type = importedTypeMap.get(entry.getValue());
-					addType(entry.getKey(), type);
-				}
-			}
-			// TODO import also wordlists and variables?
-		}
-	}
-
-	/**
-	 * Imports all type aliases.
-	 *
-	 * @param casTS
-	 *            Cas type system.
-	 */
-	private void importTypeAliases(TypeSystem casTS) {
-		for (List<Alias> aliases : typeImports.values()) {
-			for (Alias alias : aliases) {
-				Type type = casTS.getType(alias.longName);
-				if (type == null) {
-					throw new RuntimeException("Type '" + alias.longName + "' not found");
-				}
-				addType(alias.shortName, casTS.getType(alias.longName));
-			}
-		}
-	}
-
-	/**
-	 * Import all packages that are imported by the script.
-	 *
-	 * @param casTS
-	 *            Type system containing all known types.
-	 */
-	private void importPackageAliases(TypeSystem casTS) {
-		Iterator<Type> iter = casTS.getTypeIterator();
-		while (iter.hasNext()) {
-			Type type = iter.next();
-			String name = type.getName();
-			String pkg = name.substring(0, Math.max(name.lastIndexOf('.'), 0));
-			List<String> aliases = packageImports.get(pkg);
-			if (aliases != null) {
-				for (String alias : aliases) {
-					if (alias.isEmpty()) {
-						addType(type);
-					} else {
-						addType(alias + "." + type.getShortName(), type);
-					}
-				}
-			}
-		}
-	}
-
-	public String[] getResourcePaths() {
-		if (resourcePaths == null) {
-			RutaBlock parent = owner.getParent();
-			if (parent != null) {
-				return parent.getEnvironment().getResourcePaths();
-			}
-		}
-		return resourcePaths;
-	}
-
-	public void setResourcePaths(String[] resourcePaths) {
-		this.resourcePaths = resourcePaths;
-	}
-
-	public boolean ownsType(String match) {
-		match = expand(match);
-		return types.keySet().contains(match);
-	}
-
-	private String expand(String string) {
-		String complete = namespaces.get(string);
-		if (complete == null) {
-			if (!string.contains(".")) {
-				complete = namespaces.get(string);
-				if (complete == null) {
-					complete = string;
-				}
-			} else {
-				complete = string;
-			}
-		}
-		return complete;
-	}
-
-	/**
-	 * Resolves an annotation type.
-	 *
-	 * @param match
-	 *            Annotation type to resolve.
-	 * @return Resolved annotation type or null if match is unknown.
-	 * @throws IllegalArgumentException
-	 *             When {@code match} is ambiguous.
-	 */
-	public Type getType(String match) {
-		// make sure that match is not ambiguous
-		Set<String> ambiguousTargets = ambiguousTypeAlias.get(match);
-		if (ambiguousTargets != null) {
-			StringBuilder message = new StringBuilder(match);
-			message.append(" is ambiguous, use one of the following instead : ");
-			for (String target : ambiguousTargets) {
-				message.append(target).append(' ');
-			}
-			throw new IllegalArgumentException(message.toString());
-		}
-
-		// try to resolve match
-		String expanded = expand(match);
-		Type type = types.get(expanded);
-		if (type == null) {
-			RutaBlock parent = owner.getParent();
-			if (parent != null) {
-				type = parent.getEnvironment().getType(match);
-			}
-		}
-		return type;
-	}
-
-	public void addType(String string, Type type) {
-		importType(type.getName(), string);
-		types.put(type.getName(), type);
-	}
-
-	public void addType(Type type) {
-		addType(type.getShortName(), type);
-	}
-
-	public void declareType(String name) {
-		declaredAnnotationTypes.add(name);
-	}
-
-	/**
-	 * Add a typesystem to the script.
-	 *
-	 * @param descriptor
-	 *            Type system's descriptor path.
-	 */
-	public void addTypeSystem(String descriptor) {
-		typesystems.add(descriptor);
-	}
-
-	/**
-	 * Add a script to the script.
-	 *
-	 * @param script
-	 *            the script's full name.
-	 */
-	public void addScript(String script) {
-		scripts.add(script);
-	}
-
-	/**
-	 * Import a type in the current namespace.
-	 *
-	 * @param longName
-	 *            Complete type name.
-	 * @param shortName
-	 *            Short type name (without namespace).
-	 */
-	private void importType(String longName, String shortName) {
-		Set<String> targets = ambiguousTypeAlias.get(shortName);
-		if (targets != null) {
-			// shortName is already ambiguous, add longName to its list of
-			// possible targets
-			targets.add(longName);
-		} else {
-			String existing = namespaces.put(shortName, longName);
-
-			if (existing != null && !existing.equals(longName)) {
-				// shortName can now be resolved to "existing" or "longName"
-				targets = new HashSet<String>(2);
-				targets.add(existing);
-				targets.add(longName);
-
-				// add existing mapping and longName to its list of possible
-				// targets
-				ambiguousTypeAlias.put(shortName, targets);
-
-				// remove shortName from the namespace because it is ambiguous
-				namespaces.remove(shortName);
-			}
-		}
-	}
-
-	/**
-	 * Import a type from a type system.
-	 *
-	 * @param typesystem
-	 *            Typesystem from which to import the type or null.
-	 * @param longName
-	 *            Type to import.
-	 * @param shortName
-	 *            Short name to use for this type.
-	 */
-	public void importTypeFromTypeSystem(String typesystem, String longName, String shortName) {
-		String key = typesystem != null ? typesystem : "";
-		List<Alias> aliases = typeImports.get(key);
-
-		if (aliases == null) {
-			aliases = new ArrayList<Alias>();
-			typeImports.put(key, aliases);
-		}
-
-		aliases.add(new Alias(longName, shortName));
-	}
-
-	/**
-	 * Import a type from a type system.
-	 *
-	 * The type is aliased by its unqualified name.
-	 *
-	 * @param typesystem
-	 *            Typesystem from which to import the type or null.
-	 * @param longName
-	 *            Type to import.
-	 */
-	public void importTypeFromTypeSystem(String typesystem, String longName) {
-		importTypeFromTypeSystem(typesystem, longName, longName.substring(longName.lastIndexOf('.') + 1));
-	}
-
-	/**
-	 * Import all the types from a package.
-	 *
-	 * @param typesystem
-	 *            Type system describing the package to load.
-	 * @param packageName
-	 *            Package to load or null to load all packages.
-	 * @param alias
-	 *            Alias of the package. Null or empty string to use no alias.
-	 */
-	public void importPackageFromTypeSystem(String typesystem, String packageName, String alias) {
-		TypeSystemDescription tsd = TypeSystemDescriptionFactory.createTypeSystemDescription(typesystem);
-		try {
-			tsd.resolveImports(getResourceManager());
-		} catch (InvalidXMLException e) {
-			throw new RuntimeException("Cannot resolve imports in " + typesystem, e);
-		}
-
-		for (TypeDescription td : tsd.getTypes()) {
-			String qname = td.getName();
-			if (packageName == null
-					|| (qname.startsWith(packageName) && qname.indexOf('.', packageName.length() + 1) == -1)) {
-				// td is in packageName
-				if (alias != null) {
-					String shortName = alias + "." + qname.substring(qname.lastIndexOf('.') + 1);
-					importTypeFromTypeSystem(typesystem, qname, shortName);
-				} else {
-					importTypeFromTypeSystem(typesystem, qname);
-				}
-			}
-		}
-	}
-
-	/**
-	 * Imports all the packages from the specified type system.
-	 *
-	 * @param typesystem
-	 *            Typesystem to load.
-	 * @param alias
-	 *            Alias for all the packages.
-	 */
-	public void importAllPackagesFromTypeSystem(String typesystem, String alias) {
-		importPackageFromTypeSystem(typesystem, null, alias);
-	}
-
-	/**
-	 * Import all the types from a package that are available at runtime.
-	 *
-	 * @param packageName
-	 *            Package to load.
-	 * @param alias
-	 *            Alias of the package. Null or empty string to use no alias.
-	 */
-	public void importPackage(String packageName, String alias) {
-		List<String> aliases = packageImports.get(packageName);
-		if (aliases == null) {
-			aliases = new ArrayList<String>(1);
-			packageImports.put(packageName, aliases);
-		}
-
-		aliases.add(alias == null ? "" : alias);
-	}
-
-	public RutaWordList getWordList(String list) {
-		RutaWordList result = wordLists.get(list);
-		UimaContext context = owner.getContext();
-		Boolean dictRemoveWS = false;
-		if (context != null) {
-			dictRemoveWS = (Boolean) context.getConfigParameterValue(RutaEngine.PARAM_DICT_REMOVE_WS);
-			if (dictRemoveWS == null) {
-				dictRemoveWS = false;
-			}
-		}
-		if (result == null) {
-			if (list.endsWith("txt") || list.endsWith("twl") || list.endsWith("mtwl")) {
-				ResourceLoader resourceLoader = new RutaResourceLoader(getResourcePaths(), getResourceManager().getExtensionClassLoader());
-				Resource resource = resourceLoader.getResource(list);
-				if (resource.exists()) {
-					try {
-						if (list.endsWith("mtwl")) {
-							wordLists.put(list, new MultiTreeWordList(resource));
-						} else {
-							wordLists.put(list, new TreeWordList(resource, dictRemoveWS));
-						}
-					} catch (IOException e) {
-						Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Error reading word list" + list,
-								e);
-					}
-				} else {
-					Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Can't find " + list + "!");
-				}
-			} else {
-				try {
-					RutaWordList rutaTable = (RutaWordList) context.getResourceObject(list);
-					wordLists.put(list, rutaTable);
-				} catch (ResourceAccessException e) {
-					Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
-							"Can't find external resource table" + list, e);
-				}
-			}
-		}
-
-		return wordLists.get(list);
-	}
-
-	public RutaTable getWordTable(String table) {
-		UimaContext context = owner.getContext();
-
-		RutaTable result = tables.get(table);
-		if (result == null) {
-			if (table.endsWith("csv") || table.endsWith("txt") || table.endsWith("tsv")) {
-				ResourceLoader resourceLoader = new RutaResourceLoader(getResourcePaths(), getResourceManager().getExtensionClassLoader());
-				Resource resource = resourceLoader.getResource(table);
-				if (resource.exists()) {
-					try {
-						tables.put(table, new CSVTable(resource, getCsvSeparator(context)));
-					} catch (IOException e) {
-						Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
-								"Error reading csv table " + table, e);
-					}
-				} else {
-					Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Can't find " + table + "!");
-				}
-			} else {
-				try {
-					RutaTable rutaTable = (RutaTable) context.getResourceObject(table);
-					tables.put(table, rutaTable);
-				} catch (ResourceAccessException e) {
-					Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
-							"Can't find external resource table" + table, e);
-				}
-			}
-		}
-
-		return tables.get(table);
-	}
-
-	private String getCsvSeparator(UimaContext context) {
-		if (context != null) {
-            String cvsSeparator = (String) context.getConfigParameterValue(RutaEngine.PARAM_CSV_SEPARATOR);
-            if (cvsSeparator != null) {
-               return cvsSeparator;
+  private Map<String, RutaTable> tables;
+
+  private RutaBlock owner;
+
+  /**
+   * Mapping from short type name (e.g. {@code W}) to their disambiguated long type names (e.g.
+   * {@code org.apache.uima.ruta.type.W}).
+   */
+  private Map<String, String> namespaces;
+
+  /**
+   * Mapping from ambiguous short type names to all their possible long type names.
+   */
+  private Map<String, Set<String>> ambiguousTypeAlias;
+
+  /**
+   * Set of imported typesystems.
+   */
+  private Set<String> typesystems;
+
+  /**
+   * Set of imported scripts.
+   */
+  private Set<String> scripts;
+
+  /**
+   * An alias from a long to a short name.
+   */
+  private static class Alias {
+    final String longName;
+
+    final String shortName;
+
+    Alias(String longName, String shortName) {
+      this.longName = longName;
+      this.shortName = shortName;
+    }
+  }
+
+  /**
+   * Types that are imported in the environment. Keys are type system descriptors and values are
+   * aliased types.
+   */
+  private Map<String, List<Alias>> typeImports;
+
+  /**
+   * Packages that are imported in the environment without a typesystem specification.
+   *
+   * Keys are package names and values are aliases. An empty string as alias means that all types
+   * from the package should be imported in the default namespace.
+   */
+  private Map<String, List<String>> packageImports;
+
+  /**
+   * Set of types that are declared in the script.
+   */
+  private Set<String> declaredAnnotationTypes;
+
+  private Map<String, Object> variableValues;
+
+  private Map<String, Class<?>> variableTypes;
+
+  private Map<String, Class<?>> availableTypes;
+
+  private Map<String, Class<?>> variableGenericTypes;
+
+  private Map<String, Class<?>> availableListTypes;
+
+  private Map<String, Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>>> macroConditions;
+
+  private Map<String, Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>>> macroActions;
+
+  private String[] resourcePaths = null;
+
+  private CAS cas;
+
+  private Map<String, Object> initializedVariables;
+
+  private ResourceManager resourceManager;
+
+  private Map<String, String> variableAliases;
+
+  private RutaVerbalizer verbalizer = new RutaVerbalizer();
+
+  public RutaEnvironment(RutaBlock owner) {
+    super();
+    this.owner = owner;
+
+    types = new HashMap<String, Type>();
+    namespaces = new HashMap<String, String>();
+    ambiguousTypeAlias = new HashMap<String, Set<String>>();
+    typesystems = new HashSet<String>();
+    scripts = new HashSet<String>();
+    typeImports = new HashMap<String, List<Alias>>();
+    packageImports = new HashMap<String, List<String>>();
+    declaredAnnotationTypes = new HashSet<String>();
+    wordLists = new HashMap<String, RutaWordList>();
+    tables = new HashMap<String, RutaTable>();
+    variableValues = new HashMap<String, Object>();
+    variableTypes = new HashMap<String, Class<?>>();
+    variableGenericTypes = new HashMap<String, Class<?>>();
+    macroConditions = new HashMap<>();
+    macroActions = new HashMap<>();
+    availableTypes = new HashMap<String, Class<?>>();
+    availableTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION, AnnotationFS.class);
+    availableTypes.put("INT", Integer.class);
+    availableTypes.put("STRING", String.class);
+    availableTypes.put("DOUBLE", Double.class);
+    availableTypes.put("FLOAT", Float.class);
+    availableTypes.put("BOOLEAN", Boolean.class);
+    availableTypes.put("TYPE", Type.class);
+    availableTypes.put("CONDITION", AbstractRutaCondition.class);
+    availableTypes.put("ACTION", AbstractRutaAction.class);
+    availableTypes.put("WORDLIST", RutaWordList.class);
+    availableTypes.put("WORDTABLE", RutaTable.class);
+    availableTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION_LIST, List.class);
+    availableTypes.put("BOOLEANLIST", List.class);
+    availableTypes.put("INTLIST", List.class);
+    availableTypes.put("DOUBLELIST", List.class);
+    availableTypes.put("FLOATLIST", List.class);
+    availableTypes.put("STRINGLIST", List.class);
+    availableTypes.put(RutaConstants.RUTA_VARIABLE_TYPE_LIST, List.class);
+    availableListTypes = new HashMap<String, Class<?>>();
+    availableListTypes.put(RutaConstants.RUTA_VARIABLE_ANNOTATION_LIST, AnnotationFS.class);
+    availableListTypes.put("BOOLEANLIST", Boolean.class);
+    availableListTypes.put("INTLIST", Integer.class);
+    availableListTypes.put("DOUBLELIST", Double.class);
+    availableListTypes.put("FLOATLIST", Float.class);
+    availableListTypes.put("STRINGLIST", String.class);
+    availableListTypes.put(RutaConstants.RUTA_VARIABLE_TYPE_LIST, Type.class);
+    resourcePaths = getResourcePaths();
+    initializedVariables = new HashMap<String, Object>();
+    variableAliases = new HashMap<>();
+
+    // Always import BasicTypeSystem
+    addTypeSystem("org.apache.uima.ruta.engine.BasicTypeSystem");
+  }
+
+  /**
+   * Import short type names.
+   *
+   * @param cas
+   *          Cas to initialize the types for.
+   * @param strictImport
+   *          Specify whether all types should be imported (false) or only types
+   */
+  public void initializeTypes(CAS cas, boolean strictImport) {
+    this.cas = cas;
+    try {
+      if (strictImport) {
+        importDeclaredTypes(cas.getTypeSystem());
+        importDeclaredTypesystems(cas.getTypeSystem());
+        importTypeAliases(cas.getTypeSystem());
+        importPackageAliases(cas.getTypeSystem());
+        importDeclaredScripts(cas.getTypeSystem());
+      } else {
+        // import all types known to the cas
+        importAllTypes(cas.getTypeSystem());
+        importTypeAliases(cas.getTypeSystem());
+        importPackageAliases(cas.getTypeSystem());
+      }
+
+      ambiguousTypeAlias.remove(DOCUMENT);
+      namespaces.remove(DOCUMENT);
+      Type documentType = cas.getTypeSystem().getType(CAS.TYPE_NAME_DOCUMENT_ANNOTATION);
+      addType(DOCUMENT, documentType);
+      addType(documentType.getShortName(), documentType);
+
+      Type annotationType = cas.getJCas().getCasType(org.apache.uima.jcas.tcas.Annotation.type);
+      addType("Annotation", annotationType);
+    } catch (CASException e) {
+      UIMAFramework.getLogger(getClass()).log(SEVERE, "Cannot initialize types.", e);
+    } catch (InvalidXMLException e) {
+      UIMAFramework.getLogger(getClass()).log(SEVERE, "Cannot initialize types.", e);
+    }
+
+  }
+
+  /**
+   * Imports all types that are known to a type system.
+   *
+   * @param ts
+   *          Type system to import.
+   * @throws CASException
+   */
+  private void importAllTypes(TypeSystem ts) throws CASException {
+    Type topType = ts.getTopType();
+    if (topType != null) {
+      List<Type> list = ts.getProperlySubsumedTypes(topType);
+      for (Type type : list) {
+        addType(type);
+      }
+    }
+  }
+
+  /**
+   * Import all types that are declared by the script.
+   *
+   * @param casTS
+   *          Type system containing all known types.
+   * @throws InvalidXMLException
+   *           When import cannot be resolved.
+   */
+  private void importDeclaredTypes(TypeSystem casTS) throws InvalidXMLException {
+    for (String name : declaredAnnotationTypes) {
+      Type type = casTS.getType(name);
+      if (type != null) {
+        addType(type);
+      } else {
+        throw new RuntimeException("Type '" + name + "' not found");
+      }
+    }
+  }
+
+  /**
+   * Import all typesystems that are imported in the script.
+   *
+   * @param casTS
+   *          Type system containing all known types.
+   * @throws InvalidXMLException
+   *           When import cannot be resolved.
+   */
+  private void importDeclaredTypesystems(TypeSystem casTS) throws InvalidXMLException {
+    String[] descriptors = typesystems.toArray(new String[typesystems.size()]);
+    TypeSystemDescription ts = TypeSystemDescriptionFactory
+            .createTypeSystemDescription(descriptors);
+    ts.resolveImports(getResourceManager());
+    for (TypeDescription td : ts.getTypes()) {
+      Type type = casTS.getType(td.getName());
+      if (type != null) {
+        addType(type);
+      } else {
+        throw new RuntimeException("Type '" + td.getName() + "' not found");
+      }
+    }
+  }
+
+  /**
+   * Import all already initialized types of imported scripts.
+   *
+   * @param casTS
+   *          Type system containing all known types.
+   * @throws InvalidXMLException
+   *           When import cannot be resolved.
+   */
+  private void importDeclaredScripts(TypeSystem casTS) throws InvalidXMLException {
+
+    RutaModule script = owner.getScript();
+    for (String eachImportedScript : scripts) {
+      RutaModule importedModule = script.getScript(eachImportedScript);
+      RutaEnvironment importedEnvironment = importedModule.getRootBlock().getEnvironment();
+      Map<String, Type> importedTypeMap = importedEnvironment.getTypes();
+      Map<String, String> importedNamespaces = importedEnvironment.getNamespaces();
+      Set<Entry<String, String>> entrySet = importedNamespaces.entrySet();
+      for (Entry<String, String> entry : entrySet) {
+        if (!ownsType(entry.getValue()) && !StringUtils.equals(entry.getKey(), DOCUMENT)) {
+          Type type = importedTypeMap.get(entry.getValue());
+          addType(entry.getKey(), type);
+        }
+      }
+      // TODO import also wordlists and variables?
+    }
+  }
+
+  /**
+   * Imports all type aliases.
+   *
+   * @param casTS
+   *          Cas type system.
+   */
+  private void importTypeAliases(TypeSystem casTS) {
+    for (List<Alias> aliases : typeImports.values()) {
+      for (Alias alias : aliases) {
+        Type type = casTS.getType(alias.longName);
+        if (type == null) {
+          throw new RuntimeException("Type '" + alias.longName + "' not found");
+        }
+        addType(alias.shortName, casTS.getType(alias.longName));
+      }
+    }
+  }
+
+  /**
+   * Import all packages that are imported by the script.
+   *
+   * @param casTS
+   *          Type system containing all known types.
+   */
+  private void importPackageAliases(TypeSystem casTS) {
+    Iterator<Type> iter = casTS.getTypeIterator();
+    while (iter.hasNext()) {
+      Type type = iter.next();
+      String name = type.getName();
+      String pkg = name.substring(0, Math.max(name.lastIndexOf('.'), 0));
+      List<String> aliases = packageImports.get(pkg);
+      if (aliases != null) {
+        for (String alias : aliases) {
+          if (alias.isEmpty()) {
+            addType(type);
+          } else {
+            addType(alias + "." + type.getShortName(), type);
+          }
+        }
+      }
+    }
+  }
+
+  public String[] getResourcePaths() {
+    if (resourcePaths == null) {
+      RutaBlock parent = owner.getParent();
+      if (parent != null) {
+        return parent.getEnvironment().getResourcePaths();
+      }
+    }
+    return resourcePaths;
+  }
+
+  public void setResourcePaths(String[] resourcePaths) {
+    this.resourcePaths = resourcePaths;
+  }
+
+  public boolean ownsType(String match) {
+    match = expand(match);
+    return types.keySet().contains(match);
+  }
+
+  private String expand(String string) {
+    String complete = namespaces.get(string);
+    if (complete == null) {
+      if (!string.contains(".")) {
+        complete = namespaces.get(string);
+        if (complete == null) {
+          complete = string;
+        }
+      } else {
+        complete = string;
+      }
+    }
+    return complete;
+  }
+
+  /**
+   * Resolves an annotation type.
+   *
+   * @param match
+   *          Annotation type to resolve.
+   * @return Resolved annotation type or null if match is unknown.
+   * @throws IllegalArgumentException
+   *           When {@code match} is ambiguous.
+   */
+  public Type getType(String match) {
+    // make sure that match is not ambiguous
+    Set<String> ambiguousTargets = ambiguousTypeAlias.get(match);
+    if (ambiguousTargets != null) {
+      StringBuilder message = new StringBuilder(match);
+      message.append(" is ambiguous, use one of the following instead : ");
+      for (String target : ambiguousTargets) {
+        message.append(target).append(' ');
+      }
+      throw new IllegalArgumentException(message.toString());
+    }
+
+    // try to resolve match
+    String expanded = expand(match);
+    Type type = types.get(expanded);
+    if (type == null) {
+      RutaBlock parent = owner.getParent();
+      if (parent != null) {
+        type = parent.getEnvironment().getType(match);
+      }
+    }
+    return type;
+  }
+
+  public void addType(String string, Type type) {
+    importType(type.getName(), string);
+    types.put(type.getName(), type);
+  }
+
+  public void addType(Type type) {
+    addType(type.getShortName(), type);
+  }
+
+  public void declareType(String name) {
+    declaredAnnotationTypes.add(name);
+  }
+
+  /**
+   * Add a typesystem to the script.
+   *
+   * @param descriptor
+   *          Type system's descriptor path.
+   */
+  public void addTypeSystem(String descriptor) {
+    typesystems.add(descriptor);
+  }
+
+  /**
+   * Add a script to the script.
+   *
+   * @param script
+   *          the script's full name.
+   */
+  public void addScript(String script) {
+    scripts.add(script);
+  }
+
+  /**
+   * Import a type in the current namespace.
+   *
+   * @param longName
+   *          Complete type name.
+   * @param shortName
+   *          Short type name (without namespace).
+   */
+  private void importType(String longName, String shortName) {
+    Set<String> targets = ambiguousTypeAlias.get(shortName);
+    if (targets != null) {
+      // shortName is already ambiguous, add longName to its list of
+      // possible targets
+      targets.add(longName);
+    } else {
+      String existing = namespaces.put(shortName, longName);
+
+      if (existing != null && !existing.equals(longName)) {
+        // shortName can now be resolved to "existing" or "longName"
+        targets = new HashSet<String>(2);
+        targets.add(existing);
+        targets.add(longName);
+
+        // add existing mapping and longName to its list of possible
+        // targets
+        ambiguousTypeAlias.put(shortName, targets);
+
+        // remove shortName from the namespace because it is ambiguous
+        namespaces.remove(shortName);
+      }
+    }
+  }
+
+  /**
+   * Import a type from a type system.
+   *
+   * @param typesystem
+   *          Typesystem from which to import the type or null.
+   * @param longName
+   *          Type to import.
+   * @param shortName
+   *          Short name to use for this type.
+   */
+  public void importTypeFromTypeSystem(String typesystem, String longName, String shortName) {
+    String key = typesystem != null ? typesystem : "";
+    List<Alias> aliases = typeImports.get(key);
+
+    if (aliases == null) {
+      aliases = new ArrayList<Alias>();
+      typeImports.put(key, aliases);
+    }
+
+    aliases.add(new Alias(longName, shortName));
+  }
+
+  /**
+   * Import a type from a type system.
+   *
+   * The type is aliased by its unqualified name.
+   *
+   * @param typesystem
+   *          Typesystem from which to import the type or null.
+   * @param longName
+   *          Type to import.
+   */
+  public void importTypeFromTypeSystem(String typesystem, String longName) {
+    importTypeFromTypeSystem(typesystem, longName,
+            longName.substring(longName.lastIndexOf('.') + 1));
+  }
+
+  /**
+   * Import all the types from a package.
+   *
+   * @param typesystem
+   *          Type system describing the package to load.
+   * @param packageName
+   *          Package to load or null to load all packages.
+   * @param alias
+   *          Alias of the package. Null or empty string to use no alias.
+   */
+  public void importPackageFromTypeSystem(String typesystem, String packageName, String alias) {
+    TypeSystemDescription tsd = TypeSystemDescriptionFactory
+            .createTypeSystemDescription(typesystem);
+    try {
+      tsd.resolveImports(getResourceManager());
+    } catch (InvalidXMLException e) {
+      throw new RuntimeException("Cannot resolve imports in " + typesystem, e);
+    }
+
+    for (TypeDescription td : tsd.getTypes()) {
+      String qname = td.getName();
+      if (packageName == null || (qname.startsWith(packageName)
+              && qname.indexOf('.', packageName.length() + 1) == -1)) {
+        // td is in packageName
+        if (alias != null) {
+          String shortName = alias + "." + qname.substring(qname.lastIndexOf('.') + 1);
+          importTypeFromTypeSystem(typesystem, qname, shortName);
+        } else {
+          importTypeFromTypeSystem(typesystem, qname);
+        }
+      }
+    }
+  }
+
+  /**
+   * Imports all the packages from the specified type system.
+   *
+   * @param typesystem
+   *          Typesystem to load.
+   * @param alias
+   *          Alias for all the packages.
+   */
+  public void importAllPackagesFromTypeSystem(String typesystem, String alias) {
+    importPackageFromTypeSystem(typesystem, null, alias);
+  }
+
+  /**
+   * Import all the types from a package that are available at runtime.
+   *
+   * @param packageName
+   *          Package to load.
+   * @param alias
+   *          Alias of the package. Null or empty string to use no alias.
+   */
+  public void importPackage(String packageName, String alias) {
+    List<String> aliases = packageImports.get(packageName);
+    if (aliases == null) {
+      aliases = new ArrayList<String>(1);
+      packageImports.put(packageName, aliases);
+    }
+
+    aliases.add(alias == null ? "" : alias);
+  }
+
+  public RutaWordList getWordList(String list) {
+    RutaWordList result = wordLists.get(list);
+    UimaContext context = owner.getContext();
+    Boolean dictRemoveWS = false;
+    if (context != null) {
+      dictRemoveWS = (Boolean) context.getConfigParameterValue(RutaEngine.PARAM_DICT_REMOVE_WS);
+      if (dictRemoveWS == null) {
+        dictRemoveWS = false;
+      }
+    }
+    if (result == null) {
+      if (list.endsWith("txt") || list.endsWith("twl") || list.endsWith("mtwl")) {
+        ResourceLoader resourceLoader = new RutaResourceLoader(getResourcePaths(),
+                getResourceManager().getExtensionClassLoader());
+        Resource resource = resourceLoader.getResource(list);
+        if (resource.exists()) {
+          try {
+            if (list.endsWith("mtwl")) {
+              wordLists.put(list, new MultiTreeWordList(resource));
+            } else {
+              wordLists.put(list, new TreeWordList(resource, dictRemoveWS));
             }
+          } catch (IOException e) {
+            Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
+                    "Error reading word list" + list, e);
+          }
+        } else {
+          Logger.getLogger(this.getClass().getName()).log(Level.SEVERE, "Can't find " + list + "!");
         }
-		return CSVTable.DEFAULT_CSV_SEPARATOR;
-	}
+      } else {
+        try {
+          RutaWordList rutaTable = (RutaWordList) context.getResourceObject(list);
+          wordLists.put(list, rutaTable);
+        } catch (ResourceAccessException e) {
+          Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
+                  "Can't find external resource table" + list, e);
+        }
+      }
+    }
+
+    return wordLists.get(list);
+  }
+
+  public RutaTable getWordTable(String table) {
+    UimaContext context = owner.getContext();
+
+    RutaTable result = tables.get(table);
+    if (result == null) {
+      if (table.endsWith("csv") || table.endsWith("txt") || table.endsWith("tsv")) {
+        ResourceLoader resourceLoader = new RutaResourceLoader(getResourcePaths(),
+                getResourceManager().getExtensionClassLoader());
+        Resource resource = resourceLoader.getResource(table);
+        if (resource.exists()) {
+          try {
+            tables.put(table, new CSVTable(resource, getCsvSeparator(context)));
+          } catch (IOException e) {
+            Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
+                    "Error reading csv table " + table, e);
+          }
+        } else {
+          Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
+                  "Can't find " + table + "!");
+        }
+      } else {
+        try {
+          RutaTable rutaTable = (RutaTable) context.getResourceObject(table);
+          tables.put(table, rutaTable);
+        } catch (ResourceAccessException e) {
+          Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
+                  "Can't find external resource table" + table, e);
+        }
+      }
+    }
 
-	private void addVariable(String name, Class<?> type, Class<?> generic) {
-		variableTypes.put(name, type);
-		if (generic != null) {
-			variableGenericTypes.put(name, generic);
-		}
-		variableValues.put(name, getInitialValue(name, type));
-	}
-
-	@SuppressWarnings("unchecked")
-	private Object getInitialValue(String name, Class<?> type) {
-		Object init = initializedVariables.get(name);
-		if (init != null) {
-			if (init instanceof List) {
-				ArrayList<Object> list = new ArrayList<Object>();
-				list.addAll((Collection<? extends Object>) init);
-				return list;
-			}
-			return init;
-		}
-		if (Integer.class.equals(type)) {
-			return 0;
-		} else if (Double.class.equals(type)) {
-			return 0d;
-		} else if (Float.class.equals(type)) {
-			return 0f;
-		} else if (String.class.equals(type)) {
-			return "";
-		} else if (Boolean.class.equals(type)) {
-			return false;
-		} else if (Type.class.equals(type)) {
-			if (cas == null) {
-				return annotationTypeDummy;
-			} else {
-				return cas.getAnnotationType();
-			}
-		} else if (List.class.equals(type)) {
-			return new ArrayList<Object>();
-		}
-		return null;
-	}
-
-	public void addVariable(String name, String type) {
-		addVariable(name, availableTypes.get(type), availableListTypes.get(type));
-	}
-
-	public void removeVariable(String name) {
-		variableTypes.remove(name);
-		variableGenericTypes.remove(name);
-		variableValues.remove(name);
-	}
-
-	public boolean ownsVariable(String name) {
-		return variableTypes.containsKey(name);
-	}
-
-	public boolean ownsVariableOfType(String name, String type) {
-		if (variableAliases.containsKey(name)) {
-			name = variableAliases.get(name);
-		}
-		Class<?> varclass = variableTypes.get(name);
-		Class<?> aclass = availableTypes.get(type);
-		boolean list = true;
-		if (aclass.equals(List.class)) {
-			Class<?> vt = variableGenericTypes.get(name);
-			Class<?> at = availableListTypes.get(type);
-			list = vt != null && vt.equals(at);
-		}
-		return list && varclass != null && varclass.equals(aclass);
-	}
-
-	public boolean isVariable(String name) {
-		if (variableAliases.containsKey(name)) {
-			name = variableAliases.get(name);
-		}
-		if (ownsVariable(name)) {
-			return true;
-		}
-		if (owner != null && owner.getParent() != null) {
-			return owner.getParent().getEnvironment().isVariable(name);
-		}
-		return false;
-	}
-
-	public boolean isVariableOfType(String name, String type) {
-		return ownsVariableOfType(name, type)
-				|| (owner.getParent() != null && owner.getParent().getEnvironment().isVariableOfType(name, type));
-	}
-
-	public Class<?> getVariableType(String name) {
-		if (variableAliases.containsKey(name)) {
-			name = variableAliases.get(name);
-		}
-		Class<?> result = variableTypes.get(name);
-		if (result != null) {
-			return result;
-		} else if (owner.getParent() != null) {
-			return owner.getParent().getEnvironment().getVariableType(name);
-		}
-		return null;
-	}
-
-	public Class<?> getVariableGenericType(String name) {
-		Class<?> result = variableGenericTypes.get(name);
-		if (result != null) {
-			return result;
-		} else if (owner.getParent() != null) {
-			return owner.getParent().getEnvironment().getVariableGenericType(name);
-		}
-		return null;
-	}
-
-	public <T> T getVariableValue(String name, Class<T> type, RutaStream stream) {
-		if (variableAliases.containsKey(name)) {
-			name = variableAliases.get(name);
-		}
-		boolean containsKey = variableValues.containsKey(name);
-		Object result = variableValues.get(name);
-
-		if (result instanceof String && type.equals(Type.class)) {
-			// "cast" string to type, because initial values were set when there
-			// was no cas/type system
-			// yet
-			String stringValue = (String) result;
-			result = types.get(stringValue);
-			if (result == null) {
-				// try to resolve short names
-				result = getType(stringValue);
-			}
-		}
-
-		if (containsKey && result == null) {
-			// TODO find the problem with the null values!
-			// this might now work for word lists in another env.
-			Object initialValue = getInitialValue(name, type);
-			if (initialValue instanceof Type) {
-				return type.cast(initialValue);
-			} else if (initialValue != null){
-				throw new IllegalArgumentException("Variable " + name + " of type " + type
-						+ " is not correctly initialized! It is not a Type, but " + initialValue);
-			}
-		}
-		if (result == annotationTypeDummy) {
-			return type.cast(cas.getAnnotationType());
-		}
-		if (result != null) {
-			MatchContext context = new MatchContext(owner);
-			if (RutaWordList.class.isAssignableFrom(type) && result instanceof WordListExpression) {
-				WordListExpression wle = (WordListExpression) result;
-				RutaWordList list = wle.getList(context, stream);
-				return type.cast(list);
-			} else if (RutaTable.class.isAssignableFrom(type) && result instanceof WordTableExpression) {
-				WordTableExpression wte = (WordTableExpression) result;
-				RutaTable table = wte.getTable(context, stream);
-				return type.cast(table);
-			} else {
-				return type.cast(result);
-			}
-		} else if (owner.getParent() != null) {
-			return owner.getParent().getEnvironment().getVariableValue(name, type, stream);
-		}
-		return null;
-	}
-
-	public Object getVariableValue(String name, RutaStream stream) {
-		return getVariableValue(name, Object.class, stream);
-	}
-
-	@SuppressWarnings("rawtypes")
-	public Object getLiteralValue(String var, Object value) {
-		if (ownsVariable(var)) {
-			MatchContext context = new MatchContext(owner);
-			Class<?> clazz = variableTypes.get(var);
-			if (value instanceof INumberExpression) {
-				INumberExpression ne = (INumberExpression) value;
-				if (clazz.equals(Integer.class)) {
-					return ne.getIntegerValue(context, null);
-				} else if (clazz.equals(Double.class)) {
-					return ne.getDoubleValue(context, null);
-				} else if (clazz.equals(Float.class)) {
-					return ne.getFloatValue(context, null);
-				} else if (clazz.equals(String.class)) {
-					return ne.getStringValue(context, null);
-				}
-			} else if (clazz.equals(String.class) && value instanceof IStringExpression) {
-				IStringExpression se = (IStringExpression) value;
-				return se.getStringValue(context, null);
-			} else if (clazz.equals(Boolean.class) && value instanceof IBooleanExpression) {
-				IBooleanExpression be = (IBooleanExpression) value;
-				return be.getBooleanValue(context, null);
-			}
-			if (clazz.equals(RutaWordList.class) && value instanceof LiteralWordListExpression) {
-				return value;
-			}	else if (clazz.equals(RutaWordList.class) && value instanceof StringWordListExpression) {
-	        return value;
-			} else if (clazz.equals(RutaWordList.class) && value instanceof String) {
-				return value;
-			} else if (clazz.equals(RutaTable.class) && value instanceof LiteralWordTableExpression) {
-				return value;
-			} else if (clazz.equals(RutaTable.class) && value instanceof StringWordTableExpression) {
+    return tables.get(table);
+  }
+
+  private String getCsvSeparator(UimaContext context) {
+    if (context != null) {
+      String cvsSeparator = (String) context
+              .getConfigParameterValue(RutaEngine.PARAM_CSV_SEPARATOR);
+      if (cvsSeparator != null) {
+        return cvsSeparator;
+      }
+    }
+    return CSVTable.DEFAULT_CSV_SEPARATOR;
+  }
+
+  private void addVariable(String name, Class<?> type, Class<?> generic) {
+    variableTypes.put(name, type);
+    if (generic != null) {
+      variableGenericTypes.put(name, generic);
+    }
+    variableValues.put(name, getInitialValue(name, type));
+  }
+
+  @SuppressWarnings("unchecked")
+  private Object getInitialValue(String name, Class<?> type) {
+    Object init = initializedVariables.get(name);
+    if (init != null) {
+      if (init instanceof List) {
+        ArrayList<Object> list = new ArrayList<Object>();
+        list.addAll((Collection<? extends Object>) init);
+        return list;
+      }
+      return init;
+    }
+    if (Integer.class.equals(type)) {
+      return 0;
+    } else if (Double.class.equals(type)) {
+      return 0d;
+    } else if (Float.class.equals(type)) {
+      return 0f;
+    } else if (String.class.equals(type)) {
+      return "";
+    } else if (Boolean.class.equals(type)) {
+      return false;
+    } else if (Type.class.equals(type)) {
+      if (cas == null) {
+        return annotationTypeDummy;
+      } else {
+        return cas.getAnnotationType();
+      }
+    } else if (List.class.equals(type)) {
+      return new ArrayList<Object>();
+    }
+    return null;
+  }
+
+  public void addVariable(String name, String type) {
+    addVariable(name, availableTypes.get(type), availableListTypes.get(type));
+  }
+
+  public void removeVariable(String name) {
+    variableTypes.remove(name);
+    variableGenericTypes.remove(name);
+    variableValues.remove(name);
+  }
+
+  public boolean ownsVariable(String name) {
+    return variableTypes.containsKey(name);
+  }
+
+  public boolean ownsVariableOfType(String name, String type) {
+    if (variableAliases.containsKey(name)) {
+      name = variableAliases.get(name);
+    }
+    Class<?> varclass = variableTypes.get(name);
+    Class<?> aclass = availableTypes.get(type);
+    boolean list = true;
+    if (aclass.equals(List.class)) {
+      Class<?> vt = variableGenericTypes.get(name);
+      Class<?> at = availableListTypes.get(type);
+      list = vt != null && vt.equals(at);
+    }
+    return list && varclass != null && varclass.equals(aclass);
+  }
+
+  public boolean isVariable(String name) {
+    if (variableAliases.containsKey(name)) {
+      name = variableAliases.get(name);
+    }
+    if (ownsVariable(name)) {
+      return true;
+    }
+    if (owner != null && owner.getParent() != null) {
+      return owner.getParent().getEnvironment().isVariable(name);
+    }
+    return false;
+  }
+
+  public boolean isVariableOfType(String name, String type) {
+    return ownsVariableOfType(name, type) || (owner.getParent() != null
+            && owner.getParent().getEnvironment().isVariableOfType(name, type));
+  }
+
+  public Class<?> getVariableType(String name) {
+    if (variableAliases.containsKey(name)) {
+      name = variableAliases.get(name);
+    }
+    Class<?> result = variableTypes.get(name);
+    if (result != null) {
+      return result;
+    } else if (owner.getParent() != null) {
+      return owner.getParent().getEnvironment().getVariableType(name);
+    }
+    return null;
+  }
+
+  public Class<?> getVariableGenericType(String name) {
+    Class<?> result = variableGenericTypes.get(name);
+    if (result != null) {
+      return result;
+    } else if (owner.getParent() != null) {
+      return owner.getParent().getEnvironment().getVariableGenericType(name);
+    }
+    return null;
+  }
+
+  public <T> T getVariableValue(String name, Class<T> type, RutaStream stream) {
+    if (variableAliases.containsKey(name)) {
+      name = variableAliases.get(name);
+    }
+    boolean containsKey = variableValues.containsKey(name);
+    Object result = variableValues.get(name);
+
+    if (result instanceof String && type.equals(Type.class)) {
+      // "cast" string to type, because initial values were set when there
+      // was no cas/type system
+      // yet
+      String stringValue = (String) result;
+      result = types.get(stringValue);
+      if (result == null) {
+        // try to resolve short names
+        result = getType(stringValue);
+      }
+    }
+
+    if (containsKey && result == null) {
+      // TODO find the problem with the null values!
+      // this might now work for word lists in another env.
+      Object initialValue = getInitialValue(name, type);
+      if (initialValue instanceof Type) {
+        return type.cast(initialValue);
+      } else if (initialValue != null) {
+        throw new IllegalArgumentException("Variable " + name + " of type " + type
+                + " is not correctly initialized! It is not a Type, but " + initialValue);
+      }
+    }
+    if (result == annotationTypeDummy) {
+      return type.cast(cas.getAnnotationType());
+    }
+    if (result != null) {
+      MatchContext context = new MatchContext(owner);
+      if (RutaWordList.class.isAssignableFrom(type) && result instanceof WordListExpression) {
+        WordListExpression wle = (WordListExpression) result;
+        RutaWordList list = wle.getList(context, stream);
+        return type.cast(list);
+      } else if (RutaTable.class.isAssignableFrom(type) && result instanceof WordTableExpression) {
+        WordTableExpression wte = (WordTableExpression) result;
+        RutaTable table = wte.getTable(context, stream);
+        return type.cast(table);
+      } else {
+        return type.cast(result);
+      }
+    } else if (owner.getParent() != null) {
+      return owner.getParent().getEnvironment().getVariableValue(name, type, stream);
+    }
+    return null;
+  }
+
+  public Object getVariableValue(String name, RutaStream stream) {
+    return getVariableValue(name, Object.class, stream);
+  }
+
+  @SuppressWarnings("rawtypes")
+  public Object getLiteralValue(String var, Object value) {
+    if (ownsVariable(var)) {
+      MatchContext context = new MatchContext(owner);
+      Class<?> clazz = variableTypes.get(var);
+      if (value instanceof INumberExpression) {
+        INumberExpression ne = (INumberExpression) value;
+        if (clazz.equals(Integer.class)) {
+          return ne.getIntegerValue(context, null);
+        } else if (clazz.equals(Double.class)) {
+          return ne.getDoubleValue(context, null);
+        } else if (clazz.equals(Float.class)) {
+          return ne.getFloatValue(context, null);
+        } else if (clazz.equals(String.class)) {
+          return ne.getStringValue(context, null);
+        }
+      } else if (clazz.equals(String.class) && value instanceof IStringExpression) {
+        IStringExpression se = (IStringExpression) value;
+        return se.getStringValue(context, null);
+      } else if (clazz.equals(Boolean.class) && value instanceof IBooleanExpression) {
+        IBooleanExpression be = (IBooleanExpression) value;
+        return be.getBooleanValue(context, null);
+      }
+      if (clazz.equals(RutaWordList.class) && value instanceof LiteralWordListExpression) {
+        return value;
+      } else if (clazz.equals(RutaWordList.class) && value instanceof StringWordListExpression) {
+        return value;
+      } else if (clazz.equals(RutaWordList.class) && value instanceof String) {
+        return value;
+      } else if (clazz.equals(RutaTable.class) && value instanceof LiteralWordTableExpression) {
+        return value;
+      } else if (clazz.equals(RutaTable.class) && value instanceof StringWordTableExpression) {
         return value;
-			} else if (clazz.equals(RutaTable.class) && value instanceof String) {
-				return value;
-			} else if (clazz.equals(List.class) && value instanceof ListExpression) {
-				List list = getList((ListExpression) value);
-				return list;
-			} else if (clazz.equals(Type.class) && value instanceof CommonToken) {
-				String typeName = ((CommonToken) value).getText();
-				return typeName;
-			} else if (clazz.equals(Type.class) && value instanceof SimpleTypeExpression) {
-				String typeName = ((SimpleTypeExpression) value).getTypeString();
-				return typeName;
-			}
-
-			return null;
-		} else {
-			return owner.getParent().getEnvironment().getLiteralValue(var, value);
-		}
-	}
-
-	@SuppressWarnings("unchecked")
-	public void setInitialVariableValue(String var, Object value) {
-		if (ownsVariable(var)) {
-			if (value instanceof List) {
-				List<Object> initValue = new ArrayList<Object>();
-				initValue.addAll((Collection<? extends Object>) value);
-				initializedVariables.put(var, initValue);
-			} else {
-				initializedVariables.put(var, value);
-			}
-			setVariableValue(var, value);
-		} else if (owner.getParent() != null) {
-			owner.getParent().getEnvironment().setInitialVariableValue(var, value);
-		}
-	}
-
-	public void setVariableValue(String name, Object value) {
-		if (variableAliases.containsKey(name)) {
-			name = variableAliases.get(name);
-		}
-		if (ownsVariable(name)) {
-			Class<?> clazz = variableTypes.get(name);
-			if (value == null) {
-				value = getInitialValue(name, clazz);
-			}
-			variableValues.put(name, value);
-		} else if (owner.getParent() != null) {
-			owner.getParent().getEnvironment().setVariableValue(name, value);
-		}
-	}
-
-	@SuppressWarnings("rawtypes")
-	private List getList(ListExpression value) {
-		if (value instanceof SimpleBooleanListExpression) {
-			SimpleBooleanListExpression e = (SimpleBooleanListExpression) value;
-			return e.getList();
-		} else if (value instanceof SimpleNumberListExpression) {
-			SimpleNumberListExpression e = (SimpleNumberListExpression) value;
-			return e.getList();
-		} else if (value instanceof SimpleStringListExpression) {
-			SimpleStringListExpression e = (SimpleStringListExpression) value;
-			return e.getList();
-		} else if (value instanceof SimpleTypeListExpression) {
-			SimpleTypeListExpression e = (SimpleTypeListExpression) value;
-			return e.getList();
-		}
-		return null;
-	}
-
-	public void reset(CAS cas) {
-		this.cas = cas;
-		Set<Entry<String, Object>> entrySet = variableValues.entrySet();
-		for (Entry<String, Object> entry : entrySet) {
-			String key = entry.getKey();
-			Class<?> variableType = variableTypes.get(key);
-			Object initialValue = getInitialValue(key, variableTypes.get(key));
-			if ((!variableType.equals(RutaTable.class) && !variableType.equals(RutaWordList.class) ) || initialValue != null) {
-				// not for word lists
-				entry.setValue(initialValue);
-			}
-		}
-	}
-
-	public ResourceManager getResourceManager() {
-		if (resourceManager != null) {
-			return resourceManager;
-		} else {
-			RutaBlock parent = owner.getParent();
-			if (parent != null) {
-				return parent.getEnvironment().getResourceManager();
-			}
-		}
-		// at least return default resource manager
-		return UIMAFramework.newDefaultResourceManager();
-	}
-
-	public void setResourceManager(ResourceManager resourceManager) {
-		this.resourceManager = resourceManager;
-	}
-
-	public void addMacroAction(String name, Map<String, String> def, Set<String> vars,
-			List<AbstractRutaAction> actions) {
-		macroActions.put(name,
-				new ImmutableTriple<Map<String, String>, List<AbstractRutaAction>, Set<String>>(def, actions, vars));
-	}
-
-	public void addMacroCondition(String name, Map<String, String> def, Set<String> vars,
-			List<AbstractRutaCondition> conditions) {
-		macroConditions.put(name, new ImmutableTriple<Map<String, String>, List<AbstractRutaCondition>, Set<String>>(
-				def, conditions, vars));
-	}
-
-	public boolean isMacroAction(String name) {
-		boolean isDefined = macroActions.keySet().contains(name);
-		if(isDefined) {
-		  return true;
-		} else if (owner != null && owner.getParent() != null) {
-		  return owner.getParent().getEnvironment().isMacroAction(name);
-		}
+      } else if (clazz.equals(RutaTable.class) && value instanceof String) {
+        return value;
+      } else if (clazz.equals(List.class) && value instanceof ListExpression) {
+        List list = getList((ListExpression) value);
+        return list;
+      } else if (clazz.equals(Type.class) && value instanceof CommonToken) {
+        String typeName = ((CommonToken) value).getText();
+        return typeName;
+      } else if (clazz.equals(Type.class) && value instanceof SimpleTypeExpression) {
+        String typeName = ((SimpleTypeExpression) value).getTypeString();
+        return typeName;
+      }
+
+      return null;
+    } else {
+      return owner.getParent().getEnvironment().getLiteralValue(var, value);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  public void setInitialVariableValue(String var, Object value) {
+    if (ownsVariable(var)) {
+      if (value instanceof List) {
+        List<Object> initValue = new ArrayList<Object>();
+        initValue.addAll((Collection<? extends Object>) value);
+        initializedVariables.put(var, initValue);
+      } else {
+        initializedVariables.put(var, value);
+      }
+      setVariableValue(var, value);
+    } else if (owner.getParent() != null) {
+      owner.getParent().getEnvironment().setInitialVariableValue(var, value);
+    }
+  }
+
+  public void setVariableValue(String name, Object value) {
+    if (variableAliases.containsKey(name)) {
+      name = variableAliases.get(name);
+    }
+    if (ownsVariable(name)) {
+      Class<?> clazz = variableTypes.get(name);
+      if (value == null) {
+        value = getInitialValue(name, clazz);
+      }
+      variableValues.put(name, value);
+    } else if (owner.getParent() != null) {
+      owner.getParent().getEnvironment().setVariableValue(name, value);
+    }
+  }
+
+  @SuppressWarnings("rawtypes")
+  private List getList(ListExpression value) {
+    if (value instanceof SimpleBooleanListExpression) {
+      SimpleBooleanListExpression e = (SimpleBooleanListExpression) value;
+      return e.getList();
+    } else if (value instanceof SimpleNumberListExpression) {
+      SimpleNumberListExpression e = (SimpleNumberListExpression) value;
+      return e.getList();
+    } else if (value instanceof SimpleStringListExpression) {
+      SimpleStringListExpression e = (SimpleStringListExpression) value;
+      return e.getList();
+    } else if (value instanceof SimpleTypeListExpression) {
+      SimpleTypeListExpression e = (SimpleTypeListExpression) value;
+      return e.getList();
+    }
+    return null;
+  }
+
+  public void reset(CAS cas) {
+    this.cas = cas;
+    Set<Entry<String, Object>> entrySet = variableValues.entrySet();
+    for (Entry<String, Object> entry : entrySet) {
+      String key = entry.getKey();
+      Class<?> variableType = variableTypes.get(key);
+      Object initialValue = getInitialValue(key, variableTypes.get(key));
+      if ((!variableType.equals(RutaTable.class) && !variableType.equals(RutaWordList.class))
+              || initialValue != null) {
+        // not for word lists
+        entry.setValue(initialValue);
+      }
+    }
+  }
+
+  public ResourceManager getResourceManager() {
+    if (resourceManager != null) {
+      return resourceManager;
+    } else {
+      RutaBlock parent = owner.getParent();
+      if (parent != null) {
+        return parent.getEnvironment().getResourceManager();
+      }
+    }
+    // at least return default resource manager
+    return UIMAFramework.newDefaultResourceManager();
+  }
+
+  public void setResourceManager(ResourceManager resourceManager) {
+    this.resourceManager = resourceManager;
+  }
+
+  public void addMacroAction(String name, Map<String, String> def, Set<String> vars,
+          List<AbstractRutaAction> actions) {
+    macroActions.put(name,
+            new ImmutableTriple<Map<String, String>, List<AbstractRutaAction>, Set<String>>(def,
+                    actions, vars));
+  }
+
+  public void addMacroCondition(String name, Map<String, String> def, Set<String> vars,
+          List<AbstractRutaCondition> conditions) {
+    macroConditions.put(name,
+            new ImmutableTriple<Map<String, String>, List<AbstractRutaCondition>, Set<String>>(def,
+                    conditions, vars));
+  }
+
+  public boolean isMacroAction(String name) {
+    boolean isDefined = macroActions.keySet().contains(name);
+    if (isDefined) {
+      return true;
+    } else if (owner != null && owner.getParent() != null) {
+      return owner.getParent().getEnvironment().isMacroAction(name);
+    }
     return false;
-	}
+  }
 
-	public boolean isMacroCondition(String name) {
-	  boolean isDefined = macroConditions.keySet().contains(name);
-    if(isDefined) {
+  public boolean isMacroCondition(String name) {
+    boolean isDefined = macroConditions.keySet().contains(name);
+    if (isDefined) {
       return true;
     } else if (owner != null && owner.getParent() != null) {
       return owner.getParent().getEnvironment().isMacroCondition(name);
     }
     return false;
-	}
+  }
+
+  public Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>> getMacroAction(
+          String name) {
+    Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>> definition = macroActions
+            .get(name);
+    if (definition != null) {
+      return definition;
+    } else if (owner != null && owner.getParent() != null) {
+      return owner.getParent().getEnvironment().getMacroAction(name);
+    }
+    return null;
+  }
 
-	public Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>> getMacroAction(String name) {
-	  Triple<Map<String, String>, List<AbstractRutaAction>, Set<String>> definition = macroActions.get(name);
-	  if(definition != null) {
-	    return definition;
-	  } else if (owner != null && owner.getParent() != null) {
-	    return owner.getParent().getEnvironment().getMacroAction(name);
-	  }
-		return null;
-	}
-
-	public Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>> getMacroCondition(String name) {
-    Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>> definition = macroConditions.get(name);
-    if(definition != null) {
+  public Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>> getMacroCondition(
+          String name) {
+    Triple<Map<String, String>, List<AbstractRutaCondition>, Set<String>> definition = macroConditions
+            .get(name);
+    if (definition != null) {
       return definition;
     } else if (owner != null && owner.getParent() != null) {
       return owner.getParent().getEnvironment().getMacroCondition(name);
     }
     return null;
-	}
+  }
 
-	public void addAliasVariable(String name, String var) {
-		variableAliases.put(name, var);
-	}
-
-	public void removeAliasVariable(String name) {
-		variableAliases.remove(name);
-	}
-
-	public String getVariableNameOfExpression(IRutaExpression expression) {
-		String verbalize = verbalizer.verbalize(expression);
-		return verbalize;
-	}
-
-	public Map<String, Type> getTypes() {
-		return types;
-	}
-
-	public Set<String> getDeclaredAnnotationTypes() {
-		return declaredAnnotationTypes;
-	}
-
-	public Set<String> getTypesystems() {
-		return typesystems;
-	}
-
-	public Map<String, String> getNamespaces() {
-		return namespaces;
-	}
+  public void addAliasVariable(String name, String var) {
+    variableAliases.put(name, var);
+  }
+
+  public void removeAliasVariable(String name) {
+    variableAliases.remove(name);
+  }
+
+  public String getVariableNameOfExpression(IRutaExpression expression) {
+    String verbalize = verbalizer.verbalize(expression);
+    return verbalize;
+  }
+
+  public Map<String, Type> getTypes() {
+    return types;
+  }
+
+  public Set<String> getDeclaredAnnotationTypes() {
+    return declaredAnnotationTypes;
+  }
+
+  public Set<String> getTypesystems() {
+    return typesystems;
+  }
+
+  public Map<String, String> getNamespaces() {
+    return namespaces;
+  }
 
-  public void addMatchToVariable(RuleMatch ruleMatch, RuleElement element, MatchContext context,  RutaStream stream) {
+  public void addMatchToVariable(RuleMatch ruleMatch, RuleElement element, MatchContext context,
+          RutaStream stream) {
     String var = element.getLabel();
-    if(StringUtils.isBlank(var)) {
+    if (StringUtils.isBlank(var)) {
       return;
     }
     List<AnnotationFS> annotations = ruleMatch.getMatchedAnnotationsOfElement(element);
     Class<?> variableType = getVariableType(var);
-    if(List.class.equals(variableType) &&  AnnotationFS.class.equals(getVariableGenericType(var))) {
+    if (List.class.equals(variableType) && AnnotationFS.class.equals(getVariableGenericType(var))) {
       setVariableValue(var, annotations);
-    } else if(AnnotationFS.class.equals(variableType)) {
-      if(context.getDirection()) {
+    } else if (AnnotationFS.class.equals(variableType)) {
+      if (context.getDirection()) {
         AnnotationFS annotation = null;
-        if(context.getDirection()) {
-          annotation = annotations.get(annotations.size()-1);
+        if (context.getDirection()) {
+          annotation = annotations.get(annotations.size() - 1);
         } else {
           annotation = annotations.get(0);
         }

Added: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaProcessRuntimeException.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaProcessRuntimeException.java?rev=1849219&view=auto
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaProcessRuntimeException.java (added)
+++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaProcessRuntimeException.java Tue Dec 18 19:52:18 2018
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+public class RutaProcessRuntimeException extends RuntimeException {
+
+  private static final long serialVersionUID = -2749936277801227536L;
+
+  public RutaProcessRuntimeException(String msg) {
+    super(msg);
+  }
+
+  public RutaProcessRuntimeException(Throwable t) {
+    super(t);
+  }
+
+}

Modified: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaScriptFactory.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaScriptFactory.java?rev=1849219&r1=1849218&r2=1849219&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaScriptFactory.java (original)
+++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/RutaScriptFactory.java Tue Dec 18 19:52:18 2018
@@ -50,6 +50,7 @@ import org.apache.uima.ruta.rule.RuleEle
 import org.apache.uima.ruta.rule.RutaAnnotationTypeMatcher;
 import org.apache.uima.ruta.rule.RutaLiteralMatcher;
 import org.apache.uima.ruta.rule.RutaMatcher;
+import org.apache.uima.ruta.rule.RutaOptionalRuleElement;
 import org.apache.uima.ruta.rule.RutaRule;
 import org.apache.uima.ruta.rule.RutaRuleElement;
 import org.apache.uima.ruta.rule.WildCardRuleElement;
@@ -70,10 +71,10 @@ public class RutaScriptFactory {
   private UimaContext context;
 
   private ExpressionFactory expressionFactory;
-  
+
   @SuppressWarnings("unused")
   private TypeUsageInformation typeUsage;
-  
+
   public RutaScriptFactory(ExpressionFactory expressionFactory, TypeUsageInformation typeUsage) {
     super();
     if (expressionFactory == null) {
@@ -83,9 +84,9 @@ public class RutaScriptFactory {
     }
     this.typeUsage = typeUsage;
   }
-  
+
   public RutaScriptFactory(ExpressionFactory expressionFactory) {
-   this(expressionFactory, null);
+    this(expressionFactory, null);
   }
 
   public RutaScriptBlock createScriptBlock(Token id, RutaRuleElement ruleElement,
@@ -207,6 +208,12 @@ public class RutaScriptFactory {
     return new WildCardRuleElement(conditions, actions, container, parent);
   }
 
+  public AbstractRuleElement createOptionalRuleElement(List<AbstractRutaCondition> conditions,
+          List<AbstractRutaAction> actions, RuleElementContainer container, RutaBlock parent) {
+
+    return new RutaOptionalRuleElement(conditions, actions, container, parent);
+  }
+
   public ComposedRuleElement createComposedRuleElement(List<RuleElement> res,
           RuleElementQuantifier quantifier, List<AbstractRutaCondition> conditions,
           List<AbstractRutaAction> actions, RuleElementContainer container, RutaBlock parent) {

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=1849219&r1=1849218&r2=1849219&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 Dec 18 19:52:18 2018
@@ -633,45 +633,43 @@ public class RutaStream extends FSIterat
   }
 
   public RutaBasic getBasicNextTo(boolean before, AnnotationFS annotation) {
+
     if (annotation == null) {
-      return beginAnchors.get(0);
+      return null;
     }
+
     if (before) {
-      RutaBasic pointer = beginAnchors.get(annotation.getBegin());
-      moveTo(pointer);
-      if (isVisible(pointer) || !isValid()) {
-        moveToPrevious();
-      }
-      if (!isValid()) {
-        moveToLast();
-      }
-      if (isValid()) {
-        RutaBasic nextBasic = (RutaBasic) get();
-        // TODO HOTFIX for annotation of length 0
-        while (isValid() && nextBasic.getEnd() > annotation.getBegin()) {
-          moveToPrevious();
-          if (isValid()) {
-            nextBasic = (RutaBasic) get();
-          }
+
+      RutaBasic pointer = endAnchors.get(annotation.getBegin());
+      while (pointer != null && pointer.getBegin() >= documentAnnotation.getBegin()) {
+
+        if (isVisible(pointer)) {
+          return pointer;
+        }
+
+        Entry<Integer, RutaBasic> lowerEntry = endAnchors.lowerEntry(pointer.getEnd());
+        if (lowerEntry != null) {
+          pointer = lowerEntry.getValue();
+        } else {
+          pointer = null;
         }
-        return nextBasic;
       }
+
     } else {
-      RutaBasic pointer = endAnchors.get(annotation.getEnd());
-      moveTo(pointer);
-      if (isVisible(pointer)) {
-        moveToNext();
-      }
-      if (isValid()) {
-        RutaBasic nextBasic = (RutaBasic) get();
-        // TODO HOTFIX for annotation of length 0
-        while (isValid() && nextBasic.getBegin() < annotation.getEnd()) {
-          moveToNext();
-          if (isValid()) {
-            nextBasic = (RutaBasic) get();
-          }
+
+      RutaBasic pointer = beginAnchors.get(annotation.getEnd());
+      while (pointer != null && pointer.getEnd() <= documentAnnotation.getEnd()) {
+
+        if (isVisible(pointer)) {
+          return pointer;
+        }
+
+        Entry<Integer, RutaBasic> higherEntry = beginAnchors.higherEntry(pointer.getBegin());
+        if (higherEntry != null) {
+          pointer = higherEntry.getValue();
+        } else {
+          pointer = null;
         }
-        return nextBasic;
       }
     }
     return null;

Modified: uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/AbstractMarkAction.java
URL: http://svn.apache.org/viewvc/uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/AbstractMarkAction.java?rev=1849219&r1=1849218&r2=1849219&view=diff
==============================================================================
--- uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/AbstractMarkAction.java (original)
+++ uima/ruta/trunk/ruta-core/src/main/java/org/apache/uima/ruta/action/AbstractMarkAction.java Tue Dec 18 19:52:18 2018
@@ -50,6 +50,7 @@ public abstract class AbstractMarkAction
       return null;
     }
     stream.addAnnotation(newAnnotation, context.getRuleMatch());
+    addAnnotationToLabel(newAnnotation, context);
     return newAnnotation;
   }