source: josm/trunk/src/org/openstreetmap/josm/tools/template_engine/TemplateParser.java@ 13840

Last change on this file since 13840 was 13206, checked in by Don-vip, 6 years ago

enable PMD rule OptimizableToArrayCall

  • Property svn:eol-style set to native
File size: 5.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools.template_engine;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collection;
9import java.util.List;
10
11import org.openstreetmap.josm.data.osm.search.SearchCompiler;
12import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
13import org.openstreetmap.josm.data.osm.search.SearchParseError;
14import org.openstreetmap.josm.tools.template_engine.Tokenizer.Token;
15import org.openstreetmap.josm.tools.template_engine.Tokenizer.TokenType;
16
17/**
18 * Template parser.
19 */
20public class TemplateParser {
21 private final Tokenizer tokenizer;
22
23 private static final Collection<TokenType> EXPRESSION_END_TOKENS = Arrays.asList(TokenType.EOF);
24 private static final Collection<TokenType> CONDITION_WITH_APOSTROPHES_END_TOKENS = Arrays.asList(TokenType.APOSTROPHE);
25
26 /**
27 * Constructs a new {@code TemplateParser}.
28 * @param template template string to parse
29 */
30 public TemplateParser(String template) {
31 this.tokenizer = new Tokenizer(template);
32 }
33
34 private Token check(TokenType expectedToken) throws ParseError {
35 Token token = tokenizer.nextToken();
36 if (token.getType() != expectedToken)
37 throw new ParseError(token, expectedToken);
38 else
39 return token;
40 }
41
42 /**
43 * Parse the template.
44 * @return the resulting template entry
45 * @throws ParseError if the template cannot be parsed
46 */
47 public TemplateEntry parse() throws ParseError {
48 return parseExpression(EXPRESSION_END_TOKENS);
49 }
50
51 private TemplateEntry parseExpression(Collection<TokenType> endTokens) throws ParseError {
52 List<TemplateEntry> entries = new ArrayList<>();
53 while (true) {
54 TemplateEntry templateEntry;
55 Token token = tokenizer.lookAhead();
56 if (token.getType() == TokenType.CONDITION_START) {
57 templateEntry = parseCondition();
58 } else if (token.getType() == TokenType.CONTEXT_SWITCH_START) {
59 templateEntry = parseContextSwitch();
60 } else if (token.getType() == TokenType.VARIABLE_START) {
61 templateEntry = parseVariable();
62 } else if (endTokens.contains(token.getType()))
63 return CompoundTemplateEntry.fromArray(entries.toArray(new TemplateEntry[0]));
64 else if (token.getType() == TokenType.TEXT) {
65 tokenizer.nextToken();
66 templateEntry = new StaticText(token.getText());
67 } else
68 throw new ParseError(token);
69 entries.add(templateEntry);
70 }
71 }
72
73 private TemplateEntry parseVariable() throws ParseError {
74 check(TokenType.VARIABLE_START);
75 String variableName = check(TokenType.TEXT).getText();
76 check(TokenType.END);
77
78 return new Variable(variableName);
79 }
80
81 private void skipWhitespace() throws ParseError {
82 Token token = tokenizer.lookAhead();
83 if (token.getType() == TokenType.TEXT && token.getText().trim().isEmpty()) {
84 tokenizer.nextToken();
85 }
86 }
87
88 private TemplateEntry parseCondition() throws ParseError {
89 check(TokenType.CONDITION_START);
90 Collection<TemplateEntry> conditionEntries = new ArrayList<>();
91 while (true) {
92
93 TemplateEntry condition;
94 Token searchExpression = tokenizer.skip('\'');
95 check(TokenType.APOSTROPHE);
96 condition = parseExpression(CONDITION_WITH_APOSTROPHES_END_TOKENS);
97 check(TokenType.APOSTROPHE);
98 String searchText = searchExpression.getText().trim();
99 if (searchText.isEmpty()) {
100 conditionEntries.add(condition);
101 } else {
102 try {
103 conditionEntries.add(new SearchExpressionCondition(
104 SearchCompiler.compile(searchText), condition));
105 } catch (SearchParseError e) {
106 throw new ParseError(searchExpression.getPosition(), e);
107 }
108 }
109 skipWhitespace();
110
111 Token token = tokenizer.lookAhead();
112 if (token.getType() == TokenType.END) {
113 tokenizer.nextToken();
114 return new Condition(conditionEntries);
115 } else {
116 check(TokenType.PIPE);
117 }
118 }
119 }
120
121 private TemplateEntry parseContextSwitch() throws ParseError {
122
123 check(TokenType.CONTEXT_SWITCH_START);
124 Token searchExpression = tokenizer.skip('\'');
125 check(TokenType.APOSTROPHE);
126 TemplateEntry template = parseExpression(CONDITION_WITH_APOSTROPHES_END_TOKENS);
127 check(TokenType.APOSTROPHE);
128 ContextSwitchTemplate result;
129 String searchText = searchExpression.getText().trim();
130 if (searchText.isEmpty())
131 throw new ParseError(tr("Expected search expression"));
132 else {
133 try {
134 Match match = SearchCompiler.compile(searchText);
135 result = new ContextSwitchTemplate(match, template, searchExpression.getPosition());
136 } catch (SearchParseError e) {
137 throw new ParseError(searchExpression.getPosition(), e);
138 }
139 }
140 skipWhitespace();
141 check(TokenType.END);
142 return result;
143 }
144}
Note: See TracBrowser for help on using the repository browser.