Ignore:
Timestamp:
2009-12-16T21:27:28+01:00 (14 years ago)
Author:
jttt
Message:

SearchCompiler refactoring, use search pattern for OsmPrimitive.hasDirectionKeys(), added toString() and type to dataset events

Location:
trunk/src/org/openstreetmap/josm/actions/search
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java

    r1641 r2645  
    33
    44import java.io.IOException;
    5 import java.io.PushbackReader;
    6 import java.util.LinkedList;
     5import java.io.Reader;
     6
     7import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
    78
    89public class PushbackTokenizer {
    9     private PushbackReader search;
     10    private final Reader search;
    1011
    11     private LinkedList<String> pushBackBuf = new LinkedList<String>();
     12    private Token currentToken;
     13    private String currentText;
     14    private int c;
    1215
    13     public PushbackTokenizer(PushbackReader search) {
     16    public PushbackTokenizer(Reader search) {
    1417        this.search = search;
     18        getChar();
     19    }
     20
     21    public enum Token {NOT, OR, LEFT_PARENT, RIGHT_PARENT, COLON, EQUALS, KEY, EOF}
     22
     23    private void getChar() {
     24        try {
     25            c = search.read();
     26        } catch (IOException e) {
     27            throw new RuntimeException(e.getMessage(), e);
     28        }
    1529    }
    1630
     
    2337     * @return The next token in the stream.
    2438     */
    25     public String nextToken() {
    26         if (!pushBackBuf.isEmpty()) {
    27             return pushBackBuf.removeLast();
     39    public Token nextToken() {
     40        if (currentToken != null) {
     41            Token result = currentToken;
     42            currentToken = null;
     43            return result;
    2844        }
    2945
    30         try {
    31             int next;
    32             char c = ' ';
    33             while (c == ' ' || c == '\t' || c == '\n') {
    34                 next = search.read();
    35                 if (next == -1)
    36                     return null;
    37                 c = (char)next;
     46        while (Character.isWhitespace(c)) {
     47            getChar();
     48        }
     49        switch (c) {
     50        case -1:
     51            getChar();
     52            return Token.EOF;
     53        case ':':
     54            getChar();
     55            return Token.COLON;
     56        case '=':
     57            getChar();
     58            return Token.EQUALS;
     59        case '-':
     60            getChar();
     61            return Token.NOT;
     62        case '(':
     63            getChar();
     64            return Token.LEFT_PARENT;
     65        case ')':
     66            getChar();
     67            return Token.RIGHT_PARENT;
     68        case '|':
     69            getChar();
     70            return Token.OR;
     71        case '"':
     72        {
     73            StringBuilder s = new StringBuilder();
     74            while (c != -1 && c != '"') {
     75                s.append((char)c);
     76                getChar();
    3877            }
    39             StringBuilder s;
    40             switch (c) {
    41             case ':':
    42             case '=':
    43                 next = search.read();
    44                 if (next == -1 || next == ' ' || next == '\t') {
    45                     pushBack(" ");
    46                 } else {
    47                     search.unread(next);
    48                 }
    49                 return String.valueOf(c);
    50             case '-':
    51                 return "-";
    52             case '(':
    53                 return "(";
    54             case ')':
    55                 return ")";
    56             case '|':
    57                 return "|";
    58             case '"':
    59                 s = new StringBuilder(" ");
    60                 for (int nc = search.read(); nc != -1 && nc != '"'; nc = search.read())
    61                     s.append((char)nc);
    62                 return s.toString();
    63             default:
    64                 s = new StringBuilder();
    65             for (;;) {
    66                 s.append(c);
    67                 next = search.read();
    68                 if (next == -1) {
    69                     if (s.toString().equals("OR"))
    70                         return "|";
    71                     return " "+s.toString();
    72                 }
    73                 c = (char)next;
    74                 if (c == ' ' || c == '\t' || c == '"' || c == ':' || c == '(' || c == ')' || c == '|' || c == '=') {
    75                     search.unread(next);
    76                     if (s.toString().equals("OR"))
    77                         return "|";
    78                     return " "+s.toString();
    79                 }
     78            getChar();
     79            currentText = s.toString();
     80            return Token.KEY;
     81        }
     82        default:
     83        {
     84            StringBuilder s = new StringBuilder();
     85            while (!(c == -1 || Character.isWhitespace(c) || c == '"'|| c == ':' || c == '(' || c == ')' || c == '|' || c == '=')) {
     86                s.append((char)c);
     87                getChar();
    8088            }
    81             }
    82         } catch (IOException e) {
    83             throw new RuntimeException(e.getMessage(), e);
     89            currentText = s.toString();
     90            if ("or".equals(currentText))
     91                return Token.OR;
     92            else
     93                return Token.KEY;
     94        }
    8495        }
    8596    }
    8697
    87     public boolean readIfEqual(String tok) {
    88         String nextTok = nextToken();
    89         if (nextTok == null ? tok == null : nextTok.equals(tok))
     98    public boolean readIfEqual(Token token) {
     99        Token nextTok = nextToken();
     100        if (nextTok == null ? token == null : nextTok == token)
    90101            return true;
    91         pushBack(nextTok);
     102        currentToken = nextTok;
    92103        return false;
    93104    }
    94105
    95106    public String readText() {
    96         String nextTok = nextToken();
    97         if (nextTok != null && nextTok.startsWith(" "))
    98             return nextTok.substring(1);
    99         pushBack(nextTok);
     107        Token nextTok = nextToken();
     108        if (nextTok == Token.KEY)
     109            return currentText;
     110        currentToken = nextTok;
    100111        return null;
    101112    }
    102113
    103     public void pushBack(String tok) {
    104         pushBackBuf.addLast(tok);
     114    public String readText(String errorMessage) throws ParseError {
     115        String text = readText();
     116        if (text == null)
     117            throw new ParseError(errorMessage);
     118        else
     119            return text;
     120    }
     121
     122    public String getText() {
     123        return currentText;
    105124    }
    106125}
  • trunk/src/org/openstreetmap/josm/actions/search/SearchCompiler.java

    r2636 r2645  
    1414
    1515import org.openstreetmap.josm.Main;
     16import org.openstreetmap.josm.actions.search.PushbackTokenizer.Token;
    1617import org.openstreetmap.josm.data.osm.Node;
    1718import org.openstreetmap.josm.data.osm.OsmPrimitive;
     
    2324
    2425/**
    25  * Implements a google-like search.
    26  * @author Imi
     26 Implements a google-like search.
     27 <br>
     28 Grammar:
     29<pre>
     30expression =
     31  fact | expression
     32  fact expression
     33  fact
     34
     35fact =
     36 ( expression )
     37 -fact
     38 term=term
     39 term:term
     40 term
     41 </pre>
     42
     43 @author Imi
    2744 */
    2845public class SearchCompiler {
     
    184201    }
    185202
    186     private static class ExactKeyValue extends Match {
     203    public static class ExactKeyValue extends Match {
    187204
    188205        private enum Mode {
     
    201218                throw new ParseError(tr("Key cannot be empty when tag operator is used. Sample use: key=value"));
    202219            this.key = key;
    203             this.value = value;
     220            this.value = value == null?"":value;
    204221            if ("".equals(value) && "*".equals(key)) {
    205222                mode = Mode.NONE;
     
    527544            } else if (osm instanceof Relation) {
    528545                for (RelationMember member : ((Relation)osm).getMembers()) {
    529                     if (member.getMember() != null) {
    530                         // TODO Nullable member will not be allowed
    531                         isParent |= child.match(member.getMember());
    532                     }
     546                    isParent |= child.match(member.getMember());
    533547                }
    534548            }
     
    576590
    577591    public Match parse() throws ParseError {
    578         Match m = parseJuxta();
    579         if (!tokenizer.readIfEqual(null))
     592        Match m = parseExpression();
     593        if (!tokenizer.readIfEqual(Token.EOF))
    580594            throw new ParseError(tr("Unexpected token: {0}", tokenizer.nextToken()));
    581595        return m;
    582596    }
    583597
    584     private Match parseJuxta() throws ParseError {
    585         Match juxta = new Always();
    586 
    587         Match m;
    588         while ((m = parseOr()) != null) {
    589             juxta = new And(m, juxta);
    590         }
    591 
    592         return juxta;
    593     }
    594 
    595     private Match parseOr() throws ParseError {
    596         Match a = parseNot();
    597         if (tokenizer.readIfEqual("|")) {
    598             Match b = parseNot();
    599             if (a == null || b == null)
    600                 throw new ParseError(tr("Missing arguments for or."));
    601             return new Or(a, b);
    602         }
    603         return a;
    604     }
    605 
    606     private Match parseNot() throws ParseError {
    607         if (tokenizer.readIfEqual("-")) {
    608             Match m = parseParens();
    609             if (m == null)
    610                 throw new ParseError(tr("Missing argument for not."));
    611             return new Not(m);
    612         }
    613         return parseParens();
    614     }
    615 
    616     private Match parseParens() throws ParseError {
    617         if (tokenizer.readIfEqual("(")) {
    618             Match m = parseJuxta();
    619             if (!tokenizer.readIfEqual(")"))
    620                 throw new ParseError(tr("Expected closing parenthesis."));
    621             return m;
    622         }
    623         return parsePat();
    624     }
    625 
    626     private Match parsePat() throws ParseError {
    627         String tok = tokenizer.readText();
    628 
    629         if (tokenizer.readIfEqual(":")) {
    630             String tok2 = tokenizer.readText();
    631             if (tok == null) {
    632                 tok = "";
    633             }
    634             if (tok2 == null) {
    635                 tok2 = "";
    636             }
    637             return parseKV(tok, tok2);
    638         }
    639 
    640         if (tokenizer.readIfEqual("=")) {
    641             String tok2 = tokenizer.readText();
    642             if (tok == null) {
    643                 tok = "";
    644             }
    645             if (tok2 == null) {
    646                 tok2 = "";
    647             }
    648             return new ExactKeyValue(regexSearch, tok, tok2);
    649         }
    650 
    651         if (tok == null)
     598    private Match parseExpression() throws ParseError {
     599        Match factor = parseFactor();
     600        if (factor == null)
    652601            return null;
    653         else if (tok.equals("modified"))
    654             return new Modified();
    655         else if (tok.equals("incomplete"))
    656             return new Incomplete();
    657         else if (tok.equals("untagged"))
    658             return new Untagged();
    659         else if (tok.equals("selected"))
    660             return new Selected();
    661         else if (tok.equals("child"))
    662             return new Child(parseParens());
    663         else if (tok.equals("parent"))
    664             return new Parent(parseParens());
     602        if (tokenizer.readIfEqual(Token.OR))
     603            return new Or(factor, parseExpression(tr("Missing parameter for OR")));
     604        else {
     605            Match expression = parseExpression();
     606            if (expression == null)
     607                return factor;
     608            else
     609                return new And(factor, expression);
     610        }
     611    }
     612
     613    private Match parseExpression(String errorMessage) throws ParseError {
     614        Match expression = parseExpression();
     615        if (expression == null)
     616            throw new ParseError(errorMessage);
    665617        else
    666             return new Any(tok, regexSearch, caseSensitive);
    667     }
     618            return expression;
     619    }
     620
     621    private Match parseFactor() throws ParseError {
     622        if (tokenizer.readIfEqual(Token.LEFT_PARENT)) {
     623            Match expression = parseExpression();
     624            if (!tokenizer.readIfEqual(Token.RIGHT_PARENT))
     625                throw new ParseError(tr("Missing right parent"));
     626            return expression;
     627        } else if (tokenizer.readIfEqual(Token.NOT))
     628            return new Not(parseFactor(tr("Missing operator for NOT")));
     629        else if (tokenizer.readIfEqual(Token.KEY)) {
     630            String key = tokenizer.getText();
     631            if (tokenizer.readIfEqual(Token.EQUALS))
     632                return new ExactKeyValue(regexSearch, key, tokenizer.readText());
     633            else if (tokenizer.readIfEqual(Token.COLON))
     634                return parseKV(key, tokenizer.readText());
     635            else if ("modified".equals(key))
     636                return new Modified();
     637            else if ("incomplete".equals(key))
     638                return new Incomplete();
     639            else if ("untagged".equals(key))
     640                return new Untagged();
     641            else if ("selected".equals(key))
     642                return new Selected();
     643            else if ("child".equals(key))
     644                return new Child(parseFactor());
     645            else if ("parent".equals(key))
     646                return new Parent(parseFactor());
     647            else
     648                return new Any(key, regexSearch, caseSensitive);
     649        } else
     650            return null;
     651    }
     652
     653    private Match parseFactor(String errorMessage) throws ParseError {
     654        Match fact = parseFactor();
     655        if (fact == null)
     656            throw new ParseError(errorMessage);
     657        else
     658            return fact;
     659    }
     660
     661
    668662
    669663    private Match parseKV(String key, String value) throws ParseError {
     664        if (value == null) {
     665            value = "";
     666        }
    670667        if (key.equals("type"))
    671668            return new ExactType(value);
Note: See TracChangeset for help on using the changeset viewer.