Index: /trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 3304)
+++ /trunk/src/org/openstreetmap/josm/actions/search/SearchAction.java	(revision 3305)
@@ -190,4 +190,5 @@
                     + "<li>"+tr("<b>nodes:</b>... - object with given number of nodes (nodes:count or nodes:min-max)")+"</li>"
                     + "<li>"+tr("<b>tags:</b>... - object with given number of tags (tags:count or tags:min-max)")+"</li>"
+                    + "<li>"+tr("<b>role:</b>... - object with given role in a relation")+"</li>"
                     + "<li>"+tr("<b>timestamp:</b>... -  objects with this timestamp (<b>2009-11-12T14:51:09Z</b>, <b>2009-11-12</b> or <b>T14:51</b> ...)")+"</li>"
                     + "<li>"+tr("<b>modified</b> - all changed objects")+"</li>"
Index: /trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 3304)
+++ /trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java	(revision 3305)
@@ -48,4 +48,5 @@
     private boolean regexSearch = false;
     private static String  rxErrorMsg = marktr("The regex \"{0}\" had a parse error at offset {1}, full error:\n\n{2}");
+    private static String  rxErrorMsgNoPos = marktr("The regex \"{0}\" had a parse error, full error:\n\n{1}");
     private PushbackTokenizer tokenizer;
 
@@ -167,5 +168,5 @@
                     throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
                 } catch (Exception e) {
-                    throw new ParseError(tr(rxErrorMsg, key, tr("<unknown>"), e.getMessage()));
+                    throw new ParseError(tr(rxErrorMsgNoPos, key, e.getMessage()));
                 }
                 try {
@@ -174,5 +175,5 @@
                     throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
                 } catch (Exception e) {
-                    throw new ParseError(tr(rxErrorMsg, value, tr("<unknown>"), e.getMessage()));
+                    throw new ParseError(tr(rxErrorMsgNoPos, value, e.getMessage()));
                 }
                 this.key = key;
@@ -299,5 +300,5 @@
                     throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
                 } catch (Exception e) {
-                    throw new ParseError(tr(rxErrorMsg, key, tr("<unknown>"), e.getMessage()));
+                    throw new ParseError(tr(rxErrorMsgNoPos, key, e.getMessage()));
                 }
             } else {
@@ -310,5 +311,5 @@
                     throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
                 } catch (Exception e) {
-                    throw new ParseError(tr(rxErrorMsg, value, tr("<unknown>"), e.getMessage()));
+                    throw new ParseError(tr(rxErrorMsgNoPos, value, e.getMessage()));
                 }
             } else {
@@ -386,5 +387,5 @@
                     throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()));
                 } catch (Exception e) {
-                    throw new ParseError(tr(rxErrorMsg, s, tr("<unknown>"), e.getMessage()));
+                    throw new ParseError(tr(rxErrorMsgNoPos, s, e.getMessage()));
                 }
                 this.search = s;
@@ -487,4 +488,34 @@
         @Override public String toString() {
             return "user=" + user == null ? "" : user;
+        }
+    }
+
+    private static class RoleMatch extends Match {
+        private String role;
+        public RoleMatch(String role) {
+            if (role == null) {
+                this.role = "";
+            } else {
+                this.role = role;
+            }
+        }
+
+        @Override public boolean match(OsmPrimitive osm) {
+            for (OsmPrimitive ref: osm.getReferrers()) {
+                if (ref instanceof Relation && !ref.isIncomplete() && !ref.isDeleted()) {
+                    for (RelationMember m : ((Relation) ref).getMembers()) {
+                        if (m.getMember() == osm) {
+                            String testRole = m.getRole();
+                            if(role.equals(testRole == null ? "" : testRole))
+                                return true;
+                        }
+                    }
+                }
+            }
+            return false;
+        }
+
+        @Override public String toString() {
+            return "role=" + role;
         }
     }
@@ -718,4 +749,6 @@
         else if (key.equals("user"))
             return new UserMatch(value);
+        else if (key.equals("role"))
+            return new RoleMatch(value);
         else
             return new KeyValue(key, value, regexSearch, caseSensitive);
