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

Reply via email to