UIMA-3569
- introduced concept for language extension of blocks in core and ide
- added exemplary block construct that applies the rules in inverse order
- added test

git-svn-id: https://svn.apache.org/repos/asf/uima/ruta/branches/UIMA-3569@1568358 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/example-projects/ruta-ep-example-extensions/plugin.xml b/example-projects/ruta-ep-example-extensions/plugin.xml
index 78e86e4..a0029a8 100644
--- a/example-projects/ruta-ep-example-extensions/plugin.xml
+++ b/example-projects/ruta-ep-example-extensions/plugin.xml
@@ -61,5 +61,12 @@
             engine="org.apache.uima.ruta.example.extensions.ExampleNumberFunctionExtension">

       </condition>

    </extension>

+   <extension

+         point="org.apache.uima.ruta.ide.blockExtension">

+      <block

+            class="org.apache.uima.ruta.example.extensions.ExampleBlockIDEExtension"

+            engine="org.apache.uima.ruta.example.extensions.ExampleBlockExtension">

+      </block>

+   </extension>

 

 </plugin>

diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataBlock.java b/example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlock.java
similarity index 62%
rename from ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataBlock.java
rename to example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlock.java
index e0f1a81..7db0f8c 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataBlock.java
+++ b/example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlock.java
@@ -1,78 +1,89 @@
-/*

- * 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;

-

-import java.util.List;

-

-import org.apache.uima.cas.Type;

-import org.apache.uima.cas.text.AnnotationFS;

-import org.apache.uima.ruta.rule.AbstractRule;

-import org.apache.uima.ruta.rule.AbstractRuleMatch;

-import org.apache.uima.ruta.rule.RuleApply;

-import org.apache.uima.ruta.rule.RuleMatch;

-import org.apache.uima.ruta.rule.RutaRule;

-import org.apache.uima.ruta.rule.RutaRuleElement;

-import org.apache.uima.ruta.visitor.InferenceCrowd;

-

-public class RutaAutomataBlock extends RutaBlock {

-

-  public RutaAutomataBlock(String id, RutaRule rule, List<RutaStatement> elements,

-          RutaBlock parent, String defaultNamespace) {

-    super(id, rule, elements, parent, defaultNamespace);

-  }

-

-  @Override

-  public ScriptApply apply(RutaStream stream, InferenceCrowd crowd) {

-    BlockApply result = new BlockApply(this);

-    crowd.beginVisit(this, result);

-    RuleApply apply = rule.apply(stream, crowd, true);

-    for (AbstractRuleMatch<? extends AbstractRule> eachMatch : apply.getList()) {

-      if (eachMatch.matched()) {

-        AnnotationFS each = ((RuleMatch) eachMatch).getMatchedAnnotations(null, null).get(0);

-        if (each == null) {

-          continue;

-        }

-        List<Type> types = ((RutaRuleElement) rule.getRuleElements().get(0)).getMatcher().getTypes(

-                getParent(), stream);

-        for (Type eachType : types) {

-          RutaStream window = stream.getWindowStream(each, eachType);

-          for (RutaStatement element : getElements()) {

-            if (element != null) {

-              element.apply(window, crowd);

-            }

-          }

-        }

-      }

-    }

-    crowd.endVisit(this, result);

-    return result;

-  }

-

-  @Override

-  public String toString() {

-    String ruleString = rule == null ? "Document" : rule.toString();

-    return "RULES(" + name + ") " + ruleString + " containing " + elements.size() + " Elements";

-  }

-

-  public void setMatchRule(RutaRule rule) {

-    this.rule = rule;

-  }

-

-}

+/*
+ * 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.example.extensions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.text.AnnotationFS;
+import org.apache.uima.ruta.BlockApply;
+import org.apache.uima.ruta.RutaBlock;
+import org.apache.uima.ruta.RutaStatement;
+import org.apache.uima.ruta.RutaStream;
+import org.apache.uima.ruta.ScriptApply;
+import org.apache.uima.ruta.rule.AbstractRule;
+import org.apache.uima.ruta.rule.AbstractRuleMatch;
+import org.apache.uima.ruta.rule.RuleApply;
+import org.apache.uima.ruta.rule.RuleMatch;
+import org.apache.uima.ruta.rule.RutaRule;
+import org.apache.uima.ruta.rule.RutaRuleElement;
+import org.apache.uima.ruta.visitor.InferenceCrowd;
+
+/**
+ * Exemplary implementation of a block extension, which applied its rules in reverse order.
+ *
+ */
+public class ExampleBlock extends RutaBlock {
+
+  public ExampleBlock(String name, RutaRule rule, List<RutaStatement> elements, RutaBlock parent,
+          String defaultNamespace) {
+    super(name, rule, elements, parent, defaultNamespace);
+  }
+
+  @Override
+  public ScriptApply apply(RutaStream stream, InferenceCrowd crowd) {
+    BlockApply result = new BlockApply(this);
+    crowd.beginVisit(this, result);
+    RuleApply apply = rule.apply(stream, crowd, true);
+    for (AbstractRuleMatch<? extends AbstractRule> eachMatch : apply.getList()) {
+      if (eachMatch.matched()) {
+        List<AnnotationFS> matchedAnnotations = ((RuleMatch) eachMatch).getMatchedAnnotations(null,
+                null);
+        if (matchedAnnotations == null || matchedAnnotations.isEmpty()) {
+          continue;
+        }
+        AnnotationFS each = matchedAnnotations.get(0);
+        if (each == null) {
+          continue;
+        }
+        List<Type> types = ((RutaRuleElement) rule.getRuleElements().get(0)).getMatcher().getTypes(
+                getParent() == null ? this : getParent(), stream);
+        for (Type eachType : types) {
+          RutaStream window = stream.getWindowStream(each, eachType);
+          List<RutaStatement> elements = new ArrayList<RutaStatement>(getElements());
+          Collections.reverse(elements);
+          for (RutaStatement element : elements) {
+            if (element != null) {
+              element.apply(window, crowd);
+            }
+          }
+        }
+      }
+    }
+    crowd.endVisit(this, result);
+    return result;
+  }
+
+
+
+
+}
diff --git a/example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlockExtension.java b/example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlockExtension.java
new file mode 100644
index 0000000..370ae20
--- /dev/null
+++ b/example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlockExtension.java
@@ -0,0 +1,68 @@
+/*
+ * 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.example.extensions;
+
+import java.util.List;
+
+import org.apache.uima.ruta.RutaBlock;
+import org.apache.uima.ruta.RutaElement;
+import org.apache.uima.ruta.expression.RutaExpression;
+import org.apache.uima.ruta.extensions.IRutaBlockExtension;
+import org.apache.uima.ruta.extensions.RutaParseException;
+import org.apache.uima.ruta.verbalize.RutaVerbalizer;
+
+public class ExampleBlockExtension implements IRutaBlockExtension {
+
+  private final String[] knownExtensions = new String[] { "REVERSE" };
+
+  private final Class<?>[] extensions = new Class[] { ExampleBlock.class };
+
+  public String verbalize(RutaElement element, RutaVerbalizer verbalizer) {
+    if (element instanceof ExampleBlock) {
+      ExampleBlock b = (ExampleBlock) element;
+      String verbalize = verbalizer.verbalize(b, true);
+      verbalize.replaceFirst("BLOCK", verbalizeName(element));
+      return verbalize;
+    } else {
+      return "UnknownAction";
+    }
+  }
+
+  @Override
+  public RutaBlock createBlock(String name, List<RutaExpression> args, RutaBlock env)
+          throws RutaParseException {
+    return new ExampleBlock(name, null, null, env, name);
+  }
+
+
+  public String verbalizeName(RutaElement element) {
+    return knownExtensions[0];
+  }
+
+  public String[] getKnownExtensions() {
+    return knownExtensions;
+  }
+
+  public Class<?>[] extensions() {
+    return extensions;
+  }
+
+
+}
diff --git a/example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlockIDEExtension.java b/example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlockIDEExtension.java
new file mode 100644
index 0000000..2561d80
--- /dev/null
+++ b/example-projects/ruta-ep-example-extensions/src/main/java/org/apache/uima/ruta/example/extensions/ExampleBlockIDEExtension.java
@@ -0,0 +1,41 @@
+/*
+ * 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.example.extensions;
+
+import org.antlr.runtime.RecognitionException;
+import org.apache.uima.ruta.ide.core.extensions.IIDEConditionExtension;
+import org.apache.uima.ruta.ide.core.extensions.IRutaCheckerProblemFactory;
+import org.eclipse.dltk.ast.expressions.Expression;
+import org.eclipse.dltk.compiler.problem.IProblemReporter;
+
+public class ExampleBlockIDEExtension implements IIDEConditionExtension {
+  private final String[] strings = new String[] { "REVERSE" };
+
+  public String[] getKnownExtensions() {
+    return strings;
+  }
+
+  public boolean checkSyntax(Expression element, IRutaCheckerProblemFactory problemFactory,
+          IProblemReporter rep) throws RecognitionException {
+    // do not add additional checks in this example
+    return false;
+  }
+
+}
diff --git a/example-projects/ruta-ep-example-extensions/src/test/java/org/apache/uima/ruta/example/extensions/ExampleBlockTest.java b/example-projects/ruta-ep-example-extensions/src/test/java/org/apache/uima/ruta/example/extensions/ExampleBlockTest.java
new file mode 100644
index 0000000..5bfb0d5
--- /dev/null
+++ b/example-projects/ruta-ep-example-extensions/src/test/java/org/apache/uima/ruta/example/extensions/ExampleBlockTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.example.extensions;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.FSIterator;
+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.RutaEngine;
+import org.junit.Test;
+
+public class ExampleBlockTest {
+
+  @Test
+  public void test() {
+    String name = this.getClass().getSimpleName();
+    String namespace = this.getClass().getPackage().getName().replaceAll("\\.", "/");
+    CAS cas = null;
+    try {
+      cas = RutaTestUtils.process(namespace + "/" + name + RutaEngine.SCRIPT_FILE_EXTENSION, namespace + "/test.txt", 50);
+    } catch (Exception e) {
+      e.printStackTrace();
+      assert (false);
+    }
+
+    Type t = null;
+    AnnotationIndex<AnnotationFS> ai = null;
+    FSIterator<AnnotationFS> iterator = null;
+
+    t = RutaTestUtils.getTestType(cas, 4);
+    ai = cas.getAnnotationIndex(t);
+    assertEquals(1, ai.size());
+    iterator = ai.iterator();
+    assertEquals("This is a test.", iterator.next().getCoveredText());
+
+    if (cas != null) {
+      cas.release();
+    }
+
+  }
+}
diff --git a/example-projects/ruta-ep-example-extensions/src/test/resources/org/apache/uima/ruta/example/extensions/ExampleBlockTest.ruta b/example-projects/ruta-ep-example-extensions/src/test/resources/org/apache/uima/ruta/example/extensions/ExampleBlockTest.ruta
new file mode 100644
index 0000000..cf67d4b
--- /dev/null
+++ b/example-projects/ruta-ep-example-extensions/src/test/resources/org/apache/uima/ruta/example/extensions/ExampleBlockTest.ruta
@@ -0,0 +1,20 @@
+PACKAGE uima.ruta.example;
+
+DECLARE T1, T2, T3, T4;
+
+//This is a test.
+REVERSE Document{}{
+  (CW T3){-> T4};
+  (SW T2){-> T3};
+  (SW T1){-> T2};
+  (SW PERIOD){-> T1};
+}
+
+
+
+
+
+
+
+
+
diff --git a/example-projects/ruta-ep-example-extensions/src/test/resources/org/apache/uima/ruta/example/extensions/TestEngine.xml b/example-projects/ruta-ep-example-extensions/src/test/resources/org/apache/uima/ruta/example/extensions/TestEngine.xml
index 7c6b48f..71c7532 100644
--- a/example-projects/ruta-ep-example-extensions/src/test/resources/org/apache/uima/ruta/example/extensions/TestEngine.xml
+++ b/example-projects/ruta-ep-example-extensions/src/test/resources/org/apache/uima/ruta/example/extensions/TestEngine.xml
@@ -1,4 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>

+

 <!--

   Licensed to the Apache Software Foundation (ASF) under one

   or more contributor license agreements.  See the NOTICE file

@@ -17,7 +18,6 @@
   specific language governing permissions and limitations

   under the License.

 -->

-

 <analysisEngineDescription xmlns="http://uima.apache.org/resourceSpecifier">

   <frameworkImplementation>org.apache.uima.java</frameworkImplementation>

   <primitive>true</primitive>

@@ -210,7 +210,8 @@
                   <string>org.apache.uima.ruta.example.extensions.ExampleNumberFunctionExtension</string>

                   <string>org.apache.uima.ruta.example.extensions.ExampleStringFunctionExtension</string>

                   <string>org.apache.uima.ruta.example.extensions.ExampleTypeFunctionExtension</string>

-              </array>

+              <string>org.apache.uima.ruta.example.extensions.ExampleBlockExtension</string>

+          </array>

           </value>

       </nameValuePair>

     </configurationParameterSettings>

diff --git a/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g b/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g
index a240be6..8705a1f 100644
--- a/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g
+++ b/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaLexer.g
@@ -332,7 +332,6 @@
 EngineString	:	'ENGINE';

 UimafitString	:	'UIMAFIT';

 BlockString 	:	'BLOCK';

-AutomataBlockString 	:	'RULES';

 TypeString 	:	'TYPE';

 IntString	:	'INT';

 DoubleString	:	'DOUBLE';

diff --git a/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g b/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g
index 5a79982..c52d1f0 100644
--- a/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g
+++ b/ruta-core/src/main/antlr3/org/apache/uima/ruta/parser/RutaParser.g
@@ -56,13 +56,11 @@
 import org.apache.uima.ruta.action.ActionFactory;

 import org.apache.uima.ruta.condition.AbstractRutaCondition;

 import org.apache.uima.ruta.condition.ConditionFactory;

-import org.apache.uima.ruta.RutaAutomataBlock;

 import org.apache.uima.ruta.RutaBlock;

 import org.apache.uima.ruta.RutaEnvironment;

 import org.apache.uima.ruta.RutaModule;

 import org.apache.uima.ruta.RutaScriptBlock;

 import org.apache.uima.ruta.RutaScriptFactory;

-import org.apache.uima.ruta.RutaAutomataFactory;

 import org.apache.uima.ruta.RutaStatement;

 import org.apache.uima.ruta.expression.ExpressionFactory;

 import org.apache.uima.ruta.expression.IRutaExpression;

@@ -97,7 +95,6 @@
 private List vars = new ArrayList();	

 private int level = 0;

 private RutaScriptFactory factory = new RutaScriptFactory();

-private RutaScriptFactory automataFactory = new RutaAutomataFactory();

 private RutaExternalFactory external;

 private String namespace;

 private String moduleName;

@@ -302,6 +299,9 @@
       	private boolean isTypeFunctionExtension(String name) {

       	  return external.getTypeFunctionExtensions().keySet().contains(name);

       	}

+      	private boolean isBlockExtension(String name) {

+      	  return external.getBlockExtensions().keySet().contains(name);

+      	}

       	

 

 

@@ -367,7 +367,7 @@
 	| stmtVariable = variableDeclaration {stmt = stmtVariable;}

 	| stmtRule = simpleStatement {stmt = stmtRule;}

 	| stmtBlock = blockDeclaration {stmt = stmtBlock;}

-	| stmtAutomata = automataDeclaration {stmt = stmtBlock;}

+	| stmtExternal = externalBlock {stmt = stmtExternal;}

 	)

 	;

 

@@ -556,7 +556,8 @@
 	}	

 	;

 

-automataDeclaration returns [RutaBlock block = null]

+

+externalBlock returns [RutaBlock block = null]

 options {

 	backtrack = true;

 }

@@ -567,37 +568,35 @@
 @init{

 RutaRuleElement re = null;

 RuleElementIsolator container = null;

-RutaScriptFactory oldFactory = factory;

-factory = automataFactory; 

 level++;

 }

 @after {

-factory = oldFactory;

 level--;

 }

 	:

-	

-	type = AutomataBlockString 

-	LPAREN

-	id = Identifier 

-	RPAREN

-	{block = factory.createAutomataBlock(id, re, body, $blockDeclaration[level - 1]::env);}

+	{isBlockExtension(input.LT(1).getText())}? 

+	type = Identifier 

+	(LPAREN

+	args = varArgumentList

+	RPAREN)?

+	{block = external.createExternalBlock(type, args, $blockDeclaration[level - 1]::env);}

 	{$blockDeclaration::env = block;

 	container = new RuleElementIsolator();}

+	

 	re1 = ruleElementWithCA[container] {re = re1;}

+	

 	{RutaRule rule = factory.createRule(re, block);

-	if(block instanceof RutaAutomataBlock) {

-	((RutaAutomataBlock)block).setMatchRule(rule);

-	}

-	container.setContainer(rule);

-	}

+	block.setRule(rule);

+	container.setContainer(rule);}

+	

 	LCURLY body = statements RCURLY

 	{block.setElements(body);

-	$blockDeclaration::env.getScript().addBlock(id.getText(),block);

-

+	// really needs to know of the block?

+	//$blockDeclaration::env.getScript().addBlock(type,block);

 	}	

 	;

 

+

 	

 ruleElementWithCA[RuleElementContainer container] returns [RutaRuleElement re = null] 

     :

diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/RutaBlock.java b/ruta-core/src/main/java/org/apache/uima/ruta/RutaBlock.java
index 0fc3e7b..1398c1d 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/RutaBlock.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/RutaBlock.java
@@ -93,4 +93,5 @@
     return name;

   }

 

+ 

 }

diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataFactory.java b/ruta-core/src/main/java/org/apache/uima/ruta/extensions/IRutaBlockExtension.java
similarity index 70%
rename from ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataFactory.java
rename to ruta-core/src/main/java/org/apache/uima/ruta/extensions/IRutaBlockExtension.java
index a15892b..eb2ff83 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataFactory.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/extensions/IRutaBlockExtension.java
@@ -1,34 +1,32 @@
-/*

- * 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;

-

-import java.util.List;

-

-import org.antlr.runtime.Token;

-import org.apache.uima.ruta.rule.RutaRuleElement;

-

-public class RutaAutomataFactory extends RutaScriptFactory {

-

-  public RutaBlock createAutomataBlock(Token id, RutaRuleElement re, List<RutaStatement> body,

-          RutaBlock env) {

-    return createScriptBlock(id, re, body, env);

-  }

-

-}

+/*
+ * 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.extensions;
+
+import java.util.List;
+
+import org.apache.uima.ruta.RutaBlock;
+import org.apache.uima.ruta.expression.RutaExpression;
+
+public interface IRutaBlockExtension extends IRutaExtension {
+
+  RutaBlock createBlock(String name, List<RutaExpression> args, RutaBlock env)
+          throws RutaParseException;
+  
+}
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/extensions/RutaExternalFactory.java b/ruta-core/src/main/java/org/apache/uima/ruta/extensions/RutaExternalFactory.java
index c38bf5c..23e0626 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/extensions/RutaExternalFactory.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/extensions/RutaExternalFactory.java
@@ -24,6 +24,7 @@
 import java.util.Map;

 

 import org.antlr.runtime.Token;

+import org.apache.uima.ruta.RutaBlock;

 import org.apache.uima.ruta.action.AbstractRutaAction;

 import org.apache.uima.ruta.condition.AbstractRutaCondition;

 import org.apache.uima.ruta.expression.RutaExpression;

@@ -46,6 +47,8 @@
 

   private Map<String, IRutaNumberFunctionExtension> numberFunctionExtensions;

 

+  private Map<String, IRutaBlockExtension> blockExtensions;

+

   public RutaExternalFactory() {

     super();

     conditionExtensions = new HashMap<String, IRutaConditionExtension>();

@@ -54,6 +57,7 @@
     stringFunctionExtensions = new HashMap<String, IRutaStringFunctionExtension>();

     numberFunctionExtensions = new HashMap<String, IRutaNumberFunctionExtension>();

     typeFunctionExtensions = new HashMap<String, IRutaTypeFunctionExtension>();

+    blockExtensions = new HashMap<String, IRutaBlockExtension>();

   }

 

   public AbstractRutaCondition createExternalCondition(Token id, List<RutaExpression> args)

@@ -122,6 +126,20 @@
     return null;

   }

 

+  public RutaBlock createExternalBlock(Token type, List<RutaExpression> args, RutaBlock env)

+          throws RutaParseException {

+		if(type == null) {

+		  return null;

+		}

+		String t = type.getText();

+		IRutaBlockExtension extension = blockExtensions.get(t);

+		if(extension != null) {

+		  return extension.createBlock(t, args, env);

+		}

+		return null;

+	}

+  

+  

   public void addExtension(String id, IRutaExtension extension) {

     if (extension instanceof IRutaActionExtension) {

       addActionExtension(id, (IRutaActionExtension) extension);

@@ -135,6 +153,8 @@
       addNumberFunctionExtension(id, (IRutaNumberFunctionExtension) extension);

     } else if (extension instanceof IRutaTypeFunctionExtension) {

       addTypeFunctionExtension(id, (IRutaTypeFunctionExtension) extension);

+    } else if (extension instanceof IRutaBlockExtension) {

+      addBlockExtension(id, (IRutaBlockExtension) extension);

     }

   }

 

@@ -161,6 +181,10 @@
   public void addTypeFunctionExtension(String id, IRutaTypeFunctionExtension extension) {

     typeFunctionExtensions.put(id, extension);

   }

+  

+  public void addBlockExtension(String id, IRutaBlockExtension extension) {

+    blockExtensions.put(id, extension);

+  }

 

   public boolean isInitialized() {

     return !actionExtensions.isEmpty() || !conditionExtensions.isEmpty()

@@ -194,8 +218,8 @@
 

   public Map<String, IRutaTypeFunctionExtension> getTypeFunctionExtensions() {

     return typeFunctionExtensions;

-  }

-

+  }  

+  

   public void setTypeFunctionExtensions(Map<String, IRutaTypeFunctionExtension> typeFunctionExtensions) {

     this.typeFunctionExtensions = typeFunctionExtensions;

   }

@@ -215,5 +239,14 @@
   public void setConditionExtensions(Map<String, IRutaConditionExtension> conditionExtensions) {

     this.conditionExtensions = conditionExtensions;

   }

+  

+  public Map<String, IRutaBlockExtension> getBlockExtensions() {

+    return blockExtensions;

+  }

+

+  public void setBlockExtensions(Map<String, IRutaBlockExtension> blockExtensions) {

+    this.blockExtensions = blockExtensions;

+  }

+

 

 }

diff --git a/ruta-ep-addons/src/main/java/org/apache/uima/ruta/query/ui/QueryActionHandler.java b/ruta-ep-addons/src/main/java/org/apache/uima/ruta/query/ui/QueryActionHandler.java
index 0715a3d..0802700 100755
--- a/ruta-ep-addons/src/main/java/org/apache/uima/ruta/query/ui/QueryActionHandler.java
+++ b/ruta-ep-addons/src/main/java/org/apache/uima/ruta/query/ui/QueryActionHandler.java
@@ -48,6 +48,7 @@
 import org.apache.uima.ruta.addons.RutaAddonsPlugin;

 import org.apache.uima.ruta.engine.RutaEngine;

 import org.apache.uima.ruta.extensions.IRutaActionExtension;

+import org.apache.uima.ruta.extensions.IRutaBlockExtension;

 import org.apache.uima.ruta.extensions.IRutaBooleanFunctionExtension;

 import org.apache.uima.ruta.extensions.IRutaConditionExtension;

 import org.apache.uima.ruta.extensions.IRutaNumberFunctionExtension;

@@ -214,6 +215,8 @@
                 .getRutaStringFunctionExtensions();

         IRutaTypeFunctionExtension[] typeFunctionExtensions = RutaExtensionManager.getDefault()

                 .getRutaTypeFunctionExtensions();

+        IRutaBlockExtension[] blockExtensions = RutaExtensionManager.getDefault()

+                .getRutaBlockExtensions();

 

         List<String> languageExtensions = new ArrayList<String>();

 

@@ -235,6 +238,9 @@
         for (IRutaTypeFunctionExtension each : typeFunctionExtensions) {

           languageExtensions.add(each.getClass().getName());

         }

+        for (IRutaBlockExtension each : blockExtensions) {

+          languageExtensions.add(each.getClass().getName());

+        }

         ae.setConfigParameterValue(RutaEngine.PARAM_ADDITIONAL_EXTENSIONS,

                 languageExtensions.toArray(new String[0]));

 

diff --git a/ruta-ep-ide-ui/src/main/java/org/apache/uima/ruta/ide/validator/LanguageCheckerVisitor.java b/ruta-ep-ide-ui/src/main/java/org/apache/uima/ruta/ide/validator/LanguageCheckerVisitor.java
index 11dbf25..5314b6a 100644
--- a/ruta-ep-ide-ui/src/main/java/org/apache/uima/ruta/ide/validator/LanguageCheckerVisitor.java
+++ b/ruta-ep-ide-ui/src/main/java/org/apache/uima/ruta/ide/validator/LanguageCheckerVisitor.java
@@ -50,6 +50,7 @@
 import org.apache.uima.ruta.ide.core.RutaKeywordsManager;
 import org.apache.uima.ruta.ide.core.builder.RutaProjectUtils;
 import org.apache.uima.ruta.ide.core.extensions.IIDEActionExtension;
+import org.apache.uima.ruta.ide.core.extensions.IIDEBlockExtension;
 import org.apache.uima.ruta.ide.core.extensions.IIDEBooleanFunctionExtension;
 import org.apache.uima.ruta.ide.core.extensions.IIDEConditionExtension;
 import org.apache.uima.ruta.ide.core.extensions.IIDENumberFunctionExtension;
@@ -119,6 +120,8 @@
 
   private Map<String, IIDETypeFunctionExtension> typeFunctionExtensions;
 
+  private Map<String, IIDEBlockExtension> blockExtensions;
+  
   /**
    * Mapping from short type name (e.g. {@code W}) to their disambiguated long type names (e.g.
    * {@code org.apache.uima.ruta.type.W}).
@@ -179,6 +182,8 @@
 
   private String parentTypeInDeclaration;
 
+
+
   public LanguageCheckerVisitor(IProblemReporter problemReporter, ISourceLineTracker linetracker,
           ISourceModule sourceModule) {
     super();
@@ -748,8 +753,11 @@
     if (s instanceof RutaBlock) {
       RutaBlock b = (RutaBlock) s;
       knownLocalVariables.push(new HashMap<String, Integer>());
-      blocks.push(b.getName());
+      String name = b.getName();
+      blocks.push(name);
+      // TODO add syntax check for block extensions
     }
+    
     return true;
   }
 
@@ -1011,6 +1019,15 @@
         typeFunctionExtensions.put(string, each);
       }
     }
+    IIDEBlockExtension[] bextensions = RutaExtensionManager.getDefault()
+            .getIDEBlockExtensions();
+    for (IIDEBlockExtension each : bextensions) {
+      String[] knownExtensions = each.getKnownExtensions();
+      for (String string : knownExtensions) {
+        blockExtensions.put(string, each);
+      }
+    }
+    
 
   }
 
diff --git a/ruta-ep-ide/plugin.xml b/ruta-ep-ide/plugin.xml
index 6b75dd8..cbe8935 100644
--- a/ruta-ep-ide/plugin.xml
+++ b/ruta-ep-ide/plugin.xml
@@ -34,6 +34,7 @@
    <extension-point id="stringFunctionExtension" name="stringFunctionExtension" schema="schema/stringFunctionExtension.exsd"/>

    <extension-point id="rutaSemanticHighlighting" name="rutaSemanticHighlighting" schema="schema/rutaSemanticHighlighting.exsd"/>

    <extension-point id="rutaTestEngine" name="rutaTestEngine" schema="schema/rutaTestEngine.exsd"/>

+   <extension-point id="blockExtension" name="blockExtension" schema="schema/blockExtension.exsd"/>

    <extension

          id="nature"

          point="org.eclipse.core.resources.natures">

diff --git a/ruta-ep-ide/schema/blockExtension.exsd b/ruta-ep-ide/schema/blockExtension.exsd
new file mode 100644
index 0000000..b3ae614
--- /dev/null
+++ b/ruta-ep-ide/schema/blockExtension.exsd
@@ -0,0 +1,112 @@
+<?xml version='1.0' encoding='UTF-8'?>

+<!-- Schema file written by PDE -->

+<schema targetNamespace="org.apache.uima.ruta.ide" xmlns="http://www.w3.org/2001/XMLSchema">

+<annotation>

+      <appinfo>

+         <meta.schema plugin="org.apache.uima.ruta.ide" id="blockExtension" name="blockExtension"/>

+      </appinfo>

+      <documentation>

+         [Enter description of this extension point.]

+      </documentation>

+   </annotation>

+

+   <element name="extension">

+      <annotation>

+         <appinfo>

+            <meta.element />

+         </appinfo>

+      </annotation>

+      <complexType>

+         <sequence>

+            <element ref="block" minOccurs="1" maxOccurs="unbounded"/>

+         </sequence>

+         <attribute name="point" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+         <attribute name="id" type="string">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+            </annotation>

+         </attribute>

+         <attribute name="name" type="string">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+               <appinfo>

+                  <meta.attribute translatable="true"/>

+               </appinfo>

+            </annotation>

+         </attribute>

+      </complexType>

+   </element>

+

+   <element name="block">

+      <complexType>

+         <attribute name="class" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+               <appinfo>

+                  <meta.attribute kind="java" basedOn=":org.apache.uima.ruta.ide.core.extensions.IIDEBlockExtension"/>

+               </appinfo>

+            </annotation>

+         </attribute>

+         <attribute name="engine" type="string" use="required">

+            <annotation>

+               <documentation>

+                  

+               </documentation>

+               <appinfo>

+                  <meta.attribute kind="java" basedOn=":org.apache.uima.ruta.extensions.IRutaBlockExtension"/>

+               </appinfo>

+            </annotation>

+         </attribute>

+      </complexType>

+   </element>

+

+   <annotation>

+      <appinfo>

+         <meta.section type="since"/>

+      </appinfo>

+      <documentation>

+         [Enter the first release in which this extension point appears.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appinfo>

+         <meta.section type="examples"/>

+      </appinfo>

+      <documentation>

+         [Enter extension point usage example here.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appinfo>

+         <meta.section type="apiinfo"/>

+      </appinfo>

+      <documentation>

+         [Enter API information here.]

+      </documentation>

+   </annotation>

+

+   <annotation>

+      <appinfo>

+         <meta.section type="implementation"/>

+      </appinfo>

+      <documentation>

+         [Enter information about supplied implementation of this extension point.]

+      </documentation>

+   </annotation>

+

+

+</schema>

diff --git a/ruta-ep-ide/schema/conditionExtension.exsd b/ruta-ep-ide/schema/conditionExtension.exsd
index d215297..23b42fb 100644
--- a/ruta-ep-ide/schema/conditionExtension.exsd
+++ b/ruta-ep-ide/schema/conditionExtension.exsd
@@ -1,27 +1,9 @@
 <?xml version='1.0' encoding='UTF-8'?>

-<!--

-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.

--->

-

+<!-- Schema file written by PDE -->

 <schema targetNamespace="org.apache.uima.ruta.ide" xmlns="http://www.w3.org/2001/XMLSchema">

 <annotation>

       <appinfo>

-         <meta.schema plugin="org.apache.uima.ruta.ruta.ide" id="conditionExtension" name="conditionExtension"/>

+         <meta.schema plugin="org.apache.uima.ruta.ide" id="conditionExtension" name="conditionExtension"/>

       </appinfo>

       <documentation>

          [Enter description of this extension point.]

@@ -73,7 +55,7 @@
                   

                </documentation>

                <appinfo>

-                  <meta.attribute kind="java" basedOn=":org.apache.uima.ruta.ruta.ide.core.extensions.IIDEConditionExtension"/>

+                  <meta.attribute kind="java" basedOn=":org.apache.uima.ruta.ide.core.extensions.IIDEConditionExtension"/>

                </appinfo>

             </annotation>

          </attribute>

diff --git a/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g b/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g
index 341c92f..666e482 100644
--- a/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g
+++ b/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaLexer.g
@@ -331,7 +331,6 @@
 EngineString  : 'ENGINE';

 UimafitString : 'UIMAFIT';

 BlockString   : 'BLOCK';

-AutomataBlockString   : 'RULES';

 TypeString  : 'TYPE';

 IntString : 'INT';

 DoubleString  : 'DOUBLE';

diff --git a/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g b/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g
index 56cfabd..99f0973 100644
--- a/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g
+++ b/ruta-ep-ide/src/main/antlr3/org/apache/uima/ruta/ide/core/parser/RutaParser.g
@@ -28,6 +28,7 @@
 

 package org.apache.uima.ruta.ide.core.parser;

 import java.util.ArrayList;

+import java.util.Collection;

 import java.util.HashMap;

 import java.util.List;

 import java.util.Map;

@@ -85,6 +86,7 @@
 	private Map<String, String> varTypeMap = new HashMap<String, String>();

 	private Map<String, String> lists = new HashMap<String, String>();

 	private Map<String, String> tables = new HashMap<String, String>();

+	private Collection<String> knownExternalBlocks = new ArrayList();

 	public int length;

 	public DLTKTokenConverter converter;

 	public DescriptorManager descriptor;

@@ -96,6 +98,14 @@
 	

 	private ScriptFactory scriptFactory = new ScriptFactory();

 	

+	public void setKnownExternalBlocks(Collection<String> knownExternalBlocks) {

+		this.knownExternalBlocks = knownExternalBlocks;

+	}

+	

+	private boolean isBlockExtension(String name) {

+		return knownExternalBlocks.contains(name);

+	}

+	

 	public List<String> getVariables() {

 		return vars;

 	}

@@ -301,7 +311,7 @@
 	( stmts1 = declaration {stmts.addAll(stmts1);}

 	| stmtVariable = variableDeclaration {stmts.addAll(stmtVariable);}

 	| stmt3 = blockDeclaration {stmts.add(stmt3);}

-	//| stmt4 = tmRule {stmts.add(stmt4);}

+	| (externalBlock)=> stmt4 = externalBlock {stmts.add(stmt4);}

 	| stmt2 = simpleStatement {stmts.add(stmt2);}

 	

 

@@ -551,7 +561,7 @@
 }

 	:

 

-	(declareToken = BlockString | declareToken = AutomataBlockString)

+	(declareToken = BlockString)

 	LPAREN

 	id = Identifier {addVariable(id.getText(), declareToken.getText());}

 	{

@@ -562,11 +572,38 @@
 	re1 = ruleElementWithCA

 	{

 	rule = scriptFactory.createRule(re1);

-	scriptFactory.finalizeScriptBlock(block, rc, rule, body);}

+	scriptFactory.finalizeBlock(block, rc, rule, body);}

 	LCURLY body = statements rc = RCURLY

-	{scriptFactory.finalizeScriptBlock(block, rc, rule, body);}

+	{scriptFactory.finalizeBlock(block, rc, rule, body);}

 	;

 

+externalBlock returns [RutaBlock block = null]

+options{

+	backtrack = true;

+}

+

+@init{

+RutaRule rule = null;

+

+}

+@after {

+

+}

+	:

+	{isBlockExtension(input.LT(1).getText())}? 

+	(type = Identifier)

+	{block = scriptFactory.createExternalBlock(type, $blockDeclaration[level]::env);

+		$blockDeclaration::env = block;}

+	(LPAREN

+	args = varArgumentList  {block.setArguments(args);}

+	RPAREN)?

+	re1 = ruleElementWithCA

+	{

+	rule = scriptFactory.createRule(re1);

+	scriptFactory.finalizeBlock(block, rc, rule, body);}

+	LCURLY body = statements rc = RCURLY

+	{scriptFactory.finalizeBlock(block, rc, rule, body);}

+	;

 	

 ruleElementWithCA returns [RutaRuleElement re = null] 

     :

diff --git a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaExtensionManager.java b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaExtensionManager.java
index aa3a31c..fbf2c4f 100644
--- a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaExtensionManager.java
+++ b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaExtensionManager.java
@@ -25,6 +25,7 @@
 

 import org.apache.uima.ruta.extensions.IEngineLoader;

 import org.apache.uima.ruta.extensions.IRutaActionExtension;

+import org.apache.uima.ruta.extensions.IRutaBlockExtension;

 import org.apache.uima.ruta.extensions.IRutaBooleanFunctionExtension;

 import org.apache.uima.ruta.extensions.IRutaConditionExtension;

 import org.apache.uima.ruta.extensions.IRutaNumberFunctionExtension;

@@ -33,6 +34,7 @@
 import org.apache.uima.ruta.ide.RutaIdeCorePlugin;

 import org.apache.uima.ruta.ide.core.extensions.ICompletionExtension;

 import org.apache.uima.ruta.ide.core.extensions.IIDEActionExtension;

+import org.apache.uima.ruta.ide.core.extensions.IIDEBlockExtension;

 import org.apache.uima.ruta.ide.core.extensions.IIDEBooleanFunctionExtension;

 import org.apache.uima.ruta.ide.core.extensions.IIDEConditionExtension;

 import org.apache.uima.ruta.ide.core.extensions.IIDENumberFunctionExtension;

@@ -269,6 +271,27 @@
     return result.toArray(new IIDETypeFunctionExtension[0]);

   }

 

+  public IIDEBlockExtension[] getIDEBlockExtensions() {

+    Collection<IIDEBlockExtension> result = new ArrayList<IIDEBlockExtension>();

+    IExtension[] blockExtensions = Platform.getExtensionRegistry()

+            .getExtensionPoint(RutaIdeCorePlugin.PLUGIN_ID, "blockExtension").getExtensions();

+    for (IExtension extension : blockExtensions) {

+      IConfigurationElement[] configurationElements = extension.getConfigurationElements();

+      for (IConfigurationElement configurationElement : configurationElements) {

+        Object obj = null;

+        try {

+          obj = configurationElement.createExecutableExtension("class");

+        } catch (CoreException e) {

+          e.printStackTrace();

+        }

+        if (obj instanceof IIDEBlockExtension) {

+          result.add((IIDEBlockExtension) obj);

+        }

+      }

+    }

+    return result.toArray(new IIDEBlockExtension[0]);

+  }

+  

   public IRutaConditionExtension[] getRutaConditionExtensions() {

     Collection<IRutaConditionExtension> result = new ArrayList<IRutaConditionExtension>();

     IExtension[] conditionExtensions = Platform.getExtensionRegistry()

@@ -394,6 +417,27 @@
     }

     return result.toArray(new IRutaTypeFunctionExtension[0]);

   }

+  

+  public IRutaBlockExtension[] getRutaBlockExtensions() {

+    Collection<IRutaBlockExtension> result = new ArrayList<IRutaBlockExtension>();

+    IExtension[] extensions = Platform.getExtensionRegistry()

+            .getExtensionPoint(RutaIdeCorePlugin.PLUGIN_ID, "blockExtension").getExtensions();

+    for (IExtension extension : extensions) {

+      IConfigurationElement[] configurationElements = extension.getConfigurationElements();

+      for (IConfigurationElement configurationElement : configurationElements) {

+        Object obj = null;

+        try {

+          obj = configurationElement.createExecutableExtension("engine");

+        } catch (CoreException e) {

+          e.printStackTrace();

+        }

+        if (obj instanceof IRutaBlockExtension) {

+          result.add((IRutaBlockExtension) obj);

+        }

+      }

+    }

+    return result.toArray(new IRutaBlockExtension[0]);

+  }

 

   public IEngineLoader[] getEngineExtensions() {

     Collection<IEngineLoader> result = new ArrayList<IEngineLoader>();

diff --git a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaKeywords.java b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaKeywords.java
index f622852..5258692 100644
--- a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaKeywords.java
+++ b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaKeywords.java
@@ -28,7 +28,7 @@
 

   private static String[] declaration = { "WORDLIST", "DECLARE", "BOOLEAN", "PACKAGE", "TYPE",

       "TYPESYSTEM", "INT", "DOUBLE", "FLOAT", "STRING", "SCRIPT", "WORDTABLE", "ENGINE", "BLOCK",

-      "RULES", "BOOLEANLIST", "INTLIST", "DOUBLELIST", "FLOATLIST", "STRINGLIST", "TYPELIST",

+      "BOOLEANLIST", "INTLIST", "DOUBLELIST", "FLOATLIST", "STRINGLIST", "TYPELIST",

       "UIMAFIT", "IMPORT" , "FROM", "AS" };

 

   private static String[] action = { "DEL", "CALL", "MARK", "MARKSCORE", "COLOR", "LOG", "REPLACE",

diff --git a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaKeywordsManager.java b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaKeywordsManager.java
index 2b7fc4b..9d1165e 100644
--- a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaKeywordsManager.java
+++ b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/RutaKeywordsManager.java
@@ -20,6 +20,7 @@
 package org.apache.uima.ruta.ide.core;

 

 import org.apache.uima.ruta.extensions.IRutaActionExtension;

+import org.apache.uima.ruta.extensions.IRutaBlockExtension;

 import org.apache.uima.ruta.extensions.IRutaBooleanFunctionExtension;

 import org.apache.uima.ruta.extensions.IRutaConditionExtension;

 import org.apache.uima.ruta.extensions.IRutaNumberFunctionExtension;

@@ -107,6 +108,13 @@
       all[IRutaKeywords.TYPEFUNCTION] = RutaKeywords.append(all[IRutaKeywords.TYPEFUNCTION],

               knownExtensions);

     }

+    IRutaBlockExtension[] blockExtensions = RutaExtensionManager.getDefault()

+            .getRutaBlockExtensions();

+    for (IRutaBlockExtension each : blockExtensions) {

+      String[] knownExtensions = each.getKnownExtensions();

+      all[IRutaKeywords.DECLARATION] = RutaKeywords.append(all[IRutaKeywords.DECLARATION],

+              knownExtensions);

+    }

   }

 

   public static String[] getKeywords() {

diff --git a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/builder/RutaBuilder.java b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/builder/RutaBuilder.java
index f252921..9174ecd 100644
--- a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/builder/RutaBuilder.java
+++ b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/builder/RutaBuilder.java
@@ -25,6 +25,7 @@
 import org.apache.uima.ruta.engine.RutaEngine;

 import org.apache.uima.ruta.extensions.IEngineLoader;

 import org.apache.uima.ruta.extensions.IRutaActionExtension;

+import org.apache.uima.ruta.extensions.IRutaBlockExtension;

 import org.apache.uima.ruta.extensions.IRutaBooleanFunctionExtension;

 import org.apache.uima.ruta.extensions.IRutaConditionExtension;

 import org.apache.uima.ruta.extensions.IRutaNumberFunctionExtension;

@@ -193,6 +194,8 @@
             .getRutaStringFunctionExtensions();

     IRutaTypeFunctionExtension[] typeFunctionExtensions = RutaExtensionManager.getDefault()

             .getRutaTypeFunctionExtensions();

+    IRutaBlockExtension[] blockExtensions = RutaExtensionManager.getDefault()

+            .getRutaBlockExtensions();

     IEngineLoader[] engineExtensions = RutaExtensionManager.getDefault().getEngineExtensions();

 

     List<String> language = new ArrayList<String>();

@@ -216,6 +219,9 @@
     for (IRutaTypeFunctionExtension each : typeFunctionExtensions) {

       language.add(each.getClass().getName());

     }

+    for (IRutaBlockExtension each : blockExtensions) {

+      language.add(each.getClass().getName());

+    }

     for (IEngineLoader each : engineExtensions) {

       engines.add(each.getClass().getName());

     }

diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataFactory.java b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/extensions/IIDEBlockExtension.java
similarity index 67%
copy from ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataFactory.java
copy to ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/extensions/IIDEBlockExtension.java
index a15892b..69c68b0 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/RutaAutomataFactory.java
+++ b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/extensions/IIDEBlockExtension.java
@@ -1,34 +1,24 @@
-/*

- * 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;

-

-import java.util.List;

-

-import org.antlr.runtime.Token;

-import org.apache.uima.ruta.rule.RutaRuleElement;

-

-public class RutaAutomataFactory extends RutaScriptFactory {

-

-  public RutaBlock createAutomataBlock(Token id, RutaRuleElement re, List<RutaStatement> body,

-          RutaBlock env) {

-    return createScriptBlock(id, re, body, env);

-  }

-

-}

+/*
+ * 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.ide.core.extensions;
+
+public interface IIDEBlockExtension extends IRutaExtension {
+
+}
diff --git a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/parser/RutaSourceParser.java b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/parser/RutaSourceParser.java
index 9371e3e..77e1954 100644
--- a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/parser/RutaSourceParser.java
+++ b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/core/parser/RutaSourceParser.java
@@ -20,6 +20,9 @@
 package org.apache.uima.ruta.ide.core.parser;

 

 import java.io.File;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.Collection;

 import java.util.List;

 import java.util.Map;

 

@@ -28,7 +31,10 @@
 import org.antlr.runtime.CommonTokenStream;

 import org.antlr.runtime.Token;

 import org.apache.uima.ruta.engine.RutaEngine;

+import org.apache.uima.ruta.extensions.IRutaBlockExtension;

 import org.apache.uima.ruta.ide.core.IRutaKeywords;

+import org.apache.uima.ruta.ide.core.RutaExtensionManager;

+import org.apache.uima.ruta.ide.core.RutaKeywords;

 import org.apache.uima.ruta.ide.core.RutaKeywordsManager;

 import org.apache.uima.ruta.ide.core.builder.DescriptorManager;

 import org.apache.uima.ruta.ide.parser.ast.RutaModuleDeclaration;

@@ -108,6 +114,14 @@
       variables.add(each);

       variableTypes.put(each, "TYPEFUNCTION");

     }

+    Collection<String> knownExternalBlocks = new ArrayList<String>();

+    IRutaBlockExtension[] blockExtensions = RutaExtensionManager.getDefault()

+            .getRutaBlockExtensions();

+    for (IRutaBlockExtension each : blockExtensions) {

+      String[] knownExtensions = each.getKnownExtensions();

+      knownExternalBlocks.addAll(Arrays.asList(knownExtensions));

+    }

+    parser.setKnownExternalBlocks(knownExternalBlocks);

     parser.addPredefinedType("Document");

     parser.addPredefinedType("Annotation");

 

diff --git a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/RutaBlock.java b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/RutaBlock.java
index 463d786..38a32df 100644
--- a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/RutaBlock.java
+++ b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/RutaBlock.java
@@ -19,9 +19,12 @@
 

 package org.apache.uima.ruta.ide.parser.ast;

 

+import java.util.List;

+

 import org.apache.commons.lang3.StringUtils;

 import org.eclipse.dltk.ast.ASTVisitor;

 import org.eclipse.dltk.ast.declarations.MethodDeclaration;

+import org.eclipse.dltk.ast.expressions.Expression;

 

 public class RutaBlock extends MethodDeclaration {

 

@@ -29,6 +32,8 @@
 

   private String namespace;

 

+  private List<Expression> args;

+

   public RutaBlock(String name, String namespace, int nameStart, int nameEnd, int declStart,

           int declEnd) {

     super(name, nameStart, nameEnd, declStart, declEnd);

@@ -46,6 +51,11 @@
       if (rule != null) {

         rule.traverse(visitor);

       }

+      if(args != null) {

+        for (Expression each : args) {

+          each.traverse(visitor);

+        }

+      }

       traverseChildNodes(visitor);

       visitor.endvisit(this);

     }

@@ -69,4 +79,10 @@
   public String toString() {

     return this.getClass().getSimpleName() + " : " + super.toString();

   }

+

+

+  public void setArguments(List<Expression> args) {

+    this.args = args;

+    

+  }

 }

diff --git a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/ScriptFactory.java b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/ScriptFactory.java
index a8484a9..d3b2911 100644
--- a/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/ScriptFactory.java
+++ b/ruta-ep-ide/src/main/java/org/apache/uima/ruta/ide/parser/ast/ScriptFactory.java
@@ -39,8 +39,7 @@
   public void resetRuleCounter() {

     idCounter = 0;

   }

-  

-  

+

   public RutaRule createRule(RutaRuleElement element) {

     List<Expression> elements = new ArrayList<Expression>();

     elements.add(element);

@@ -49,7 +48,7 @@
 

   public RutaRule createRule(List<Expression> elements, Token s, boolean updateCounter) {

     RutaRule rule = new RutaRule(elements, idCounter);

-    if(updateCounter) {

+    if (updateCounter) {

       idCounter++;

     }

     if (s != null) {

@@ -58,7 +57,7 @@
     }

     return rule;

   }

-  

+

   public RutaRule createRule(List<Expression> elements, Token s) {

     return createRule(elements, s, true);

   }

@@ -152,7 +151,7 @@
     filterNullObjects(c);

     filterNullObjects(a);

     RutaRuleElement rutaRuleElement = new RutaRuleElement(bounds[0], bounds[1], null, null, c, a);

-    if(w != null && w.getText().equals("#")) {

+    if (w != null && w.getText().equals("#")) {

       rutaRuleElement.setWildcard(true);

     }

     return rutaRuleElement;

@@ -184,7 +183,7 @@
    * @param id

    * @param type

    * @param rutaBlock

-   * @return

+   * @return RutaBlock

    */

   public RutaBlock createScriptBlock(Token id, Token type, RutaBlock rutaBlock) {

     int[] bounds = getBounds(type, id);

@@ -200,7 +199,21 @@
     }

   }

 

-  public void finalizeScriptBlock(RutaBlock block, Token rc, RutaRule rule, List<Statement> body) {

+  /**

+   * Creates an AST element for an external block construct

+   * @param type

+   * @param parent block

+   * @return new external block construct

+   */

+  public RutaBlock createExternalBlock(Token type, RutaBlock env) {

+    int[] bounds = getBounds(type);

+    int[] nameBounds = getBounds(type);

+    RutaBlock block = new RutaBlock(type.getText(), type.getText(), nameBounds[0], nameBounds[1],

+            bounds[0], bounds[1]);

+    return block;

+  }

+

+  public void finalizeBlock(RutaBlock block, Token rc, RutaRule rule, List<Statement> body) {

     // taking care of null statements - errors should have been recognized

     // in parser

     filterNullObjects(body);