Changeset 12656 in josm for trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java
- Timestamp:
- 2017-08-26T00:40:19+02:00 (7 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/data/osm/search
- Files:
-
- 1 added
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java
r12651 r12656 1 1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm. actions.search;2 package org.openstreetmap.josm.data.osm.search; 3 3 4 4 import static org.openstreetmap.josm.tools.I18n.marktr; … … 24 24 25 25 import org.openstreetmap.josm.Main; 26 import org.openstreetmap.josm.actions.search.PushbackTokenizer.Range; 27 import org.openstreetmap.josm.actions.search.PushbackTokenizer.Token; 26 import org.openstreetmap.josm.actions.search.SearchAction; 28 27 import org.openstreetmap.josm.data.Bounds; 29 28 import org.openstreetmap.josm.data.coor.LatLon; … … 36 35 import org.openstreetmap.josm.data.osm.Tagged; 37 36 import org.openstreetmap.josm.data.osm.Way; 37 import org.openstreetmap.josm.data.osm.search.PushbackTokenizer.Range; 38 import org.openstreetmap.josm.data.osm.search.PushbackTokenizer.Token; 38 39 import org.openstreetmap.josm.gui.MainApplication; 39 40 import org.openstreetmap.josm.gui.mappaint.Environment; … … 53 54 54 55 /** 55 Implements a google-like search. 56 <br> 57 Grammar: 58 <pre> 59 expression = 60 fact | expression 61 fact expression 62 fact 63 64 fact = 65 ( expression ) 66 -fact 67 term? 68 term=term 69 term:term 70 term 71 </pre> 72 73 @author Imi 56 * Implements a google-like search. 57 * <br> 58 * Grammar: 59 * <pre> 60 * expression = 61 * fact | expression 62 * fact expression 63 * fact 64 * 65 * fact = 66 * ( expression ) 67 * -fact 68 * term? 69 * term=term 70 * term:term 71 * term 72 * </pre> 73 * 74 * @author Imi 75 * @since 12656 (moved from actions.search package) 74 76 */ 75 77 public class SearchCompiler { … … 126 128 127 129 @Override 128 public Match get(String keyword, PushbackTokenizer tokenizer) throws ParseError {130 public Match get(String keyword, PushbackTokenizer tokenizer) throws SearchParseError { 129 131 switch(keyword) { 130 132 case "modified": … … 198 200 minDate = DateUtils.fromString(rangeA1.isEmpty() ? "1980" : rangeA1).getTime(); 199 201 } catch (UncheckedParseException ex) { 200 throw new ParseError(tr("Cannot parse timestamp ''{0}''", rangeA1), ex);202 throw new SearchParseError(tr("Cannot parse timestamp ''{0}''", rangeA1), ex); 201 203 } 202 204 try { … … 204 206 maxDate = rangeA2.isEmpty() ? System.currentTimeMillis() : DateUtils.fromString(rangeA2).getTime(); 205 207 } catch (UncheckedParseException ex) { 206 throw new ParseError(tr("Cannot parse timestamp ''{0}''", rangeA2), ex);208 throw new SearchParseError(tr("Cannot parse timestamp ''{0}''", rangeA2), ex); 207 209 } 208 210 return new TimestampRange(minDate, maxDate); 209 211 } else { 210 throw new ParseError("<html>" + tr("Expecting {0} after {1}", "<i>min</i>/<i>max</i>", "<i>timestamp</i>"));212 throw new SearchParseError("<html>" + tr("Expecting {0} after {1}", "<i>min</i>/<i>max</i>", "<i>timestamp</i>")); 211 213 } 212 214 } 213 215 } else { 214 throw new ParseError("<html>" + tr("Expecting {0} after {1}", "<code>:</code>", "<i>" + keyword + "</i>"));216 throw new SearchParseError("<html>" + tr("Expecting {0} after {1}", "<code>:</code>", "<i>" + keyword + "</i>")); 215 217 } 216 218 } … … 252 254 253 255 public interface SimpleMatchFactory extends MatchFactory { 254 Match get(String keyword, PushbackTokenizer tokenizer) throws ParseError;256 Match get(String keyword, PushbackTokenizer tokenizer) throws SearchParseError; 255 257 } 256 258 257 259 public interface UnaryMatchFactory extends MatchFactory { 258 UnaryMatch get(String keyword, Match matchOperand, PushbackTokenizer tokenizer) throws ParseError;260 UnaryMatch get(String keyword, Match matchOperand, PushbackTokenizer tokenizer) throws SearchParseError; 259 261 } 260 262 261 263 public interface BinaryMatchFactory extends MatchFactory { 262 AbstractBinaryMatch get(String keyword, Match lhs, Match rhs, PushbackTokenizer tokenizer) throws ParseError;264 AbstractBinaryMatch get(String keyword, Match lhs, Match rhs, PushbackTokenizer tokenizer) throws SearchParseError; 263 265 } 264 266 265 267 /** 266 268 * Base class for all search criteria. If the criterion only depends on an object's tags, 267 * inherit from {@link org.openstreetmap.josm. actions.search.SearchCompiler.TaggedMatch}.269 * inherit from {@link org.openstreetmap.josm.data.osm.search.SearchCompiler.TaggedMatch}. 268 270 */ 269 271 public abstract static class Match implements Predicate<OsmPrimitive> { … … 536 538 } 537 539 538 Id(PushbackTokenizer tokenizer) throws ParseError {540 Id(PushbackTokenizer tokenizer) throws SearchParseError { 539 541 this(tokenizer.readRange(tr("Range of primitive ids expected"))); 540 542 } … … 559 561 } 560 562 561 ChangesetId(PushbackTokenizer tokenizer) throws ParseError {563 ChangesetId(PushbackTokenizer tokenizer) throws SearchParseError { 562 564 this(tokenizer.readRange(tr("Range of changeset ids expected"))); 563 565 } … … 582 584 } 583 585 584 Version(PushbackTokenizer tokenizer) throws ParseError {586 Version(PushbackTokenizer tokenizer) throws SearchParseError { 585 587 this(tokenizer.readRange(tr("Range of versions expected"))); 586 588 } … … 607 609 private final boolean caseSensitive; 608 610 609 KeyValue(String key, String value, boolean regexSearch, boolean caseSensitive) throws ParseError {611 KeyValue(String key, String value, boolean regexSearch, boolean caseSensitive) throws SearchParseError { 610 612 this.caseSensitive = caseSensitive; 611 613 if (regexSearch) { … … 615 617 this.keyPattern = Pattern.compile(key, searchFlags); 616 618 } catch (PatternSyntaxException e) { 617 throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);619 throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e); 618 620 } catch (IllegalArgumentException e) { 619 throw new ParseError(tr(rxErrorMsgNoPos, key, e.getMessage()), e);621 throw new SearchParseError(tr(rxErrorMsgNoPos, key, e.getMessage()), e); 620 622 } 621 623 try { 622 624 this.valuePattern = Pattern.compile(value, searchFlags); 623 625 } catch (PatternSyntaxException e) { 624 throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);626 throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e); 625 627 } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { 626 throw new ParseError(tr(rxErrorMsgNoPos, value, e.getMessage()), e);628 throw new SearchParseError(tr(rxErrorMsgNoPos, value, e.getMessage()), e); 627 629 } 628 630 this.key = key; … … 771 773 * @param key key 772 774 * @param value value 773 * @throws ParseError if a parse error occurs775 * @throws SearchParseError if a parse error occurs 774 776 */ 775 public ExactKeyValue(boolean regexp, String key, String value) throws ParseError {777 public ExactKeyValue(boolean regexp, String key, String value) throws SearchParseError { 776 778 if ("".equals(key)) 777 throw new ParseError(tr("Key cannot be empty when tag operator is used. Sample use: key=value"));779 throw new SearchParseError(tr("Key cannot be empty when tag operator is used. Sample use: key=value")); 778 780 this.key = key; 779 781 this.value = value == null ? "" : value; … … 812 814 keyPattern = Pattern.compile(key, regexFlags(false)); 813 815 } catch (PatternSyntaxException e) { 814 throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);816 throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e); 815 817 } catch (IllegalArgumentException e) { 816 throw new ParseError(tr(rxErrorMsgNoPos, key, e.getMessage()), e);818 throw new SearchParseError(tr(rxErrorMsgNoPos, key, e.getMessage()), e); 817 819 } 818 820 } else { … … 823 825 valuePattern = Pattern.compile(this.value, regexFlags(false)); 824 826 } catch (PatternSyntaxException e) { 825 throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);827 throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e); 826 828 } catch (IllegalArgumentException e) { 827 throw new ParseError(tr(rxErrorMsgNoPos, value, e.getMessage()), e);829 throw new SearchParseError(tr(rxErrorMsgNoPos, value, e.getMessage()), e); 828 830 } 829 831 } else { … … 893 895 private final boolean caseSensitive; 894 896 895 Any(String s, boolean regexSearch, boolean caseSensitive) throws ParseError {897 Any(String s, boolean regexSearch, boolean caseSensitive) throws SearchParseError { 896 898 s = Normalizer.normalize(s, Normalizer.Form.NFC); 897 899 this.caseSensitive = caseSensitive; … … 900 902 this.searchRegex = Pattern.compile(s, regexFlags(caseSensitive)); 901 903 } catch (PatternSyntaxException e) { 902 throw new ParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e);904 throw new SearchParseError(tr(rxErrorMsg, e.getPattern(), e.getIndex(), e.getMessage()), e); 903 905 } catch (IllegalArgumentException | StringIndexOutOfBoundsException e) { 904 906 // StringIndexOutOfBoundsException catched because of https://bugs.openjdk.java.net/browse/JI-9044959 905 907 // See #13870: To remove after we switch to a version of Java which resolves this bug 906 throw new ParseError(tr(rxErrorMsgNoPos, s, e.getMessage()), e);908 throw new SearchParseError(tr(rxErrorMsgNoPos, s, e.getMessage()), e); 907 909 } 908 910 this.search = s; … … 959 961 private final OsmPrimitiveType type; 960 962 961 ExactType(String type) throws ParseError {963 ExactType(String type) throws SearchParseError { 962 964 this.type = OsmPrimitiveType.from(type); 963 965 if (this.type == null) 964 throw new ParseError(tr("Unknown primitive type: {0}. Allowed values are node, way or relation", type));966 throw new SearchParseError(tr("Unknown primitive type: {0}. Allowed values are node, way or relation", type)); 965 967 } 966 968 … … 1048 1050 private final boolean modulo; 1049 1051 1050 Nth(PushbackTokenizer tokenizer, boolean modulo) throws ParseError {1052 Nth(PushbackTokenizer tokenizer, boolean modulo) throws SearchParseError { 1051 1053 this((int) tokenizer.readNumber(tr("Positive integer expected")), modulo); 1052 1054 } … … 1131 1133 } 1132 1134 1133 NodeCountRange(PushbackTokenizer tokenizer) throws ParseError {1135 NodeCountRange(PushbackTokenizer tokenizer) throws SearchParseError { 1134 1136 this(tokenizer.readRange(tr("Range of numbers expected"))); 1135 1137 } … … 1160 1162 } 1161 1163 1162 WayCountRange(PushbackTokenizer tokenizer) throws ParseError {1164 WayCountRange(PushbackTokenizer tokenizer) throws SearchParseError { 1163 1165 this(tokenizer.readRange(tr("Range of numbers expected"))); 1164 1166 } … … 1189 1191 } 1190 1192 1191 TagCountRange(PushbackTokenizer tokenizer) throws ParseError {1193 TagCountRange(PushbackTokenizer tokenizer) throws SearchParseError { 1192 1194 this(tokenizer.readRange(tr("Range of numbers expected"))); 1193 1195 } … … 1414 1416 } 1415 1417 1416 AreaSize(PushbackTokenizer tokenizer) throws ParseError {1418 AreaSize(PushbackTokenizer tokenizer) throws SearchParseError { 1417 1419 this(tokenizer.readRange(tr("Range of numbers expected"))); 1418 1420 } … … 1439 1441 } 1440 1442 1441 WayLength(PushbackTokenizer tokenizer) throws ParseError {1443 WayLength(PushbackTokenizer tokenizer) throws SearchParseError { 1442 1444 this(tokenizer.readRange(tr("Range of numbers expected"))); 1443 1445 } … … 1571 1573 private final List<TaggingPreset> presets; 1572 1574 1573 Preset(String presetName) throws ParseError {1575 Preset(String presetName) throws SearchParseError { 1574 1576 1575 1577 if (presetName == null || presetName.isEmpty()) { 1576 throw new ParseError("The name of the preset is required");1578 throw new SearchParseError("The name of the preset is required"); 1577 1579 } 1578 1580 … … 1593 1595 1594 1596 if (this.presets.isEmpty()) { 1595 throw new ParseError(tr("Unknown preset name: ") + presetName);1597 throw new SearchParseError(tr("Unknown preset name: ") + presetName); 1596 1598 } 1597 1599 } … … 1624 1626 } 1625 1627 1626 public static class ParseError extends Exception {1627 public ParseError(String msg) {1628 super(msg);1629 }1630 1631 public ParseError(String msg, Throwable cause) {1632 super(msg, cause);1633 }1634 1635 public ParseError(Token expected, Token found) {1636 this(tr("Unexpected token. Expected {0}, found {1}", expected, found));1637 }1638 }1639 1640 1628 /** 1641 1629 * Compiles the search expression. 1642 1630 * @param searchStr the search expression 1643 1631 * @return a {@link Match} object for the expression 1644 * @throws ParseError if an error has been encountered while compiling1632 * @throws SearchParseError if an error has been encountered while compiling 1645 1633 * @see #compile(org.openstreetmap.josm.actions.search.SearchAction.SearchSetting) 1646 1634 */ 1647 public static Match compile(String searchStr) throws ParseError {1635 public static Match compile(String searchStr) throws SearchParseError { 1648 1636 return new SearchCompiler(false, false, 1649 1637 new PushbackTokenizer( … … 1656 1644 * @param setting the settings to use 1657 1645 * @return a {@link Match} object for the expression 1658 * @throws ParseError if an error has been encountered while compiling1646 * @throws SearchParseError if an error has been encountered while compiling 1659 1647 * @see #compile(String) 1660 1648 */ 1661 public static Match compile(SearchAction.SearchSetting setting) throws ParseError {1649 public static Match compile(SearchAction.SearchSetting setting) throws SearchParseError { 1662 1650 if (setting.mapCSSSearch) { 1663 1651 return compileMapCSS(setting.text); … … 1669 1657 } 1670 1658 1671 static Match compileMapCSS(String mapCSS) throws ParseError {1659 static Match compileMapCSS(String mapCSS) throws SearchParseError { 1672 1660 try { 1673 1661 final List<Selector> selectors = new MapCSSParser(new StringReader(mapCSS)).selectors(); … … 1684 1672 }; 1685 1673 } catch (ParseException e) { 1686 throw new ParseError(tr("Failed to parse MapCSS selector"), e);1674 throw new SearchParseError(tr("Failed to parse MapCSS selector"), e); 1687 1675 } 1688 1676 } … … 1692 1680 * 1693 1681 * @return match determined by search string 1694 * @throws org.openstreetmap.josm. actions.search.SearchCompiler.ParseError if search expression cannot be parsed1695 */ 1696 public Match parse() throws ParseError {1682 * @throws org.openstreetmap.josm.data.osm.search.SearchParseError if search expression cannot be parsed 1683 */ 1684 public Match parse() throws SearchParseError { 1697 1685 Match m = Optional.ofNullable(parseExpression()).orElse(Always.INSTANCE); 1698 1686 if (!tokenizer.readIfEqual(Token.EOF)) 1699 throw new ParseError(tr("Unexpected token: {0}", tokenizer.nextToken()));1687 throw new SearchParseError(tr("Unexpected token: {0}", tokenizer.nextToken())); 1700 1688 Logging.debug("Parsed search expression is {0}", m); 1701 1689 return m; … … 1706 1694 * 1707 1695 * @return match determined by parsing expression 1708 * @throws ParseError if search expression cannot be parsed1709 */ 1710 private Match parseExpression() throws ParseError {1696 * @throws SearchParseError if search expression cannot be parsed 1697 */ 1698 private Match parseExpression() throws SearchParseError { 1711 1699 // Step 1: parse the whole expression and build a list of factors and logical tokens 1712 1700 List<Object> list = parseExpressionStep1(); … … 1716 1704 } 1717 1705 1718 private List<Object> parseExpressionStep1() throws ParseError {1706 private List<Object> parseExpressionStep1() throws SearchParseError { 1719 1707 Match factor; 1720 1708 String token = null; … … 1739 1727 } 1740 1728 } else if (errorMessage != null) { 1741 throw new ParseError(errorMessage);1729 throw new SearchParseError(errorMessage); 1742 1730 } 1743 1731 } while (factor != null); … … 1777 1765 * 1778 1766 * @return match determined by parsing factor string 1779 * @throws ParseError if search expression cannot be parsed1780 */ 1781 private Match parseFactor() throws ParseError {1767 * @throws SearchParseError if search expression cannot be parsed 1768 */ 1769 private Match parseFactor() throws SearchParseError { 1782 1770 if (tokenizer.readIfEqual(Token.LEFT_PARENT)) { 1783 1771 Match expression = parseExpression(); 1784 1772 if (!tokenizer.readIfEqual(Token.RIGHT_PARENT)) 1785 throw new ParseError(Token.RIGHT_PARENT, tokenizer.nextToken());1773 throw new SearchParseError(Token.RIGHT_PARENT, tokenizer.nextToken()); 1786 1774 return expression; 1787 1775 } else if (tokenizer.readIfEqual(Token.NOT)) { … … 1827 1815 } 1828 1816 1829 private Match parseFactor(String errorMessage) throws ParseError {1830 return Optional.ofNullable(parseFactor()).orElseThrow(() -> new ParseError(errorMessage));1817 private Match parseFactor(String errorMessage) throws SearchParseError { 1818 return Optional.ofNullable(parseFactor()).orElseThrow(() -> new SearchParseError(errorMessage)); 1831 1819 } 1832 1820 … … 1874 1862 } 1875 1863 } 1876
Note:
See TracChangeset
for help on using the changeset viewer.