Merge pull request #160 from apache/bugfix/159-Assignment-of-composed-number-expression-is-broken
Issue #159: Assignment of composed number expression is broken
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 4627ba1..9bc7782 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
@@ -2431,7 +2431,7 @@
| match = dottedIdWithIndex2 (comp = LESS | comp = GREATER | comp = GREATEREQUAL | comp = LESSEQUAL |comp = EQUAL | comp = NOTEQUAL) arg = argument
{MatchReference mr = expressionFactory.createMatchReference(match, comp, arg);
expr = expressionFactory.createAnnotationTypeExpression(mr);}
- | (complexStringExpression) => cse = complexStringExpression {expr = cse;}
+ | (genericComposedExpression) => gce = genericComposedExpression {expr = gce;}
| (featureExpression)=> fe = featureExpression {expr = expressionFactory.createGenericFeatureExpression(fe);}
| a2 = booleanExpression {expr = a2;}
| a3 = numberExpression {expr = a3;}
@@ -2720,6 +2720,14 @@
;
+complexNumberExpression returns [INumberExpression expr = null]
+@init{List<INumberExpression> exprs = new ArrayList<INumberExpression>();
+ List<Token> ops = new ArrayList<Token>();}
+ :
+ e = multiplicativeExpression{exprs.add(e);} ((PLUS | MINUS)=> op = (PLUS | MINUS){ops.add(op);} e = multiplicativeExpression{exprs.add(e);} )+
+ {expr = expressionFactory.createComposedNumberExpression(exprs,ops);}
+ ;
+
additiveExpression returns [INumberExpression expr = null]
@init{List<INumberExpression> exprs = new ArrayList<INumberExpression>();
List<Token> ops = new ArrayList<Token>();}
@@ -2778,7 +2786,7 @@
|(e = stringFunction)=> e = stringFunction{expr = e;}
;
-complexStringExpression returns [IStringExpression expr = null]
+genericComposedExpression returns [IRutaExpression expr = null]
options {
backtrack = true;
}
@@ -2786,7 +2794,7 @@
:
a1 = simpleArgument {list.add(a1);}
((PLUS)=>PLUS an = simpleArgument {list.add(an);})+
- {expr = expressionFactory.createGenericComposedStringExpression(list);}
+ {expr = expressionFactory.createGenericComposedExpression(list);}
;
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/condition/ConditionFactory.java b/ruta-core/src/main/java/org/apache/uima/ruta/condition/ConditionFactory.java
index 3cde11f..e61c247 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/condition/ConditionFactory.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/condition/ConditionFactory.java
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/expression/ExpressionFactory.java b/ruta-core/src/main/java/org/apache/uima/ruta/expression/ExpressionFactory.java
index cf752cf..e990b75 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/expression/ExpressionFactory.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/expression/ExpressionFactory.java
@@ -181,13 +181,15 @@
for (IRutaExpression each : expressions) {
if (each instanceof IStringExpression) {
stringExpression.add((IStringExpression) each);
- } else {
- System.out.println();
}
}
return new ComposedStringExpression(stringExpression);
}
+ public IRutaExpression createGenericComposedExpression(List<IRutaExpression> list) {
+ return new GenericComposedExpression(list);
+ }
+
public AbstractStringExpression createReferenceStringExpression(Token var) {
return new StringVariableExpression(var.getText());
}
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/expression/GenericComposedExpression.java b/ruta-core/src/main/java/org/apache/uima/ruta/expression/GenericComposedExpression.java
new file mode 100644
index 0000000..d9c007a
--- /dev/null
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/expression/GenericComposedExpression.java
@@ -0,0 +1,83 @@
+/*
+ * 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.expression;
+
+import java.util.List;
+
+import org.apache.uima.ruta.RutaStream;
+import org.apache.uima.ruta.expression.number.INumberExpression;
+import org.apache.uima.ruta.expression.string.IStringExpression;
+import org.apache.uima.ruta.rule.MatchContext;
+
+public class GenericComposedExpression extends RutaExpression implements INumberExpression {
+
+ private final List<IRutaExpression> expressions;
+
+ public GenericComposedExpression(List<IRutaExpression> expressions) {
+ super();
+ this.expressions = expressions;
+ }
+
+ @Override
+ public String getStringValue(MatchContext context, RutaStream stream) {
+ if (expressions == null) {
+ return null;
+ }
+ if (expressions.size() == 1) {
+ IRutaExpression first = expressions.get(0);
+ if (first instanceof IStringExpression) {
+ return ((IStringExpression) first).getStringValue(context, stream);
+ }
+ return null;
+ }
+ StringBuilder result = new StringBuilder();
+ for (IRutaExpression each : expressions) {
+ if (each instanceof IStringExpression) {
+ result.append(((IStringExpression) each).getStringValue(context, stream));
+ }
+ }
+ return result.toString();
+ }
+
+ @Override
+ public int getIntegerValue(MatchContext context, RutaStream stream) {
+ return (int) getDoubleValue(context, stream);
+ }
+
+ @Override
+ public double getDoubleValue(MatchContext context, RutaStream stream) {
+ double result = 0;
+ for (IRutaExpression each : expressions) {
+ if (each instanceof INumberExpression) {
+ result += ((INumberExpression) each).getDoubleValue(context, stream);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public float getFloatValue(MatchContext context, RutaStream stream) {
+ return (float) getDoubleValue(context, stream);
+ }
+
+ public List<IRutaExpression> getExpressions() {
+ return expressions;
+ }
+}
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/utils/UIMAUtils.java b/ruta-core/src/main/java/org/apache/uima/ruta/utils/UIMAUtils.java
index cac0a9a..5a3bccc 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/utils/UIMAUtils.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/utils/UIMAUtils.java
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -33,7 +33,7 @@
public static FSArray<? extends FeatureStructure> toFSArray(JCas jCas,
List<? extends FeatureStructure> fsList) {
- FSArray<FeatureStructure> fsArray = new FSArray<FeatureStructure>(jCas, fsList.size());
+ FSArray<FeatureStructure> fsArray = new FSArray<>(jCas, fsList.size());
fsArray.copyFromArray(fsList.toArray(new FeatureStructure[fsList.size()]), 0, 0, fsList.size());
return fsArray;
}
@@ -58,7 +58,7 @@
public static <T extends FeatureStructure> List<T> toList(FSArray<FeatureStructure> fsArray,
Class<T> cls) {
- List<T> list = new ArrayList<T>();
+ List<T> list = new ArrayList<>();
if (fsArray == null) {
return list;
}
diff --git a/ruta-core/src/main/java/org/apache/uima/ruta/verbalize/ExpressionVerbalizer.java b/ruta-core/src/main/java/org/apache/uima/ruta/verbalize/ExpressionVerbalizer.java
index 2e8cba7..c4b3a94 100644
--- a/ruta-core/src/main/java/org/apache/uima/ruta/verbalize/ExpressionVerbalizer.java
+++ b/ruta-core/src/main/java/org/apache/uima/ruta/verbalize/ExpressionVerbalizer.java
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -20,10 +20,13 @@
package org.apache.uima.ruta.verbalize;
import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.uima.cas.CAS;
import org.apache.uima.ruta.expression.AnnotationTypeExpression;
+import org.apache.uima.ruta.expression.GenericComposedExpression;
import org.apache.uima.ruta.expression.IRutaExpression;
import org.apache.uima.ruta.expression.MatchReference;
import org.apache.uima.ruta.expression.NullExpression;
@@ -83,6 +86,8 @@
public String verbalize(IRutaExpression expression) {
if (expression instanceof NullExpression) {
return "null";
+ } else if (expression instanceof GenericComposedExpression) {
+ return verbalize((GenericComposedExpression) expression);
} else if (expression instanceof GenericFeatureExpression) {
return verbalize(((GenericFeatureExpression) expression).getFeatureExpression());
} else if (expression instanceof AnnotationTypeExpression) {
@@ -336,4 +341,9 @@
+ verbalize(expression.getArg());
}
+ public String verbalize(GenericComposedExpression expression) {
+ GenericComposedExpression gce = expression;
+ List<IRutaExpression> expressions = gce.getExpressions();
+ return expressions.stream().map(e -> verbalize(e)).collect(Collectors.joining("+"));
+ }
}
diff --git a/ruta-core/src/test/java/org/apache/uima/ruta/expression/number/ComposedNumberExpressionTest.java b/ruta-core/src/test/java/org/apache/uima/ruta/expression/number/ComposedNumberExpressionTest.java
index 7c8f79e..73e93d0 100644
--- a/ruta-core/src/test/java/org/apache/uima/ruta/expression/number/ComposedNumberExpressionTest.java
+++ b/ruta-core/src/test/java/org/apache/uima/ruta/expression/number/ComposedNumberExpressionTest.java
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -31,7 +31,7 @@
public void testGetStringValueWithInteger() {
List<INumberExpression> list = new ArrayList<>();
list.add(new SimpleNumberExpression(Integer.valueOf(1)));
- ComposedNumberExpression expr = new ComposedNumberExpression(list, new ArrayList<String>());
+ ComposedNumberExpression expr = new ComposedNumberExpression(list, new ArrayList<>());
String string = expr.getStringValue(null, null);
assertThat(string).isEqualTo("1");
}
diff --git a/ruta-core/src/test/java/org/apache/uima/ruta/expression/number/NumberExpressionTest.java b/ruta-core/src/test/java/org/apache/uima/ruta/expression/number/NumberExpressionTest.java
new file mode 100644
index 0000000..76c3855
--- /dev/null
+++ b/ruta-core/src/test/java/org/apache/uima/ruta/expression/number/NumberExpressionTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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.expression.number;
+
+import org.apache.uima.cas.CAS;
+import org.apache.uima.ruta.engine.Ruta;
+import org.apache.uima.ruta.engine.RutaTestUtils;
+import org.junit.jupiter.api.Test;
+
+public class NumberExpressionTest {
+
+ @Test
+ public void testComposedAssignment() throws Exception {
+ String script = "INT i = 1;";
+ script += "Document{i==2 -> T1};";
+ script += "Document{-> i = i + 1};";
+ script += "Document{i==2 -> T2};";
+ script += "Document{-> i = 1 + 1 + 1};";
+ script += "Document{i==3 -> T3};";
+ script += "Document{i== 1+1+1 -> T4};";
+ script += "Document{i== 1+i-1 -> T5};";
+ script += "Document{-> i = (1 + 1 * 3) / 2};";
+ script += "Document{i== 8 / 4 -> T6};";
+ CAS cas = RutaTestUtils.getCAS("This is a test.");
+ Ruta.apply(cas, script);
+
+ RutaTestUtils.assertAnnotationsEquals(cas, 1, 0);
+ RutaTestUtils.assertAnnotationsEquals(cas, 2, 1, "This is a test.");
+ RutaTestUtils.assertAnnotationsEquals(cas, 3, 1, "This is a test.");
+ RutaTestUtils.assertAnnotationsEquals(cas, 4, 1, "This is a test.");
+ RutaTestUtils.assertAnnotationsEquals(cas, 5, 1, "This is a test.");
+ RutaTestUtils.assertAnnotationsEquals(cas, 6, 1, "This is a test.");
+ }
+
+}
diff --git a/ruta-core/src/test/java/org/apache/uima/ruta/verbalizer/ExpressionVerbalizerTest.java b/ruta-core/src/test/java/org/apache/uima/ruta/verbalizer/ExpressionVerbalizerTest.java
index 6e8c541..8ad8681 100644
--- a/ruta-core/src/test/java/org/apache/uima/ruta/verbalizer/ExpressionVerbalizerTest.java
+++ b/ruta-core/src/test/java/org/apache/uima/ruta/verbalizer/ExpressionVerbalizerTest.java
@@ -6,9 +6,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -22,8 +22,10 @@
import static org.assertj.core.api.Assertions.assertThat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
+import org.apache.uima.ruta.expression.GenericComposedExpression;
import org.apache.uima.ruta.expression.MatchReference;
import org.apache.uima.ruta.expression.annotation.AnnotationLabelExpression;
import org.apache.uima.ruta.expression.annotation.AnnotationVariableExpression;
@@ -67,49 +69,16 @@
@Test
public void test() {
RutaVerbalizer v = new RutaVerbalizer();
- // List<TypeExpression> typeExprList = new ArrayList<TypeExpression>();
- // List<StringExpression> stringExprList = new ArrayList<StringExpression>();
- // List<RutaExpression> exprList = new ArrayList<RutaExpression>();
- // List<INumberExpression> indexes = new ArrayList<INumberExpression>();
-
- //
- // // typeExprList.add(typeExpr1);
- // // typeExprList.add(typeExpr2);
- //
- //
- // StringExpression stringExpr = new SimpleStringExpression("string");
- // stringExprList.add(stringExpr);
- // // exprList.add(typeExpr1);
- // WordTableExpression wordTableExpr = new ReferenceWordTableExpression(var);
- // WordListExpression wordListExpr = new ReferenceWordListExpression(var);
- // TypeListExpression typeListExpr = new SimpleTypeListExpression(typeExprList);
- // StringListExpression stringListExpr = new SimpleStringListExpression(stringExprList);
- // Map<StringExpression, RutaExpression> stringExprMap = new HashMap<StringExpression,
- // RutaExpression>();
- // Map<StringExpression, INumberExpression> stringExprNumExprMap = new HashMap<StringExpression,
- // INumberExpression>();
- // Map<StringExpression, TypeExpression> stringExprTypeExprMap = new HashMap<StringExpression,
- // TypeExpression>();
- // @SuppressWarnings("rawtypes")
- // ListExpression listExpr = new SimpleTypeListExpression(typeExprList);
- // @SuppressWarnings("rawtypes")
- // List<ListExpression> listExprList = new ArrayList<ListExpression>();
- // listExprList.add(listExpr);
- // stringExprMap.put(stringExpr, stringExpr);
- // // stringExprNumExprMap.put(stringExpr, numExpr1);
- // // stringExprTypeExprMap.put(stringExpr, typeExpr1);
- // // indexes.add(numExpr1);
- // // indexes.add(numExpr2);
String s = null;
String var = "anyVar";
ITypeExpression typeExpr1 = new SimpleTypeExpression("Type1");
ITypeExpression typeExpr2 = new TypeVariableExpression("typeVar");
- List<INumberExpression> numExprList1 = new ArrayList<INumberExpression>();
- List<INumberExpression> numExprList2 = new ArrayList<INumberExpression>();
- List<String> opList1 = new ArrayList<String>();
- List<String> opList2 = new ArrayList<String>();
+ List<INumberExpression> numExprList1 = new ArrayList<>();
+ List<INumberExpression> numExprList2 = new ArrayList<>();
+ List<String> opList1 = new ArrayList<>();
+ List<String> opList2 = new ArrayList<>();
INumberExpression numExpr1 = new SimpleNumberExpression(4);
INumberExpression numExpr2 = new NumberVariableExpression("numVar");
INumberExpression numExpr3 = new NumberVariableExpression("4.9");
@@ -171,7 +140,7 @@
s = v.verbalize(boolExpr11);
assertThat(s).isEqualTo("Type1 != typeVar");
- List<IStringExpression> stringExprList = new ArrayList<IStringExpression>();
+ List<IStringExpression> stringExprList = new ArrayList<>();
AbstractStringExpression stringExpr1 = new SimpleStringExpression("string");
AbstractStringExpression stringExpr2 = new StringVariableExpression(var);
stringExprList.add(stringExpr1);
@@ -192,7 +161,7 @@
s = v.verbalize(sle2);
assertThat(s).isEqualTo("anyVar");
- List<IBooleanExpression> boolExprList = new ArrayList<IBooleanExpression>();
+ List<IBooleanExpression> boolExprList = new ArrayList<>();
boolExprList.add(boolExpr1);
boolExprList.add(boolExpr3);
AbstractBooleanListExpression ble1 = new SimpleBooleanListExpression(boolExprList);
@@ -202,7 +171,7 @@
s = v.verbalize(ble2);
assertThat(s).isEqualTo("anyVar");
- List<INumberExpression> numExprList = new ArrayList<INumberExpression>();
+ List<INumberExpression> numExprList = new ArrayList<>();
numExprList.add(numExpr1);
numExprList.add(numExpr3);
AbstractNumberListExpression nle1 = new SimpleNumberListExpression(numExprList);
@@ -212,7 +181,7 @@
s = v.verbalize(nle2);
assertThat(s).isEqualTo("anyVar");
- List<ITypeExpression> typeExprList = new ArrayList<ITypeExpression>();
+ List<ITypeExpression> typeExprList = new ArrayList<>();
typeExprList.add(typeExpr1);
typeExprList.add(typeExpr2);
AbstractTypeListExpression tle1 = new SimpleTypeListExpression(typeExprList);
@@ -243,4 +212,22 @@
assertThat(v.verbalize(new GenericFeatureExpression(null))).isEqualTo("");
}
+ @Test
+ public void testGenericComposedExpression() {
+ RutaVerbalizer v = new RutaVerbalizer();
+ assertThat(v.verbalize(new GenericComposedExpression(
+ Arrays.asList(new SimpleStringExpression("a"), new SimpleStringExpression("b")))))
+ .isEqualTo("\"a\"+\"b\"");
+ assertThat(v.verbalize(new GenericComposedExpression(
+ Arrays.asList(new SimpleNumberExpression(1), new SimpleNumberExpression(2)))))
+ .isEqualTo("1+2");
+ assertThat(v.verbalize(new GenericComposedExpression(
+ Arrays.asList(new SimpleStringExpression("a"), new SimpleNumberExpression(2)))))
+ .isEqualTo("\"a\"+2");
+ assertThat(v.verbalize(new GenericComposedExpression(
+ Arrays.asList(new SimpleFeatureExpression(new MatchReference("abc.d")),
+ new AnnotationVariableExpression("l"))))).isEqualTo("abc.d+l");
+ assertThat(v.verbalize(new GenericFeatureExpression(null))).isEqualTo("");
+ }
+
}