svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.expressionevaluator / org.gvsig.expressionevaluator.lib / org.gvsig.expressionevaluator.lib.impl / src / main / java / org / gvsig / expressionevaluator / impl / DefaultStatement.java @ 45648
History | View | Annotate | Download (32.7 KB)
1 | 44139 | jjdelcerro | package org.gvsig.expressionevaluator.impl; |
---|---|---|---|
2 | |||
3 | import java.util.ArrayList; |
||
4 | import java.util.List; |
||
5 | 44379 | jjdelcerro | import java.util.Objects; |
6 | 44139 | jjdelcerro | import org.apache.commons.lang3.ArrayUtils; |
7 | import org.apache.commons.lang3.StringUtils; |
||
8 | 44738 | jjdelcerro | import org.apache.commons.lang3.tuple.ImmutablePair; |
9 | import org.apache.commons.lang3.tuple.Pair; |
||
10 | 44139 | jjdelcerro | import org.gvsig.expressionevaluator.Code; |
11 | 44750 | jjdelcerro | import org.gvsig.expressionevaluator.CodeBuilder; |
12 | 44139 | jjdelcerro | import org.gvsig.expressionevaluator.Codes; |
13 | 44262 | jjdelcerro | import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_LIST; |
14 | 44139 | jjdelcerro | import org.gvsig.expressionevaluator.ExpressionSyntaxException; |
15 | import org.gvsig.expressionevaluator.LexicalAnalyzer.Token; |
||
16 | import org.gvsig.expressionevaluator.Statement; |
||
17 | import org.gvsig.expressionevaluator.Statement.CompoundRule; |
||
18 | import org.gvsig.expressionevaluator.Statement.ConditionalRule; |
||
19 | import org.gvsig.expressionevaluator.Statement.Rule; |
||
20 | import org.gvsig.expressionevaluator.Statement.StatementContext; |
||
21 | import org.gvsig.expressionevaluator.impl.function.programming.CodeBlockFunction; |
||
22 | import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseCodes; |
||
23 | 44752 | jjdelcerro | import org.gvsig.expressionevaluator.Code.Callable; |
24 | 44769 | jjdelcerro | import org.gvsig.expressionevaluator.ExpressionBuilder; |
25 | import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_TUPLE; |
||
26 | 44139 | jjdelcerro | |
27 | /**
|
||
28 | *
|
||
29 | * @author jjdelcerro
|
||
30 | */
|
||
31 | public class DefaultStatement implements Statement { |
||
32 | |||
33 | private final List<Rule> rules; |
||
34 | private final String name; |
||
35 | 44384 | jjdelcerro | private StatementBuilder stmtBuilder;
|
36 | // private String codeId;
|
||
37 | // private ArgsBuilder argsBuilder;
|
||
38 | 44139 | jjdelcerro | |
39 | 44738 | jjdelcerro | public interface IsApplicableRule extends Rule { |
40 | public boolean isApplicable(StatementContext context); |
||
41 | } |
||
42 | |||
43 | 44139 | jjdelcerro | public interface RepeatRule extends CompoundRule { |
44 | |||
45 | public String getClassifier(); |
||
46 | } |
||
47 | |||
48 | 44738 | jjdelcerro | public class RuleRequireAnyToken implements IsApplicableRule { |
49 | 44139 | jjdelcerro | |
50 | private final String[] required_token; |
||
51 | 44750 | jjdelcerro | private String id; |
52 | 44139 | jjdelcerro | |
53 | 44144 | jjdelcerro | public RuleRequireAnyToken(String... required_token) { |
54 | 44139 | jjdelcerro | this.required_token = required_token;
|
55 | } |
||
56 | 44750 | jjdelcerro | |
57 | @Override
|
||
58 | public RuleRequireAnyToken capture_as(String... ids) { |
||
59 | this.id = ids[0]; |
||
60 | return this; |
||
61 | } |
||
62 | 44139 | jjdelcerro | |
63 | 44379 | jjdelcerro | @Override
|
64 | 44139 | jjdelcerro | public void parse(StatementContext context) { |
65 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
66 | 44139 | jjdelcerro | Token token = context.look_token(); |
67 | if (!token.is(this.required_token)) { |
||
68 | throw new ExpressionSyntaxException( |
||
69 | I18N.A_XTokenX_was_expected_and_XliteralX_was_found( |
||
70 | 44384 | jjdelcerro | StringUtils.join(this.required_token,", "), |
71 | 44139 | jjdelcerro | token.getLiteral() |
72 | ), |
||
73 | context.getLexicalAnalyzer() |
||
74 | ); |
||
75 | } |
||
76 | 44750 | jjdelcerro | if( this.id != null ) { |
77 | Code code = context.getCodeBuilder().constant(token.getValue()); |
||
78 | context.setCode(id, code); |
||
79 | } |
||
80 | 44139 | jjdelcerro | context.next_token(); |
81 | } |
||
82 | |||
83 | 44738 | jjdelcerro | @Override
|
84 | public boolean isApplicable(StatementContext context) { |
||
85 | Token token = context.next_token(); |
||
86 | boolean r = token.is(this.required_token); |
||
87 | context.trace(this.toString()+".isApplicable return "+r); |
||
88 | return r;
|
||
89 | 44139 | jjdelcerro | } |
90 | |||
91 | @Override
|
||
92 | public String toString() { |
||
93 | return "require_token(" + StringUtils.join(this.required_token) + ")"; |
||
94 | } |
||
95 | |||
96 | } |
||
97 | |||
98 | 44738 | jjdelcerro | public class RuleRequireIdentifier implements IsApplicableRule { |
99 | 44139 | jjdelcerro | |
100 | 44750 | jjdelcerro | private String id; |
101 | 44139 | jjdelcerro | |
102 | 44750 | jjdelcerro | public RuleRequireIdentifier() {
|
103 | 44139 | jjdelcerro | } |
104 | |||
105 | 44379 | jjdelcerro | @Override
|
106 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
107 | this.id = ids[0]; |
||
108 | return this; |
||
109 | } |
||
110 | |||
111 | @Override
|
||
112 | 44139 | jjdelcerro | public void parse(StatementContext context) { |
113 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
114 | 44139 | jjdelcerro | Token token = context.look_token(); |
115 | if (token.getType() != Token.IDENTIFIER) {
|
||
116 | throw new ExpressionSyntaxException( |
||
117 | I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()), |
||
118 | context.getLexicalAnalyzer() |
||
119 | ); |
||
120 | } |
||
121 | 44750 | jjdelcerro | if( this.id!=null ) { |
122 | String identifier = (String) token.getLiteral(); |
||
123 | Code code = context.getCodeBuilder().constant(identifier); |
||
124 | context.setCode(id, code); |
||
125 | } |
||
126 | 44139 | jjdelcerro | context.next_token(); |
127 | } |
||
128 | |||
129 | @Override
|
||
130 | 44738 | jjdelcerro | public boolean isApplicable(StatementContext context) { |
131 | Token token = context.next_token(); |
||
132 | boolean r = token.getType() == Token.IDENTIFIER;
|
||
133 | context.trace(this.toString()+".isApplicable return "+r); |
||
134 | return r;
|
||
135 | } |
||
136 | |||
137 | @Override
|
||
138 | 44139 | jjdelcerro | public String toString() { |
139 | return "require_identifier('" + this.id + "')"; |
||
140 | } |
||
141 | } |
||
142 | |||
143 | 44533 | jjdelcerro | public class RuleRequireLiteralString implements Rule { |
144 | |||
145 | 44750 | jjdelcerro | private String id; |
146 | 44533 | jjdelcerro | |
147 | 44750 | jjdelcerro | public RuleRequireLiteralString() {
|
148 | 44533 | jjdelcerro | } |
149 | |||
150 | @Override
|
||
151 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
152 | this.id = ids[0]; |
||
153 | return this; |
||
154 | } |
||
155 | |||
156 | @Override
|
||
157 | 44533 | jjdelcerro | public void parse(StatementContext context) { |
158 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
159 | 44533 | jjdelcerro | Token token = context.look_token(); |
160 | if (token.getType() != Token.STRING_LITERAL) {
|
||
161 | throw new ExpressionSyntaxException( |
||
162 | I18N.A_string_literal_was_expected(), |
||
163 | context.getLexicalAnalyzer() |
||
164 | ); |
||
165 | } |
||
166 | 44750 | jjdelcerro | if( this.id!=null ) { |
167 | String identifier = (String) token.getValue(); |
||
168 | Code code = context.getCodeBuilder().constant(identifier); |
||
169 | context.setCode(id, code); |
||
170 | context.next_token(); |
||
171 | } |
||
172 | 44533 | jjdelcerro | } |
173 | |||
174 | @Override
|
||
175 | public String toString() { |
||
176 | return "require_literal_string('" + this.id + "')"; |
||
177 | } |
||
178 | } |
||
179 | |||
180 | 44139 | jjdelcerro | public class RuleRequireExpression implements Rule { |
181 | |||
182 | 44750 | jjdelcerro | private String id; |
183 | 45153 | jjdelcerro | boolean allow_assignement;
|
184 | 44139 | jjdelcerro | |
185 | 45153 | jjdelcerro | public RuleRequireExpression(boolean allow_assignement) { |
186 | this.allow_assignement = allow_assignement;
|
||
187 | 44139 | jjdelcerro | } |
188 | |||
189 | 44379 | jjdelcerro | @Override
|
190 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
191 | this.id = ids[0]; |
||
192 | return this; |
||
193 | } |
||
194 | |||
195 | @Override
|
||
196 | 44139 | jjdelcerro | public void parse(StatementContext context) { |
197 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
198 | 45153 | jjdelcerro | Code code = context.parse_expression(allow_assignement); |
199 | 44139 | jjdelcerro | if (code == null) { |
200 | throw new ExpressionSyntaxException(context.getLexicalAnalyzer()); |
||
201 | } |
||
202 | 44750 | jjdelcerro | if( this.id!=null ) { |
203 | context.setCode(id, code); |
||
204 | } |
||
205 | 44139 | jjdelcerro | } |
206 | |||
207 | @Override
|
||
208 | public String toString() { |
||
209 | return "require_expression('" + this.id + "')"; |
||
210 | } |
||
211 | } |
||
212 | |||
213 | 44379 | jjdelcerro | |
214 | public class RuleSetExpression implements Rule { |
||
215 | |||
216 | private final String id; |
||
217 | private final Object value; |
||
218 | |||
219 | public RuleSetExpression(String id, Object value) { |
||
220 | this.id = id;
|
||
221 | this.value = value;
|
||
222 | } |
||
223 | |||
224 | @Override
|
||
225 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
226 | throw new UnsupportedOperationException("Unsupported operation."); |
||
227 | } |
||
228 | |||
229 | @Override
|
||
230 | 44379 | jjdelcerro | public void parse(StatementContext context) { |
231 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
232 | 44379 | jjdelcerro | if( this.value instanceof Code ) { |
233 | context.setCode(id, (Code) this.value);
|
||
234 | } else {
|
||
235 | context.setCode(id, context.getCodeBuilder().constant(value)); |
||
236 | } |
||
237 | } |
||
238 | |||
239 | @Override
|
||
240 | public String toString() { |
||
241 | return "set_expression('" + this.id + "', "+Objects.toString(value)+")"; |
||
242 | } |
||
243 | } |
||
244 | |||
245 | 44139 | jjdelcerro | public class RuleRequiereExpressions implements Rule { |
246 | |||
247 | 44750 | jjdelcerro | private String id; |
248 | 44139 | jjdelcerro | private final String separator; |
249 | |||
250 | 44750 | jjdelcerro | public RuleRequiereExpressions(String separator) { |
251 | 44139 | jjdelcerro | this.separator = separator;
|
252 | } |
||
253 | |||
254 | 44379 | jjdelcerro | @Override
|
255 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
256 | this.id = ids[0]; |
||
257 | return this; |
||
258 | } |
||
259 | |||
260 | @Override
|
||
261 | 44139 | jjdelcerro | public void parse(StatementContext context) { |
262 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
263 | 44139 | jjdelcerro | Codes codes = context.parse_expressions(this.separator);
|
264 | if (codes == null) { |
||
265 | throw new ExpressionSyntaxException(context.getLexicalAnalyzer()); |
||
266 | } |
||
267 | 44750 | jjdelcerro | if( this.id!=null ) { |
268 | Code code; |
||
269 | if( codes.size()==1 ) { |
||
270 | code = codes.get(0);
|
||
271 | } else {
|
||
272 | code = context.getCodeBuilder().function(CodeBlockFunction.NAME, codes); |
||
273 | } |
||
274 | context.setCode(id, code); |
||
275 | 44379 | jjdelcerro | } |
276 | 44139 | jjdelcerro | } |
277 | |||
278 | @Override
|
||
279 | public String toString() { |
||
280 | return "require_expressions('" + this.id + "', '" + this.separator + "')"; |
||
281 | } |
||
282 | } |
||
283 | |||
284 | 44533 | jjdelcerro | public abstract class AbstractConditionalRule implements ConditionalRule { |
285 | |||
286 | protected final List<Rule> onTrueRules; |
||
287 | protected final List<Rule> onFalseRules; |
||
288 | |||
289 | public AbstractConditionalRule() {
|
||
290 | this.onTrueRules = new ArrayList<>(); |
||
291 | this.onFalseRules = new ArrayList<>(); |
||
292 | } |
||
293 | |||
294 | 44750 | jjdelcerro | @Override
|
295 | public ConditionalRule capture_as(String... ids) { |
||
296 | throw new UnsupportedOperationException("Operation not suppted."); |
||
297 | } |
||
298 | |||
299 | 44533 | jjdelcerro | protected void parseOnTrueRules(StatementContext context) { |
300 | for (Rule rule : this.onTrueRules) { |
||
301 | rule.parse(context); |
||
302 | } |
||
303 | } |
||
304 | |||
305 | protected void parseOnFalseRules(StatementContext context) { |
||
306 | for (Rule rule : this.onFalseRules) { |
||
307 | rule.parse(context); |
||
308 | } |
||
309 | } |
||
310 | |||
311 | @Override
|
||
312 | public ConditionalRule addRuleOnTrue(Rule rule) {
|
||
313 | this.onTrueRules.add(rule);
|
||
314 | return this; |
||
315 | } |
||
316 | |||
317 | @Override
|
||
318 | public ConditionalRule addRuleOnFalse(Rule rule) {
|
||
319 | this.onFalseRules.add(rule);
|
||
320 | return this; |
||
321 | } |
||
322 | |||
323 | } |
||
324 | |||
325 | 44144 | jjdelcerro | public class RuleOptionalAnyToken implements ConditionalRule { |
326 | 44139 | jjdelcerro | |
327 | private final String[] optional_token; |
||
328 | private final List<Rule> onTrueRules; |
||
329 | private final List<Rule> onFalseRules; |
||
330 | 44750 | jjdelcerro | private String id; |
331 | 44139 | jjdelcerro | |
332 | 44144 | jjdelcerro | public RuleOptionalAnyToken(String... optional_token) { |
333 | 44139 | jjdelcerro | this.optional_token = optional_token;
|
334 | this.onTrueRules = new ArrayList<>(); |
||
335 | this.onFalseRules = new ArrayList<>(); |
||
336 | } |
||
337 | |||
338 | 44379 | jjdelcerro | @Override
|
339 | 44750 | jjdelcerro | public ConditionalRule capture_as(String... ids) { |
340 | this.id = ids[0]; |
||
341 | return this; |
||
342 | } |
||
343 | |||
344 | @Override
|
||
345 | 44139 | jjdelcerro | public void parse(StatementContext context) { |
346 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
347 | 44139 | jjdelcerro | Token token = context.look_token(); |
348 | if (token.is(this.optional_token)) { |
||
349 | 44750 | jjdelcerro | if( this.id!=null ) { |
350 | Code code = context.getCodeBuilder().constant(token.getValue()); |
||
351 | context.setCode(id, code); |
||
352 | } |
||
353 | 44139 | jjdelcerro | context.next_token(); |
354 | for (Rule rule : this.onTrueRules) { |
||
355 | rule.parse(context); |
||
356 | } |
||
357 | } else {
|
||
358 | for (Rule rule : this.onFalseRules) { |
||
359 | rule.parse(context); |
||
360 | } |
||
361 | } |
||
362 | } |
||
363 | |||
364 | 44379 | jjdelcerro | @Override
|
365 | 44144 | jjdelcerro | public RuleOptionalAnyToken addRuleOnTrue(Rule rule) {
|
366 | 44139 | jjdelcerro | this.onTrueRules.add(rule);
|
367 | return this; |
||
368 | } |
||
369 | |||
370 | 44379 | jjdelcerro | @Override
|
371 | 44144 | jjdelcerro | public RuleOptionalAnyToken addRuleOnFalse(Rule rule) {
|
372 | 44139 | jjdelcerro | this.onFalseRules.add(rule);
|
373 | return this; |
||
374 | } |
||
375 | |||
376 | @Override
|
||
377 | public String toString() { |
||
378 | 44738 | jjdelcerro | return "optional_token(" + StringUtils.join(this.optional_token) + ") onTrue:" + StringUtils.join(onTrueRules, ",")+", onFalse:" + StringUtils.join(onFalseRules, ","); |
379 | 44139 | jjdelcerro | } |
380 | } |
||
381 | |||
382 | 44738 | jjdelcerro | public class RuleSwitchToken implements SwichTokenRule { |
383 | |||
384 | private final List<Pair<String,Rule[]>> caseRules; |
||
385 | private Rule[] defaultRule; |
||
386 | |||
387 | public RuleSwitchToken() {
|
||
388 | this.caseRules = new ArrayList<>(); |
||
389 | } |
||
390 | |||
391 | @Override
|
||
392 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
393 | throw new UnsupportedOperationException("Unsupported operation."); |
||
394 | } |
||
395 | |||
396 | @Override
|
||
397 | 44738 | jjdelcerro | public void parse(StatementContext context) { |
398 | context.trace(this.toString()+".parse"); |
||
399 | Token token = context.look_token(); |
||
400 | for (Pair<String, Rule[]> caseRule : caseRules) { |
||
401 | if( token.is(caseRule.getKey()) ) {
|
||
402 | context.next_token(); |
||
403 | for (Rule rule : caseRule.getValue()) {
|
||
404 | rule.parse(context); |
||
405 | } |
||
406 | return;
|
||
407 | } |
||
408 | } |
||
409 | if( defaultRule!=null ) { |
||
410 | for (Rule rule : defaultRule) {
|
||
411 | rule.parse(context); |
||
412 | } |
||
413 | } |
||
414 | } |
||
415 | |||
416 | @Override
|
||
417 | public SwichTokenRule addCase(String token, Rule... rules) { |
||
418 | this.caseRules.add(new ImmutablePair(token,rules)); |
||
419 | return this; |
||
420 | } |
||
421 | |||
422 | @Override
|
||
423 | public SwichTokenRule addDefault(Rule... rules) {
|
||
424 | this.defaultRule = rules;
|
||
425 | return this; |
||
426 | } |
||
427 | |||
428 | @Override
|
||
429 | public String toString() { |
||
430 | return "switch_token() rules:" + StringUtils.join(this.caseRules,",") + " default: " + defaultRule; |
||
431 | } |
||
432 | } |
||
433 | |||
434 | 44144 | jjdelcerro | public class RuleRepeatUntilAnyTokens implements RepeatRule { |
435 | 44139 | jjdelcerro | |
436 | private final String[] exit_tokens; |
||
437 | private final List<Rule> rules; |
||
438 | private int counter; |
||
439 | |||
440 | 44144 | jjdelcerro | public RuleRepeatUntilAnyTokens(String[] exit_tokens) { |
441 | 44139 | jjdelcerro | this.exit_tokens = exit_tokens;
|
442 | this.rules = new ArrayList<>(); |
||
443 | } |
||
444 | |||
445 | 44379 | jjdelcerro | @Override
|
446 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
447 | throw new UnsupportedOperationException("Operation not suppted."); |
||
448 | } |
||
449 | |||
450 | @Override
|
||
451 | 44139 | jjdelcerro | public void parse(StatementContext context) { |
452 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
453 | 44139 | jjdelcerro | String save = context.getCodeClassifier();
|
454 | try {
|
||
455 | this.counter = 1; |
||
456 | while (true) { |
||
457 | Token token = context.look_token(); |
||
458 | if (token.is(this.exit_tokens)) { |
||
459 | break;
|
||
460 | } |
||
461 | context.setCodeClassifier(String.valueOf(counter).trim());
|
||
462 | for (Rule rule : rules) {
|
||
463 | rule.parse(context); |
||
464 | } |
||
465 | this.counter = this.counter + 1; |
||
466 | } |
||
467 | } finally {
|
||
468 | context.setCodeClassifier(save); |
||
469 | } |
||
470 | } |
||
471 | |||
472 | 44379 | jjdelcerro | @Override
|
473 | 44144 | jjdelcerro | public RuleRepeatUntilAnyTokens addRule(Rule rule) {
|
474 | 44139 | jjdelcerro | this.rules.add(rule);
|
475 | return this; |
||
476 | } |
||
477 | |||
478 | @Override
|
||
479 | public String getClassifier() { |
||
480 | String s = String.valueOf(counter).trim(); |
||
481 | return s;
|
||
482 | } |
||
483 | |||
484 | @Override
|
||
485 | public String toString() { |
||
486 | return "repeat_until_tokens('" + ArrayUtils.toString(this.exit_tokens) + "') rules:" + StringUtils.join(rules, ","); |
||
487 | } |
||
488 | } |
||
489 | |||
490 | 44738 | jjdelcerro | public class RuleRepeat implements RepeatRule { |
491 | |||
492 | private final List<Rule> rules; |
||
493 | private int counter; |
||
494 | |||
495 | public RuleRepeat() {
|
||
496 | this.rules = new ArrayList<>(); |
||
497 | } |
||
498 | 44750 | jjdelcerro | |
499 | 44738 | jjdelcerro | @Override
|
500 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
501 | throw new UnsupportedOperationException("Operation not suppted."); |
||
502 | } |
||
503 | |||
504 | @Override
|
||
505 | 44738 | jjdelcerro | public void parse(StatementContext context) { |
506 | context.trace(this.toString()+".parse"); |
||
507 | String save = context.getCodeClassifier();
|
||
508 | try {
|
||
509 | this.counter = 1; |
||
510 | boolean breakloop = false; |
||
511 | while (!breakloop) {
|
||
512 | context.setCodeClassifier(String.valueOf(counter).trim());
|
||
513 | for (Rule rule : rules) {
|
||
514 | try {
|
||
515 | rule.parse(context); |
||
516 | } catch(BreakLoopException ex) {
|
||
517 | breakloop = true;
|
||
518 | break;
|
||
519 | } |
||
520 | } |
||
521 | this.counter = this.counter + 1; |
||
522 | } |
||
523 | } finally {
|
||
524 | context.setCodeClassifier(save); |
||
525 | } |
||
526 | } |
||
527 | |||
528 | @Override
|
||
529 | public RuleRepeat addRule(Rule rule) {
|
||
530 | this.rules.add(rule);
|
||
531 | return this; |
||
532 | } |
||
533 | |||
534 | @Override
|
||
535 | public String getClassifier() { |
||
536 | String s = String.valueOf(counter).trim(); |
||
537 | return s;
|
||
538 | } |
||
539 | |||
540 | @Override
|
||
541 | public String toString() { |
||
542 | return "repeat() rules:" + StringUtils.join(rules, ","); |
||
543 | } |
||
544 | } |
||
545 | |||
546 | public static class BreakLoopException extends RuntimeException { |
||
547 | |||
548 | } |
||
549 | |||
550 | public static class RuleBreakLoop implements Rule { |
||
551 | |||
552 | public RuleBreakLoop() {
|
||
553 | } |
||
554 | |||
555 | @Override
|
||
556 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
557 | throw new UnsupportedOperationException("Operation not suppted."); |
||
558 | } |
||
559 | |||
560 | @Override
|
||
561 | 44738 | jjdelcerro | public void parse(StatementContext context) { |
562 | context.trace(this.toString()+".parse"); |
||
563 | throw new BreakLoopException(); |
||
564 | } |
||
565 | |||
566 | @Override
|
||
567 | public String toString() { |
||
568 | return "break_loop()"; |
||
569 | } |
||
570 | } |
||
571 | |||
572 | 44750 | jjdelcerro | public static class RuleFail implements Rule { |
573 | |||
574 | public RuleFail() {
|
||
575 | } |
||
576 | |||
577 | @Override
|
||
578 | public Rule capture_as(String... ids) { |
||
579 | throw new UnsupportedOperationException("Operation not suppted."); |
||
580 | } |
||
581 | |||
582 | @Override
|
||
583 | public void parse(StatementContext context) { |
||
584 | context.trace(this.toString()+".parse"); |
||
585 | throw new ExpressionSyntaxException(); |
||
586 | } |
||
587 | |||
588 | @Override
|
||
589 | public String toString() { |
||
590 | return "fail()"; |
||
591 | } |
||
592 | } |
||
593 | |||
594 | 44533 | jjdelcerro | public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule { |
595 | 44139 | jjdelcerro | |
596 | 44750 | jjdelcerro | private String id; |
597 | 44139 | jjdelcerro | private final String separator; |
598 | |||
599 | 44750 | jjdelcerro | public RuleOptionalIdentifiers(String separator) { |
600 | 44533 | jjdelcerro | super();
|
601 | 44139 | jjdelcerro | this.separator = separator;
|
602 | } |
||
603 | |||
604 | 44379 | jjdelcerro | @Override
|
605 | 44750 | jjdelcerro | public ConditionalRule capture_as(String... ids) { |
606 | this.id = ids[0]; |
||
607 | return this; |
||
608 | } |
||
609 | |||
610 | @Override
|
||
611 | 44139 | jjdelcerro | public void parse(StatementContext context) { |
612 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
613 | 44139 | jjdelcerro | BaseCodes args = (BaseCodes) context.getCodeBuilder().args(); |
614 | Token token = context.look_token(); |
||
615 | while (token.getType() == Token.IDENTIFIER) {
|
||
616 | String identifier = (String) token.getLiteral(); |
||
617 | 44384 | jjdelcerro | if( context.isReservedWord(identifier) ) {
|
618 | break;
|
||
619 | } |
||
620 | 44139 | jjdelcerro | Code code = context.getCodeBuilder().constant(identifier); |
621 | args.add(code); |
||
622 | context.next_token(); |
||
623 | token = context.look_token(); |
||
624 | if (!token.is(this.separator)) { |
||
625 | break;
|
||
626 | } |
||
627 | context.next_token(); |
||
628 | token = context.look_token(); |
||
629 | } |
||
630 | if (args.size() != 0) { |
||
631 | 44750 | jjdelcerro | if( this.id!=null ) { |
632 | 44533 | jjdelcerro | Code code = context.getCodeBuilder().function(FUNCTION_LIST, args); |
633 | context.setCode(id, code); |
||
634 | 44750 | jjdelcerro | } |
635 | this.parseOnTrueRules(context);
|
||
636 | 44533 | jjdelcerro | } else {
|
637 | this.parseOnFalseRules(context);
|
||
638 | 44139 | jjdelcerro | } |
639 | } |
||
640 | |||
641 | @Override
|
||
642 | public String toString() { |
||
643 | return "optional_identifiers('" + id + "', '" + this.separator + "')"; |
||
644 | } |
||
645 | } |
||
646 | |||
647 | 44740 | jjdelcerro | public class RuleRequireIdentifiers implements Rule { |
648 | |||
649 | 44750 | jjdelcerro | private String id; |
650 | 44740 | jjdelcerro | private final String separator; |
651 | |||
652 | 44750 | jjdelcerro | public RuleRequireIdentifiers(String separator) { |
653 | 44740 | jjdelcerro | super();
|
654 | this.separator = separator;
|
||
655 | } |
||
656 | |||
657 | @Override
|
||
658 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
659 | this.id = ids[0]; |
||
660 | return this; |
||
661 | } |
||
662 | |||
663 | @Override
|
||
664 | 44740 | jjdelcerro | public void parse(StatementContext context) { |
665 | context.trace(this.toString()+".parse"); |
||
666 | BaseCodes args = (BaseCodes) context.getCodeBuilder().args(); |
||
667 | Token token = context.look_token(); |
||
668 | while (token.getType() == Token.IDENTIFIER) {
|
||
669 | String identifier = (String) token.getLiteral(); |
||
670 | if( context.isReservedWord(identifier) ) {
|
||
671 | break;
|
||
672 | } |
||
673 | 44769 | jjdelcerro | Code code = context.getCodeBuilder().identifier(identifier); |
674 | 44740 | jjdelcerro | args.add(code); |
675 | context.next_token(); |
||
676 | token = context.look_token(); |
||
677 | if (!token.is(this.separator)) { |
||
678 | break;
|
||
679 | } |
||
680 | context.next_token(); |
||
681 | token = context.look_token(); |
||
682 | } |
||
683 | if (args.size() == 0) { |
||
684 | throw new ExpressionSyntaxException( |
||
685 | I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()), |
||
686 | context.getLexicalAnalyzer() |
||
687 | ); |
||
688 | } |
||
689 | 44750 | jjdelcerro | if( this.id!=null ) { |
690 | 44769 | jjdelcerro | Code code = context.getCodeBuilder().function(FUNCTION_TUPLE, args); |
691 | 44750 | jjdelcerro | context.setCode(id, code); |
692 | } |
||
693 | 44740 | jjdelcerro | } |
694 | |||
695 | @Override
|
||
696 | public String toString() { |
||
697 | return "require_identifiers('" + id + "', '" + this.separator + "')"; |
||
698 | } |
||
699 | } |
||
700 | |||
701 | 44533 | jjdelcerro | public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule { |
702 | |||
703 | 44750 | jjdelcerro | private String id; |
704 | 44533 | jjdelcerro | |
705 | 44750 | jjdelcerro | public RuleOptionalLiteralString() {
|
706 | 44533 | jjdelcerro | super();
|
707 | } |
||
708 | |||
709 | @Override
|
||
710 | 44750 | jjdelcerro | public ConditionalRule capture_as(String... ids) { |
711 | this.id = ids[0]; |
||
712 | return this; |
||
713 | } |
||
714 | |||
715 | @Override
|
||
716 | 44533 | jjdelcerro | public void parse(StatementContext context) { |
717 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
718 | 44533 | jjdelcerro | Token token = context.look_token(); |
719 | if (token.getType() == Token.STRING_LITERAL) {
|
||
720 | 44750 | jjdelcerro | if( this.id!=null ) { |
721 | String s = (String) token.getValue(); |
||
722 | Code code = context.getCodeBuilder().constant(s); |
||
723 | context.setCode(id, code); |
||
724 | context.next_token(); |
||
725 | } |
||
726 | 44533 | jjdelcerro | this.parseOnTrueRules(context);
|
727 | } else {
|
||
728 | this.parseOnFalseRules(context);
|
||
729 | } |
||
730 | } |
||
731 | |||
732 | @Override
|
||
733 | public String toString() { |
||
734 | return "optional_literal_string('" + id + "')"; |
||
735 | } |
||
736 | } |
||
737 | |||
738 | 44384 | jjdelcerro | public static class ArgsBuilderFromNames implements ArgsBuilder { |
739 | 44139 | jjdelcerro | |
740 | 44738 | jjdelcerro | protected final String[] argNames; |
741 | 44139 | jjdelcerro | |
742 | 44384 | jjdelcerro | public ArgsBuilderFromNames(String... argNames) { |
743 | 44139 | jjdelcerro | this.argNames = argNames;
|
744 | } |
||
745 | |||
746 | 44379 | jjdelcerro | @Override
|
747 | 44738 | jjdelcerro | public String toString() { |
748 | return "args_names("+StringUtils.join(argNames,",")+")"; |
||
749 | } |
||
750 | |||
751 | @Override
|
||
752 | 44139 | jjdelcerro | public Codes build(StatementContext context) {
|
753 | 44738 | jjdelcerro | context.trace(this.toString()+".build"); |
754 | 44139 | jjdelcerro | BaseCodes args = (BaseCodes) context.getCodeBuilder().args(); |
755 | for (String argName : argNames) { |
||
756 | if (argName.contains("#")) { |
||
757 | 45132 | jjdelcerro | Code code = context.getCode(argName); |
758 | if (code == null) { |
||
759 | int n = 1; |
||
760 | while (true) { |
||
761 | String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1); |
||
762 | code = context.getCode(argNameX); |
||
763 | if (code == null) { |
||
764 | break;
|
||
765 | } |
||
766 | args.add(code); |
||
767 | n++; |
||
768 | 44139 | jjdelcerro | } |
769 | 45132 | jjdelcerro | } else {
|
770 | 44750 | jjdelcerro | args.add(code); |
771 | 44139 | jjdelcerro | } |
772 | } else {
|
||
773 | Code code = context.getCode(argName); |
||
774 | 44592 | jjdelcerro | // if( code == null) {
|
775 | // code = context.getCodeBuilder().constant(null);
|
||
776 | // }
|
||
777 | 44750 | jjdelcerro | args.add(code); |
778 | 44139 | jjdelcerro | } |
779 | } |
||
780 | return args;
|
||
781 | } |
||
782 | } |
||
783 | |||
784 | 44750 | jjdelcerro | public static class FixedArgsBuilderFromNames implements ArgsBuilder { |
785 | |||
786 | protected final String[] argNames; |
||
787 | |||
788 | public FixedArgsBuilderFromNames(String... argNames) { |
||
789 | this.argNames = argNames;
|
||
790 | } |
||
791 | |||
792 | @Override
|
||
793 | public String toString() { |
||
794 | return "fixed_args_names("+StringUtils.join(argNames,",")+")"; |
||
795 | } |
||
796 | |||
797 | @Override
|
||
798 | public Codes build(StatementContext context) {
|
||
799 | context.trace(this.toString()+".build"); |
||
800 | CodeBuilder codeBuilder = context.getCodeBuilder(); |
||
801 | BaseCodes args = (BaseCodes) codeBuilder.args(); |
||
802 | for (String argName : argNames) { |
||
803 | if (argName.contains("#")) { |
||
804 | int n = 1; |
||
805 | BaseCodes argsX = (BaseCodes) codeBuilder.args(); |
||
806 | while (true) { |
||
807 | String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1); |
||
808 | Code code = context.getCode(argNameX); |
||
809 | if (code == null) { |
||
810 | break;
|
||
811 | } |
||
812 | argsX.add(code); |
||
813 | n++; |
||
814 | } |
||
815 | |||
816 | args.add(codeBuilder.tuple(argsX)); |
||
817 | } else {
|
||
818 | Code code = context.getCode(argName); |
||
819 | if( code == null) { |
||
820 | code = context.getCodeBuilder().constant(null);
|
||
821 | } |
||
822 | args.add(code); |
||
823 | } |
||
824 | } |
||
825 | return args;
|
||
826 | } |
||
827 | } |
||
828 | |||
829 | 44384 | jjdelcerro | public static class ArgsBuilderExpand extends ArgsBuilderFromNames { |
830 | 44139 | jjdelcerro | |
831 | 44384 | jjdelcerro | public ArgsBuilderExpand(String... argNames) { |
832 | 44139 | jjdelcerro | super(argNames);
|
833 | } |
||
834 | |||
835 | 44379 | jjdelcerro | @Override
|
836 | 44738 | jjdelcerro | public String toString() { |
837 | return "args_expand("+StringUtils.join(argNames,",")+")"; |
||
838 | } |
||
839 | |||
840 | @Override
|
||
841 | 44139 | jjdelcerro | public Codes build(StatementContext context) {
|
842 | BaseCodes args = (BaseCodes) context.getCodeBuilder().args(); |
||
843 | |||
844 | Codes base_args = super.build(context);
|
||
845 | for (Code arg : base_args) {
|
||
846 | 44752 | jjdelcerro | if( arg.code() == Code.CALLABLE &&
|
847 | ((Callable)arg).name().equals(CodeBlockFunction.NAME) ) {
|
||
848 | Codes block_args = ((Callable)arg).parameters();
|
||
849 | 44139 | jjdelcerro | for (Code block_arg : block_args) {
|
850 | args.add(block_arg); |
||
851 | } |
||
852 | } else {
|
||
853 | args.add(arg); |
||
854 | } |
||
855 | } |
||
856 | return args;
|
||
857 | } |
||
858 | } |
||
859 | |||
860 | 44384 | jjdelcerro | public static class StatementBuilderBase implements StatementBuilder { |
861 | protected ArgsBuilder argsBuilder;
|
||
862 | protected String codeID; |
||
863 | |||
864 | public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) { |
||
865 | this.codeID = codeID;
|
||
866 | this.argsBuilder = argsBuilder;
|
||
867 | } |
||
868 | |||
869 | @Override
|
||
870 | public String getCodeID() { |
||
871 | return this.codeID; |
||
872 | } |
||
873 | |||
874 | @Override
|
||
875 | public ArgsBuilder getArgsBuilder() {
|
||
876 | return this.argsBuilder; |
||
877 | } |
||
878 | |||
879 | @Override
|
||
880 | public Code build(StatementContext context) {
|
||
881 | Codes args = this.getArgsBuilder().build(context);
|
||
882 | Code code = null;
|
||
883 | if (this.getCodeID() == null) { |
||
884 | code = args.get(0);
|
||
885 | } else {
|
||
886 | if (args.size() == 0) { |
||
887 | code = context.getCodeBuilder().function(this.getCodeID(), null); |
||
888 | } else {
|
||
889 | // Si es un bloque dentro de otro, dejamos solo uno.
|
||
890 | if( args.size()==1 && |
||
891 | StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,this.getCodeID()) ) {
|
||
892 | Code code0 = args.get(0);
|
||
893 | 44752 | jjdelcerro | if( code0.code() == Code.CALLABLE &&
|
894 | StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Callable)code0).name())
|
||
895 | 44384 | jjdelcerro | ) { |
896 | code = code0; |
||
897 | } |
||
898 | } |
||
899 | if( code == null ) { |
||
900 | code = context.getCodeBuilder().function(this.getCodeID(), args);
|
||
901 | } |
||
902 | } |
||
903 | } |
||
904 | return code;
|
||
905 | } |
||
906 | } |
||
907 | |||
908 | 44139 | jjdelcerro | public DefaultStatement(String name) { |
909 | this.rules = new ArrayList<>(); |
||
910 | 44384 | jjdelcerro | this.stmtBuilder = null; |
911 | 44139 | jjdelcerro | this.name = name;
|
912 | } |
||
913 | |||
914 | 44379 | jjdelcerro | @Override
|
915 | 44139 | jjdelcerro | public String getName() { |
916 | return name;
|
||
917 | } |
||
918 | |||
919 | @Override
|
||
920 | 44144 | jjdelcerro | public Rule require_any_token(String... token) { |
921 | return new RuleRequireAnyToken(token); |
||
922 | 44139 | jjdelcerro | } |
923 | |||
924 | @Override
|
||
925 | 44750 | jjdelcerro | public Rule require_identifier() {
|
926 | return new RuleRequireIdentifier(); |
||
927 | 44139 | jjdelcerro | } |
928 | |||
929 | @Override
|
||
930 | 44750 | jjdelcerro | public Rule require_identifiers(String sep) { |
931 | return new RuleRequireIdentifiers(sep); |
||
932 | 44740 | jjdelcerro | } |
933 | |||
934 | @Override
|
||
935 | 44750 | jjdelcerro | public Rule require_literal_string() {
|
936 | return new RuleRequireLiteralString(); |
||
937 | 44533 | jjdelcerro | } |
938 | |||
939 | @Override
|
||
940 | 44379 | jjdelcerro | public Rule set_expression(String id, Object value) { |
941 | return new RuleSetExpression(id, value); |
||
942 | } |
||
943 | |||
944 | @Override
|
||
945 | 44750 | jjdelcerro | public Rule require_expression() {
|
946 | 45153 | jjdelcerro | return this.require_expression(true); |
947 | 44139 | jjdelcerro | } |
948 | |||
949 | @Override
|
||
950 | 45153 | jjdelcerro | public Rule require_expression(boolean allow_assignement) { |
951 | return new RuleRequireExpression(allow_assignement); |
||
952 | } |
||
953 | |||
954 | @Override
|
||
955 | 44750 | jjdelcerro | public Rule require_expressions(String separator) { |
956 | return new RuleRequiereExpressions(separator); |
||
957 | 44139 | jjdelcerro | } |
958 | |||
959 | @Override
|
||
960 | 44144 | jjdelcerro | public ConditionalRule optional_any_token(String... id) { |
961 | return new RuleOptionalAnyToken(id); |
||
962 | 44139 | jjdelcerro | } |
963 | |||
964 | @Override
|
||
965 | 44750 | jjdelcerro | public ConditionalRule optional_identifiers(String separator) { |
966 | return new RuleOptionalIdentifiers(separator); |
||
967 | 44139 | jjdelcerro | } |
968 | |||
969 | @Override
|
||
970 | 44750 | jjdelcerro | public ConditionalRule optional_literal_string() {
|
971 | return new RuleOptionalLiteralString(); |
||
972 | 44533 | jjdelcerro | } |
973 | |||
974 | @Override
|
||
975 | 44144 | jjdelcerro | public CompoundRule repeat_until_any_tokens(String... tokens) { |
976 | return new RuleRepeatUntilAnyTokens(tokens); |
||
977 | 44139 | jjdelcerro | } |
978 | |||
979 | @Override
|
||
980 | public Statement addRule(Rule rule) { |
||
981 | this.rules.add(rule);
|
||
982 | return this; |
||
983 | } |
||
984 | |||
985 | @Override
|
||
986 | public boolean isApplicable(StatementContext context) { |
||
987 | if (this.rules.isEmpty()) { |
||
988 | return false; |
||
989 | } |
||
990 | 44738 | jjdelcerro | context.trace(this.getName()+".isApplicable"); |
991 | 44750 | jjdelcerro | context.save_state(); |
992 | 44738 | jjdelcerro | try {
|
993 | for (Rule rule : rules) {
|
||
994 | 44750 | jjdelcerro | if( rule == null ) { |
995 | continue;
|
||
996 | 44738 | jjdelcerro | } |
997 | 44750 | jjdelcerro | if (rule instanceof IsApplicableRule) { |
998 | if( !((IsApplicableRule) rule).isApplicable(context) ) {
|
||
999 | context.trace(this.getName()+".isApplicable return false"); |
||
1000 | return false; |
||
1001 | } |
||
1002 | } else {
|
||
1003 | rule.parse(context); |
||
1004 | 44738 | jjdelcerro | } |
1005 | } |
||
1006 | 44750 | jjdelcerro | context.trace(this.getName()+".isApplicable return true"); |
1007 | return true; |
||
1008 | } catch(Exception ex) { |
||
1009 | context.trace(this.getName()+".isApplicable return false (error)"); |
||
1010 | return false; |
||
1011 | 44738 | jjdelcerro | } finally {
|
1012 | 44750 | jjdelcerro | context.restore_state(); |
1013 | 44139 | jjdelcerro | } |
1014 | } |
||
1015 | |||
1016 | @Override
|
||
1017 | public ArgsBuilder args_names(String... args) { |
||
1018 | ArgsBuilder x = new ArgsBuilderFromNames(args);
|
||
1019 | return x;
|
||
1020 | } |
||
1021 | |||
1022 | @Override
|
||
1023 | 44750 | jjdelcerro | public ArgsBuilder fixed_args_names(String... args) { |
1024 | ArgsBuilder x = new FixedArgsBuilderFromNames(args);
|
||
1025 | return x;
|
||
1026 | } |
||
1027 | |||
1028 | @Override
|
||
1029 | 44139 | jjdelcerro | public ArgsBuilder args_expand(String... args) { |
1030 | ArgsBuilder x = new ArgsBuilderExpand(args);
|
||
1031 | return x;
|
||
1032 | } |
||
1033 | |||
1034 | @Override
|
||
1035 | 44384 | jjdelcerro | public void code(final String id, final ArgsBuilder argsBuilder) { |
1036 | this.builder(new StatementBuilderBase(id, argsBuilder)); |
||
1037 | 44139 | jjdelcerro | } |
1038 | |||
1039 | 44738 | jjdelcerro | @Override
|
1040 | 44384 | jjdelcerro | public void builder(StatementBuilder builder) { |
1041 | this.stmtBuilder = builder;
|
||
1042 | } |
||
1043 | |||
1044 | 44139 | jjdelcerro | @Override
|
1045 | public Code parse(StatementContext context) {
|
||
1046 | 44738 | jjdelcerro | context.trace(this.getName()+".parse"); |
1047 | 44139 | jjdelcerro | for (Rule rule : rules) {
|
1048 | rule.parse(context); |
||
1049 | } |
||
1050 | 44384 | jjdelcerro | Code code = this.stmtBuilder.build(context);
|
1051 | 44738 | jjdelcerro | context.trace(this.getName()+".return "+code); |
1052 | 44139 | jjdelcerro | return code;
|
1053 | } |
||
1054 | |||
1055 | @Override
|
||
1056 | public String toString() { |
||
1057 | return this.getName() + " " + StringUtils.join(this.rules, ";"); |
||
1058 | |||
1059 | } |
||
1060 | 44738 | jjdelcerro | |
1061 | @Override
|
||
1062 | public CompoundRule repeat() {
|
||
1063 | return new RuleRepeat(); |
||
1064 | } |
||
1065 | |||
1066 | @Override
|
||
1067 | 44750 | jjdelcerro | public Rule fail() {
|
1068 | return new RuleFail(); |
||
1069 | } |
||
1070 | |||
1071 | @Override
|
||
1072 | 44738 | jjdelcerro | public Rule break_loop() {
|
1073 | return new RuleBreakLoop(); |
||
1074 | } |
||
1075 | |||
1076 | @Override
|
||
1077 | public SwichTokenRule switch_token() {
|
||
1078 | return new RuleSwitchToken(); |
||
1079 | } |
||
1080 | |||
1081 | 44139 | jjdelcerro | } |