9
9
* BNF rules:
10
10
*
11
11
* <pre>
12
- * WHITESPACE = Character.isWhitespace()+
13
12
* IDENTIFIER = Character.isJavaIdentifierStart() Character.isJavaIdentifierPart()*
14
13
* IDENTIFIER_OR_FUNCTION = IDENTIFIER "()"?
15
14
* CHAINED_IDENTIFIERS = IDENTIFIER ('.' IDENTIFIER_OR_FUNCTION)*
16
15
* LOWER_ALPHA = [a-z]+
17
- * VAR = "%{" CHAINED_IDENTIFIER (WHITESPACE LOWER_ALPHA)? '}'
16
+ * VAR = "%{" CHAINED_IDENTIFIER (LOWER_ALPHA)? '}'
18
17
*
19
18
* CONST = .*
20
19
*
25
24
* FACTOR = COMPARISON | ('!' FACTOR) | ('(' EXP ')')
26
25
*
27
26
*
28
- * TAG_START = " <#"
29
- * TAG_END = " </#"
27
+ * TAG_START = ' <' '#'
28
+ * TAG_END = ' <' '/' '#' LOWER_ALPHA '>'
30
29
* IF_TAG = TAG_START "if" '(' EXPRESSION ')' '>' LIST_TAG_BODY TAG_END "if" '>'
31
30
* </pre>
32
31
*
33
32
* @author Eric Nielsen
34
33
*/
35
34
public final class TemplateParser {
36
35
37
- private ParentNode parent = new RootNode ();
38
36
private final String source ;
39
37
private int index = -1 ;
40
38
private int currentCodePoint ;
@@ -54,6 +52,10 @@ private boolean next() {
54
52
}
55
53
}
56
54
55
+ private boolean accept (int codePoint ) {
56
+ return currentCodePoint == codePoint && next ();
57
+ }
58
+
57
59
private boolean __whitespace () { return Character .isWhitespace (currentCodePoint ); }
58
60
59
61
@ SuppressWarnings ("empty-statement" )
@@ -73,7 +75,7 @@ private boolean _identifier() {
73
75
private boolean _identifierOrFunction () {
74
76
if (!_identifier ()) { return false ; }
75
77
if (currentCodePoint == '(' ) {
76
- if (!(next () && currentCodePoint == ')' && next ( ))) { return false ; }
78
+ if (!(next () && accept ( ')' ))) { return false ; }
77
79
}
78
80
return true ;
79
81
}
@@ -104,37 +106,40 @@ private String _lowerAlpha() {
104
106
}
105
107
106
108
private VarNode _var () {
107
- if (!(currentCodePoint == '%' && next () && currentCodePoint == '{' && next ())) { return null ; }
109
+ if (!(accept ('%' ) && accept ('{' ))) { return null ; }
110
+ _whitespace (); // optional
108
111
Identifiers ident = _chainedIdentifiers ();
109
112
if (ident == null ) { return null ; }
110
113
BuiltIn builtIn = null ;
111
114
if (_whitespace ()) {
112
115
String builtInName = _lowerAlpha ();
113
- if (builtInName == null ) { return null ; }
114
- builtIn = TemplatorConfig .instance ().getBuiltIn (builtInName );
116
+ if (builtInName != null ) {
117
+ builtIn = TemplatorConfig .instance ().getBuiltIn (builtInName );
118
+ _whitespace (); // optional
119
+ }
115
120
}
116
121
if (currentCodePoint != '}' ) { return null ; }
117
122
next ();
118
123
return new VarNode (ident , builtIn );
119
124
}
120
125
121
126
private Op _comparisonOp () {
122
- if (currentCodePoint == '=' && next ( )) {
123
- return currentCodePoint == '=' && next ( ) ? Op .eq : null ;
124
- } else if (currentCodePoint == '>' && next ( )) {
127
+ if (accept ( '=' )) {
128
+ return accept ( '=' ) ? Op .eq : null ;
129
+ } else if (accept ( '>' )) {
125
130
if (currentCodePoint == '=' ) {
126
131
return next () ? Op .gte : null ;
127
132
} else {
128
133
return Op .gt ;
129
134
}
130
- } else if (currentCodePoint == '<' && next ( )) {
135
+ } else if (accept ( '<' )) {
131
136
if (currentCodePoint == '=' ) {
132
137
return next () ? Op .lte : null ;
133
138
} else {
134
139
return Op .lt ;
135
140
}
136
141
} else {
137
- return currentCodePoint == '!' && next ( ) && currentCodePoint == '=' && next ( ) ? Op .neq : null ;
142
+ return accept ( '!' ) && accept ( '=' ) ? Op .neq : null ;
138
143
}
139
144
}
140
145
@@ -155,7 +160,7 @@ private Exp _exp() {
155
160
if (leftExp == null ) { return null ; }
156
161
_whitespace (); // optional
157
162
if (currentCodePoint == '|' ) {
158
- if (!(next () && currentCodePoint == '|' && next ( ))) { return null ; }
163
+ if (!(next () && accept ( '|' ))) { return null ; }
159
164
_whitespace (); // optional
160
165
Exp rightExp = _term ();
161
166
if (rightExp == null ) { return null ; }
@@ -169,7 +174,7 @@ private Exp _term() {
169
174
if (leftExp == null ) { return null ; }
170
175
_whitespace (); // optional
171
176
if (currentCodePoint == '&' ) {
172
- if (!(next () && currentCodePoint == '&' && next ( ))) { return null ; }
177
+ if (!(next () && accept ( '&' ))) { return null ; }
173
178
_whitespace (); // optional
174
179
Exp rightExp = _factor ();
175
180
if (rightExp == null ) { return null ; }
@@ -186,7 +191,7 @@ private Exp _factor() {
186
191
Exp exp = _exp ();
187
192
if (exp == null ) { return null ; }
188
193
_whitespace (); // optional
189
- if (!( currentCodePoint == ')' && next () )) { return null ; }
194
+ if (!accept ( ')' )) { return null ; }
190
195
return exp ;
191
196
case '!' :
192
197
if (!next ()) { return null ; }
@@ -198,57 +203,110 @@ private Exp _factor() {
198
203
}
199
204
200
205
private boolean _tagStart () {
201
- return currentCodePoint == '<' && next () && currentCodePoint == '#' && next ();
206
+ if (!accept ('<' )) { return false ; }
207
+ _whitespace (); // optional
208
+ if (!accept ('#' )) { return false ; }
209
+ return true ;
202
210
}
203
211
204
- private boolean _tagEnd () {
205
- return currentCodePoint == '<' && next () && currentCodePoint == '/' && next () && currentCodePoint == '#' && next ();
212
+ private String _tagEnd () {
213
+ if (!accept ('<' )) { return null ; }
214
+ _whitespace (); // optional
215
+ if (!accept ('/' )) { return null ; }
216
+ _whitespace (); // optional
217
+ if (!accept ('#' )) { return null ; }
218
+ String tagName = _lowerAlpha ();
219
+ if (tagName == null ) { return null ; }
220
+ _whitespace (); // optional
221
+ if (currentCodePoint != '>' ) { return null ; }
222
+ next ();
223
+ return tagName ;
206
224
}
207
225
208
- private Node _ifTag () {
226
+ private Node _ifTagStart () {
209
227
if (!_tagStart ()) { return null ; }
210
228
String tagName = _lowerAlpha ();
211
229
if (!"if" .equals (tagName )) { return null ; }
212
230
_whitespace (); // optional
213
- if (!( currentCodePoint == '(' && next () )) { return null ; }
231
+ if (!accept ( '(' )) { return null ; }
214
232
_whitespace (); // optional
215
233
Exp exp = _exp ();
216
234
if (exp == null ) { return null ; }
217
235
_whitespace (); // optional
218
- if (!( currentCodePoint == ')' && next () )) { return null ; }
236
+ if (!accept ( ')' )) { return null ; }
219
237
_whitespace (); // optional
220
- if (currentCodePoint != '>' ) { return null ; }
221
- next ();
238
+ if (!accept ('>' )) { return null ; }
222
239
return new IfNode (exp );
223
240
}
224
241
225
242
Node parse () {
243
+ ParentNode root = new RootNode ();
244
+ //TODO: refactor this
245
+ if (next ()) {
246
+ for (;;) {
247
+ int startIndex = index ;
248
+ Node node = _ifTagStart ();
249
+ if (node != null ) {
250
+ addConstEndingAt (startIndex , root );
251
+ constStartIndex = index ;
252
+ if (!"if" .equals (parse ((ParentNode ) node ))) {
253
+ node = null ;
254
+ }
255
+ } else {
256
+ node = _var ();
257
+ }
258
+ if (node == null ) {
259
+ if (startIndex == index ) {
260
+ if (!next ()) { break ; }
261
+ }
262
+ } else {
263
+ addConstEndingAt (startIndex , root );
264
+ constStartIndex = index ;
265
+ root .children .add (node );
266
+ }
267
+ }
268
+ }
269
+ addConstEndingAt (source .length (), root );
270
+ return root ;
271
+ }
272
+
273
+ private String parse (ParentNode root ) {
226
274
//TODO: refactor this
275
+ constStartIndex = index ;
227
276
if (next ()) {
228
277
for (;;) {
229
278
int startIndex = index ;
230
- Node node = _ifTag ();
279
+ String tagEndName = _tagEnd ();
280
+ if (tagEndName != null ) {
281
+ addConstEndingAt (startIndex , root );
282
+ constStartIndex = index ;
283
+ return tagEndName ;
284
+ }
285
+ Node node = _ifTagStart ();
231
286
if (node == null ) {
232
287
node = _var ();
288
+ } else {
289
+ if (!"if" .equals (parse ((ParentNode ) node ))) {
290
+ node = null ;
291
+ }
233
292
}
234
293
if (node == null ) {
235
294
if (startIndex == index ) {
236
295
if (!next ()) { break ; }
237
296
}
238
297
} else {
239
- addConstEndingAt (startIndex );
298
+ addConstEndingAt (startIndex , root );
240
299
constStartIndex = index ;
241
- parent .children .add (node );
300
+ root .children .add (node );
242
301
}
243
302
}
244
303
}
245
- addConstEndingAt (source .length ());
246
- return parent ;
304
+ return null ;
247
305
}
248
306
249
- private void addConstEndingAt (int endIndex ) {
307
+ private void addConstEndingAt (int endIndex , ParentNode root ) {
250
308
if (endIndex - 1 > constStartIndex ) {
251
- parent .children .add (new ConstNode (source .substring (constStartIndex , endIndex )));
309
+ root .children .add (new ConstNode (source .substring (constStartIndex , endIndex )));
252
310
}
253
311
}
254
312
}
0 commit comments