Hi Mike
name~'(?i)ferry terminal' & !(highway=bus_stop) {echotags 'Trigger 3'} - this
works fine
!(highway=bus_stop) & name~'(?i)ferry terminal' {echotags 'Trigger 4'} - this fails
with an error "Invalid rule
Expression" (without explaining what the error was)
Is it possible to fix this one as well?
Yes I can fix that one in exactly the same way. Patch attached.
There are a few cases which use ! that could work but will not.
Eg !(highway!=primary) could work as it is the same as highway=primary.
Steve
Index: test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java (revision 3976)
+++ test/uk/me/parabola/mkgmap/osmstyle/RuleFileReaderTest.java (revision )
@@ -357,15 +357,12 @@
assertEquals(2, type.getType());
}
- @Test
+ @Test(expected = SyntaxException.class)
public void testNEAtTop() {
- RuleSet rs = makeRuleSet("QUOTA != 'fred' [0x2]");
- Element el = new Way(1);
- el.addTag("QUOTA", "tom");
-
- GType type = getFirstType(rs, el);
- assertNotNull(type);
- assertEquals(2, type.getType());
+ // This is not allowed, in spite of the commit comment that introduced
+ // this test. It should also match an element with no tags and that
+ // is not allowed.
+ makeRuleSet("QUOTA != 'fred' [0x2]");
}
@Test
Index: src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java (revision 3976)
+++ src/uk/me/parabola/mkgmap/osmstyle/RuleFileReader.java (revision )
@@ -44,6 +44,7 @@
import uk.me.parabola.mkgmap.osmstyle.eval.ExpressionReader;
import uk.me.parabola.mkgmap.osmstyle.eval.LinkedOp;
import uk.me.parabola.mkgmap.osmstyle.eval.NodeType;
+import uk.me.parabola.mkgmap.osmstyle.eval.NotEqualOp;
import uk.me.parabola.mkgmap.osmstyle.eval.NotOp;
import uk.me.parabola.mkgmap.osmstyle.eval.Op;
import uk.me.parabola.mkgmap.osmstyle.eval.OrOp;
@@ -475,6 +476,26 @@
return op;
}
+ private static Op removeNot(Op op) {
+ Op first = op.getFirst();
+ switch (first.getType()) {
+ case NOT:
+ return removeNot(first.getFirst());
+ case EQUALS:
+ BinaryOp ne = new NotEqualOp();
+ ne.setFirst(first.getFirst());
+ ne.setSecond(first.getSecond());
+ return ne;
+ case NOT_EQUALS:
+ BinaryOp eq = new EqualsOp();
+ eq.setFirst(first.getFirst());
+ eq.setSecond(first.getSecond());
+ return eq;
+ }
+
+ return op;
+ }
+
/**
* Swap the terms so that the most selective or fastest term to calculate
* is first.
@@ -600,8 +621,10 @@
* EQUALS to the front followed by EXISTS. Without knowing tag
* frequency you can only guess at what the most selective operations
* are, so all we do is arrange EQUALS - EXISTS - everything else.
+ *
* Note that you must have an EQUALS or EXISTS first, so you can't
- * bring anything else earlier than them.
+ * bring anything else earlier than them. You cannot have NOT_EQUALS
+ * or NOT_EXISTS first, so they have to be moved after everything else.
*
* @return An integer, lower values mean the operation should be earlier
* in the expression than operations with higher values.
@@ -619,8 +642,15 @@
case OR:
return Math.max(selectivity(op.getFirst()), selectivity(op.getSecond()));
+ case NOT_EQUALS:
+ case NOT_EXISTS:
+ case NOT:
+ // None of these can be first, this will ensure that they never are
+ // when there is more than one term
+ return 200;
+
default:
- return 1000;
+ return 100;
}
}
@@ -629,7 +659,7 @@
// The lookup key for the exists operation is 'tag=*'
createAndSaveRule(op.getFirst().getKeyValue() + "=*", op, actions, gt);
} else {
- throw new SyntaxException(scanner, "Cannot start expression with: " + op);
+ throw new SyntaxException(scanner, "Expression cannot contain only not-equals and not-exists terms");
}
}
@@ -695,6 +725,9 @@
}
private AndOp combineWithExists(Op first, BinaryOp op) {
+ if (op.isType(NOT_EXISTS) || op.isType(NOT_EQUALS))
+ throw new SyntaxException("Expression cannot contain only not-equals and not-exists terms");
+
Op existsOp = new ExistsOp();
existsOp.setFirst(first);
Index: test/uk/me/parabola/mkgmap/osmstyle/RuleSetTest.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- test/uk/me/parabola/mkgmap/osmstyle/RuleSetTest.java (revision 3976)
+++ test/uk/me/parabola/mkgmap/osmstyle/RuleSetTest.java (revision )
@@ -21,6 +21,7 @@
import uk.me.parabola.mkgmap.reader.osm.Rule;
import uk.me.parabola.mkgmap.reader.osm.TypeResult;
import uk.me.parabola.mkgmap.reader.osm.Way;
+import uk.me.parabola.mkgmap.scan.SyntaxException;
import org.junit.Test;
@@ -77,7 +78,6 @@
/**
* An action variable is set on a rule that starts with an exists clause.
* We then attempt to match on value that it is
- * @throws Exception
*/
@Test
public void testActionVarSetOnExistsRule1() throws Exception {
@@ -338,8 +338,73 @@
assertEquals("second element", 0x6, list.get(1).getType());
}
+ @Test
+ public void testNotEqualPlusRegex() {
+ // Test first term not-equal, second a regex
+ RuleSet rs = makeRuleSet("highway!=bus_stop & name~'(?i)ferry terminal' [0x6]");
+
+ Way el = new Way(1);
+ el.addTag("name", "Ferry terminal");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull("Expect rule to match", type);
+ assertEquals("Expect rule to match", 6, type.getType());
+ }
+
+ @Test
+ public void testNotExistsPlusRegex() {
+ // Test first term not-equal, second a regex
+ RuleSet rs = makeRuleSet("highway!=* & name~'(?i)ferry terminal' [0x6]");
+
+ Way el = new Way(1);
+ el.addTag("name", "Ferry terminal");
+
+ GType type = getFirstType(rs, el);
+ assertNotNull("Expect rule to match", type);
+ assertEquals("Expect rule to match", 6, type.getType());
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void testOnlyNotExists() {
+ makeRuleSet("highway != * [0x2]");
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void testOnlyNotEqual() {
+ makeRuleSet("highway != 'primary' [0x2]");
+ }
+
+ @Test(expected = SyntaxException.class)
+ public void testOnlyNotAllowedTerms() {
+ makeRuleSet("highway != 'primary & a != bar & c !=*' [0x2]");
+ }
+
+ @Test
+ public void testNotAndRegex() {
+ RuleSet rs = makeRuleSet("!(highway=primary) & name~'.ello' [0x2]");
+
+ Way way = new Way(1);
+ way.addTag("name", "hello");
+
+ GType type = getFirstType(rs, way);
+ assertNotNull(type);
+ assertEquals(2, type.getType());
+ }
+
+ //@Test
+ //public void testLoneNotNotEquals() {
+ // RuleSet rs = makeRuleSet("!(highway!=primary) [0x2]");
+ //
+ // Way way = new Way(1);
+ // way.addTag("highway", "primary");
+ //
+ // GType type = getFirstType(rs, way);
+ // assertNotNull(type);
+ // assertEquals(2, type.getType());
+ //}
+
private List<GType> resolveList(RuleSet rs, Way el) {
- final List<GType> list = new ArrayList<GType>();
+ final List<GType> list = new ArrayList<>();
rs.resolveType(el, new TypeResult() {
public void add(Element el, GType type) {
list.add(type);
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev