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