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 @ 46050
History | View | Annotate | Download (32.9 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 | 46050 | omartinez | context.setOtherValues(counter); |
463 | 44139 | jjdelcerro | for (Rule rule : rules) {
|
464 | rule.parse(context); |
||
465 | } |
||
466 | 46050 | omartinez | this.counter = (int) context.getOtherValues(); |
467 | 44139 | jjdelcerro | this.counter = this.counter + 1; |
468 | } |
||
469 | } finally {
|
||
470 | context.setCodeClassifier(save); |
||
471 | } |
||
472 | } |
||
473 | |||
474 | 44379 | jjdelcerro | @Override
|
475 | 44144 | jjdelcerro | public RuleRepeatUntilAnyTokens addRule(Rule rule) {
|
476 | 44139 | jjdelcerro | this.rules.add(rule);
|
477 | return this; |
||
478 | } |
||
479 | |||
480 | @Override
|
||
481 | public String getClassifier() { |
||
482 | String s = String.valueOf(counter).trim(); |
||
483 | return s;
|
||
484 | } |
||
485 | |||
486 | @Override
|
||
487 | public String toString() { |
||
488 | return "repeat_until_tokens('" + ArrayUtils.toString(this.exit_tokens) + "') rules:" + StringUtils.join(rules, ","); |
||
489 | } |
||
490 | } |
||
491 | |||
492 | 44738 | jjdelcerro | public class RuleRepeat implements RepeatRule { |
493 | |||
494 | private final List<Rule> rules; |
||
495 | private int counter; |
||
496 | |||
497 | public RuleRepeat() {
|
||
498 | this.rules = new ArrayList<>(); |
||
499 | } |
||
500 | 44750 | jjdelcerro | |
501 | 44738 | jjdelcerro | @Override
|
502 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
503 | throw new UnsupportedOperationException("Operation not suppted."); |
||
504 | } |
||
505 | |||
506 | @Override
|
||
507 | 44738 | jjdelcerro | public void parse(StatementContext context) { |
508 | context.trace(this.toString()+".parse"); |
||
509 | 46050 | omartinez | String saveCodeClassifier = context.getCodeClassifier();
|
510 | 44738 | jjdelcerro | try {
|
511 | this.counter = 1; |
||
512 | boolean breakloop = false; |
||
513 | while (!breakloop) {
|
||
514 | context.setCodeClassifier(String.valueOf(counter).trim());
|
||
515 | 46050 | omartinez | context.setOtherValues(counter); |
516 | 44738 | jjdelcerro | for (Rule rule : rules) {
|
517 | try {
|
||
518 | rule.parse(context); |
||
519 | } catch(BreakLoopException ex) {
|
||
520 | breakloop = true;
|
||
521 | break;
|
||
522 | } |
||
523 | } |
||
524 | 46050 | omartinez | this.counter = (int) context.getOtherValues(); |
525 | 44738 | jjdelcerro | this.counter = this.counter + 1; |
526 | } |
||
527 | } finally {
|
||
528 | 46050 | omartinez | context.setCodeClassifier(saveCodeClassifier); |
529 | 44738 | jjdelcerro | } |
530 | } |
||
531 | |||
532 | @Override
|
||
533 | public RuleRepeat addRule(Rule rule) {
|
||
534 | this.rules.add(rule);
|
||
535 | return this; |
||
536 | } |
||
537 | |||
538 | @Override
|
||
539 | public String getClassifier() { |
||
540 | String s = String.valueOf(counter).trim(); |
||
541 | return s;
|
||
542 | } |
||
543 | |||
544 | @Override
|
||
545 | public String toString() { |
||
546 | return "repeat() rules:" + StringUtils.join(rules, ","); |
||
547 | } |
||
548 | } |
||
549 | |||
550 | public static class BreakLoopException extends RuntimeException { |
||
551 | |||
552 | } |
||
553 | |||
554 | public static class RuleBreakLoop implements Rule { |
||
555 | |||
556 | public RuleBreakLoop() {
|
||
557 | } |
||
558 | |||
559 | @Override
|
||
560 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
561 | throw new UnsupportedOperationException("Operation not suppted."); |
||
562 | } |
||
563 | |||
564 | @Override
|
||
565 | 44738 | jjdelcerro | public void parse(StatementContext context) { |
566 | context.trace(this.toString()+".parse"); |
||
567 | throw new BreakLoopException(); |
||
568 | } |
||
569 | |||
570 | @Override
|
||
571 | public String toString() { |
||
572 | return "break_loop()"; |
||
573 | } |
||
574 | } |
||
575 | |||
576 | 44750 | jjdelcerro | public static class RuleFail implements Rule { |
577 | |||
578 | public RuleFail() {
|
||
579 | } |
||
580 | |||
581 | @Override
|
||
582 | public Rule capture_as(String... ids) { |
||
583 | throw new UnsupportedOperationException("Operation not suppted."); |
||
584 | } |
||
585 | |||
586 | @Override
|
||
587 | public void parse(StatementContext context) { |
||
588 | context.trace(this.toString()+".parse"); |
||
589 | throw new ExpressionSyntaxException(); |
||
590 | } |
||
591 | |||
592 | @Override
|
||
593 | public String toString() { |
||
594 | return "fail()"; |
||
595 | } |
||
596 | } |
||
597 | |||
598 | 44533 | jjdelcerro | public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule { |
599 | 44139 | jjdelcerro | |
600 | 44750 | jjdelcerro | private String id; |
601 | 44139 | jjdelcerro | private final String separator; |
602 | |||
603 | 44750 | jjdelcerro | public RuleOptionalIdentifiers(String separator) { |
604 | 44533 | jjdelcerro | super();
|
605 | 44139 | jjdelcerro | this.separator = separator;
|
606 | } |
||
607 | |||
608 | 44379 | jjdelcerro | @Override
|
609 | 44750 | jjdelcerro | public ConditionalRule capture_as(String... ids) { |
610 | this.id = ids[0]; |
||
611 | return this; |
||
612 | } |
||
613 | |||
614 | @Override
|
||
615 | 44139 | jjdelcerro | public void parse(StatementContext context) { |
616 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
617 | 44139 | jjdelcerro | BaseCodes args = (BaseCodes) context.getCodeBuilder().args(); |
618 | Token token = context.look_token(); |
||
619 | while (token.getType() == Token.IDENTIFIER) {
|
||
620 | String identifier = (String) token.getLiteral(); |
||
621 | 44384 | jjdelcerro | if( context.isReservedWord(identifier) ) {
|
622 | break;
|
||
623 | } |
||
624 | 44139 | jjdelcerro | Code code = context.getCodeBuilder().constant(identifier); |
625 | args.add(code); |
||
626 | context.next_token(); |
||
627 | token = context.look_token(); |
||
628 | if (!token.is(this.separator)) { |
||
629 | break;
|
||
630 | } |
||
631 | context.next_token(); |
||
632 | token = context.look_token(); |
||
633 | } |
||
634 | if (args.size() != 0) { |
||
635 | 44750 | jjdelcerro | if( this.id!=null ) { |
636 | 44533 | jjdelcerro | Code code = context.getCodeBuilder().function(FUNCTION_LIST, args); |
637 | context.setCode(id, code); |
||
638 | 44750 | jjdelcerro | } |
639 | this.parseOnTrueRules(context);
|
||
640 | 44533 | jjdelcerro | } else {
|
641 | this.parseOnFalseRules(context);
|
||
642 | 44139 | jjdelcerro | } |
643 | } |
||
644 | |||
645 | @Override
|
||
646 | public String toString() { |
||
647 | return "optional_identifiers('" + id + "', '" + this.separator + "')"; |
||
648 | } |
||
649 | } |
||
650 | |||
651 | 44740 | jjdelcerro | public class RuleRequireIdentifiers implements Rule { |
652 | |||
653 | 44750 | jjdelcerro | private String id; |
654 | 44740 | jjdelcerro | private final String separator; |
655 | |||
656 | 44750 | jjdelcerro | public RuleRequireIdentifiers(String separator) { |
657 | 44740 | jjdelcerro | super();
|
658 | this.separator = separator;
|
||
659 | } |
||
660 | |||
661 | @Override
|
||
662 | 44750 | jjdelcerro | public Rule capture_as(String... ids) { |
663 | this.id = ids[0]; |
||
664 | return this; |
||
665 | } |
||
666 | |||
667 | @Override
|
||
668 | 44740 | jjdelcerro | public void parse(StatementContext context) { |
669 | context.trace(this.toString()+".parse"); |
||
670 | BaseCodes args = (BaseCodes) context.getCodeBuilder().args(); |
||
671 | Token token = context.look_token(); |
||
672 | while (token.getType() == Token.IDENTIFIER) {
|
||
673 | String identifier = (String) token.getLiteral(); |
||
674 | if( context.isReservedWord(identifier) ) {
|
||
675 | break;
|
||
676 | } |
||
677 | 44769 | jjdelcerro | Code code = context.getCodeBuilder().identifier(identifier); |
678 | 44740 | jjdelcerro | args.add(code); |
679 | context.next_token(); |
||
680 | token = context.look_token(); |
||
681 | if (!token.is(this.separator)) { |
||
682 | break;
|
||
683 | } |
||
684 | context.next_token(); |
||
685 | token = context.look_token(); |
||
686 | } |
||
687 | if (args.size() == 0) { |
||
688 | throw new ExpressionSyntaxException( |
||
689 | I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()), |
||
690 | context.getLexicalAnalyzer() |
||
691 | ); |
||
692 | } |
||
693 | 44750 | jjdelcerro | if( this.id!=null ) { |
694 | 44769 | jjdelcerro | Code code = context.getCodeBuilder().function(FUNCTION_TUPLE, args); |
695 | 44750 | jjdelcerro | context.setCode(id, code); |
696 | } |
||
697 | 44740 | jjdelcerro | } |
698 | |||
699 | @Override
|
||
700 | public String toString() { |
||
701 | return "require_identifiers('" + id + "', '" + this.separator + "')"; |
||
702 | } |
||
703 | } |
||
704 | |||
705 | 44533 | jjdelcerro | public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule { |
706 | |||
707 | 44750 | jjdelcerro | private String id; |
708 | 44533 | jjdelcerro | |
709 | 44750 | jjdelcerro | public RuleOptionalLiteralString() {
|
710 | 44533 | jjdelcerro | super();
|
711 | } |
||
712 | |||
713 | @Override
|
||
714 | 44750 | jjdelcerro | public ConditionalRule capture_as(String... ids) { |
715 | this.id = ids[0]; |
||
716 | return this; |
||
717 | } |
||
718 | |||
719 | @Override
|
||
720 | 44533 | jjdelcerro | public void parse(StatementContext context) { |
721 | 44738 | jjdelcerro | context.trace(this.toString()+".parse"); |
722 | 44533 | jjdelcerro | Token token = context.look_token(); |
723 | if (token.getType() == Token.STRING_LITERAL) {
|
||
724 | 44750 | jjdelcerro | if( this.id!=null ) { |
725 | String s = (String) token.getValue(); |
||
726 | Code code = context.getCodeBuilder().constant(s); |
||
727 | context.setCode(id, code); |
||
728 | context.next_token(); |
||
729 | } |
||
730 | 44533 | jjdelcerro | this.parseOnTrueRules(context);
|
731 | } else {
|
||
732 | this.parseOnFalseRules(context);
|
||
733 | } |
||
734 | } |
||
735 | |||
736 | @Override
|
||
737 | public String toString() { |
||
738 | return "optional_literal_string('" + id + "')"; |
||
739 | } |
||
740 | } |
||
741 | |||
742 | 44384 | jjdelcerro | public static class ArgsBuilderFromNames implements ArgsBuilder { |
743 | 44139 | jjdelcerro | |
744 | 44738 | jjdelcerro | protected final String[] argNames; |
745 | 44139 | jjdelcerro | |
746 | 44384 | jjdelcerro | public ArgsBuilderFromNames(String... argNames) { |
747 | 44139 | jjdelcerro | this.argNames = argNames;
|
748 | } |
||
749 | |||
750 | 44379 | jjdelcerro | @Override
|
751 | 44738 | jjdelcerro | public String toString() { |
752 | return "args_names("+StringUtils.join(argNames,",")+")"; |
||
753 | } |
||
754 | |||
755 | @Override
|
||
756 | 44139 | jjdelcerro | public Codes build(StatementContext context) {
|
757 | 44738 | jjdelcerro | context.trace(this.toString()+".build"); |
758 | 44139 | jjdelcerro | BaseCodes args = (BaseCodes) context.getCodeBuilder().args(); |
759 | for (String argName : argNames) { |
||
760 | if (argName.contains("#")) { |
||
761 | 45132 | jjdelcerro | Code code = context.getCode(argName); |
762 | if (code == null) { |
||
763 | int n = 1; |
||
764 | while (true) { |
||
765 | String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1); |
||
766 | code = context.getCode(argNameX); |
||
767 | if (code == null) { |
||
768 | break;
|
||
769 | } |
||
770 | args.add(code); |
||
771 | n++; |
||
772 | 44139 | jjdelcerro | } |
773 | 45132 | jjdelcerro | } else {
|
774 | 44750 | jjdelcerro | args.add(code); |
775 | 44139 | jjdelcerro | } |
776 | } else {
|
||
777 | Code code = context.getCode(argName); |
||
778 | 44592 | jjdelcerro | // if( code == null) {
|
779 | // code = context.getCodeBuilder().constant(null);
|
||
780 | // }
|
||
781 | 44750 | jjdelcerro | args.add(code); |
782 | 44139 | jjdelcerro | } |
783 | } |
||
784 | return args;
|
||
785 | } |
||
786 | } |
||
787 | |||
788 | 44750 | jjdelcerro | public static class FixedArgsBuilderFromNames implements ArgsBuilder { |
789 | |||
790 | protected final String[] argNames; |
||
791 | |||
792 | public FixedArgsBuilderFromNames(String... argNames) { |
||
793 | this.argNames = argNames;
|
||
794 | } |
||
795 | |||
796 | @Override
|
||
797 | public String toString() { |
||
798 | return "fixed_args_names("+StringUtils.join(argNames,",")+")"; |
||
799 | } |
||
800 | |||
801 | @Override
|
||
802 | public Codes build(StatementContext context) {
|
||
803 | context.trace(this.toString()+".build"); |
||
804 | CodeBuilder codeBuilder = context.getCodeBuilder(); |
||
805 | BaseCodes args = (BaseCodes) codeBuilder.args(); |
||
806 | for (String argName : argNames) { |
||
807 | if (argName.contains("#")) { |
||
808 | int n = 1; |
||
809 | BaseCodes argsX = (BaseCodes) codeBuilder.args(); |
||
810 | while (true) { |
||
811 | String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1); |
||
812 | Code code = context.getCode(argNameX); |
||
813 | if (code == null) { |
||
814 | break;
|
||
815 | } |
||
816 | argsX.add(code); |
||
817 | n++; |
||
818 | } |
||
819 | |||
820 | args.add(codeBuilder.tuple(argsX)); |
||
821 | } else {
|
||
822 | Code code = context.getCode(argName); |
||
823 | if( code == null) { |
||
824 | code = context.getCodeBuilder().constant(null);
|
||
825 | } |
||
826 | args.add(code); |
||
827 | } |
||
828 | } |
||
829 | return args;
|
||
830 | } |
||
831 | } |
||
832 | |||
833 | 44384 | jjdelcerro | public static class ArgsBuilderExpand extends ArgsBuilderFromNames { |
834 | 44139 | jjdelcerro | |
835 | 44384 | jjdelcerro | public ArgsBuilderExpand(String... argNames) { |
836 | 44139 | jjdelcerro | super(argNames);
|
837 | } |
||
838 | |||
839 | 44379 | jjdelcerro | @Override
|
840 | 44738 | jjdelcerro | public String toString() { |
841 | return "args_expand("+StringUtils.join(argNames,",")+")"; |
||
842 | } |
||
843 | |||
844 | @Override
|
||
845 | 44139 | jjdelcerro | public Codes build(StatementContext context) {
|
846 | BaseCodes args = (BaseCodes) context.getCodeBuilder().args(); |
||
847 | |||
848 | Codes base_args = super.build(context);
|
||
849 | for (Code arg : base_args) {
|
||
850 | 44752 | jjdelcerro | if( arg.code() == Code.CALLABLE &&
|
851 | ((Callable)arg).name().equals(CodeBlockFunction.NAME) ) {
|
||
852 | Codes block_args = ((Callable)arg).parameters();
|
||
853 | 44139 | jjdelcerro | for (Code block_arg : block_args) {
|
854 | args.add(block_arg); |
||
855 | } |
||
856 | } else {
|
||
857 | args.add(arg); |
||
858 | } |
||
859 | } |
||
860 | return args;
|
||
861 | } |
||
862 | } |
||
863 | |||
864 | 44384 | jjdelcerro | public static class StatementBuilderBase implements StatementBuilder { |
865 | protected ArgsBuilder argsBuilder;
|
||
866 | protected String codeID; |
||
867 | |||
868 | public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) { |
||
869 | this.codeID = codeID;
|
||
870 | this.argsBuilder = argsBuilder;
|
||
871 | } |
||
872 | |||
873 | @Override
|
||
874 | public String getCodeID() { |
||
875 | return this.codeID; |
||
876 | } |
||
877 | |||
878 | @Override
|
||
879 | public ArgsBuilder getArgsBuilder() {
|
||
880 | return this.argsBuilder; |
||
881 | } |
||
882 | |||
883 | @Override
|
||
884 | public Code build(StatementContext context) {
|
||
885 | Codes args = this.getArgsBuilder().build(context);
|
||
886 | Code code = null;
|
||
887 | if (this.getCodeID() == null) { |
||
888 | code = args.get(0);
|
||
889 | } else {
|
||
890 | if (args.size() == 0) { |
||
891 | code = context.getCodeBuilder().function(this.getCodeID(), null); |
||
892 | } else {
|
||
893 | // Si es un bloque dentro de otro, dejamos solo uno.
|
||
894 | if( args.size()==1 && |
||
895 | StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,this.getCodeID()) ) {
|
||
896 | Code code0 = args.get(0);
|
||
897 | 44752 | jjdelcerro | if( code0.code() == Code.CALLABLE &&
|
898 | StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Callable)code0).name())
|
||
899 | 44384 | jjdelcerro | ) { |
900 | code = code0; |
||
901 | } |
||
902 | } |
||
903 | if( code == null ) { |
||
904 | code = context.getCodeBuilder().function(this.getCodeID(), args);
|
||
905 | } |
||
906 | } |
||
907 | } |
||
908 | return code;
|
||
909 | } |
||
910 | } |
||
911 | |||
912 | 44139 | jjdelcerro | public DefaultStatement(String name) { |
913 | this.rules = new ArrayList<>(); |
||
914 | 44384 | jjdelcerro | this.stmtBuilder = null; |
915 | 44139 | jjdelcerro | this.name = name;
|
916 | } |
||
917 | |||
918 | 44379 | jjdelcerro | @Override
|
919 | 44139 | jjdelcerro | public String getName() { |
920 | return name;
|
||
921 | } |
||
922 | |||
923 | @Override
|
||
924 | 44144 | jjdelcerro | public Rule require_any_token(String... token) { |
925 | return new RuleRequireAnyToken(token); |
||
926 | 44139 | jjdelcerro | } |
927 | |||
928 | @Override
|
||
929 | 44750 | jjdelcerro | public Rule require_identifier() {
|
930 | return new RuleRequireIdentifier(); |
||
931 | 44139 | jjdelcerro | } |
932 | |||
933 | @Override
|
||
934 | 44750 | jjdelcerro | public Rule require_identifiers(String sep) { |
935 | return new RuleRequireIdentifiers(sep); |
||
936 | 44740 | jjdelcerro | } |
937 | |||
938 | @Override
|
||
939 | 44750 | jjdelcerro | public Rule require_literal_string() {
|
940 | return new RuleRequireLiteralString(); |
||
941 | 44533 | jjdelcerro | } |
942 | |||
943 | @Override
|
||
944 | 44379 | jjdelcerro | public Rule set_expression(String id, Object value) { |
945 | return new RuleSetExpression(id, value); |
||
946 | } |
||
947 | |||
948 | @Override
|
||
949 | 44750 | jjdelcerro | public Rule require_expression() {
|
950 | 45153 | jjdelcerro | return this.require_expression(true); |
951 | 44139 | jjdelcerro | } |
952 | |||
953 | @Override
|
||
954 | 45153 | jjdelcerro | public Rule require_expression(boolean allow_assignement) { |
955 | return new RuleRequireExpression(allow_assignement); |
||
956 | } |
||
957 | |||
958 | @Override
|
||
959 | 44750 | jjdelcerro | public Rule require_expressions(String separator) { |
960 | return new RuleRequiereExpressions(separator); |
||
961 | 44139 | jjdelcerro | } |
962 | |||
963 | @Override
|
||
964 | 44144 | jjdelcerro | public ConditionalRule optional_any_token(String... id) { |
965 | return new RuleOptionalAnyToken(id); |
||
966 | 44139 | jjdelcerro | } |
967 | |||
968 | @Override
|
||
969 | 44750 | jjdelcerro | public ConditionalRule optional_identifiers(String separator) { |
970 | return new RuleOptionalIdentifiers(separator); |
||
971 | 44139 | jjdelcerro | } |
972 | |||
973 | @Override
|
||
974 | 44750 | jjdelcerro | public ConditionalRule optional_literal_string() {
|
975 | return new RuleOptionalLiteralString(); |
||
976 | 44533 | jjdelcerro | } |
977 | |||
978 | @Override
|
||
979 | 44144 | jjdelcerro | public CompoundRule repeat_until_any_tokens(String... tokens) { |
980 | return new RuleRepeatUntilAnyTokens(tokens); |
||
981 | 44139 | jjdelcerro | } |
982 | |||
983 | @Override
|
||
984 | public Statement addRule(Rule rule) { |
||
985 | this.rules.add(rule);
|
||
986 | return this; |
||
987 | } |
||
988 | |||
989 | @Override
|
||
990 | public boolean isApplicable(StatementContext context) { |
||
991 | if (this.rules.isEmpty()) { |
||
992 | return false; |
||
993 | } |
||
994 | 44738 | jjdelcerro | context.trace(this.getName()+".isApplicable"); |
995 | 44750 | jjdelcerro | context.save_state(); |
996 | 44738 | jjdelcerro | try {
|
997 | for (Rule rule : rules) {
|
||
998 | 44750 | jjdelcerro | if( rule == null ) { |
999 | continue;
|
||
1000 | 44738 | jjdelcerro | } |
1001 | 44750 | jjdelcerro | if (rule instanceof IsApplicableRule) { |
1002 | if( !((IsApplicableRule) rule).isApplicable(context) ) {
|
||
1003 | context.trace(this.getName()+".isApplicable return false"); |
||
1004 | return false; |
||
1005 | } |
||
1006 | } else {
|
||
1007 | rule.parse(context); |
||
1008 | 44738 | jjdelcerro | } |
1009 | } |
||
1010 | 44750 | jjdelcerro | context.trace(this.getName()+".isApplicable return true"); |
1011 | return true; |
||
1012 | } catch(Exception ex) { |
||
1013 | context.trace(this.getName()+".isApplicable return false (error)"); |
||
1014 | return false; |
||
1015 | 44738 | jjdelcerro | } finally {
|
1016 | 44750 | jjdelcerro | context.restore_state(); |
1017 | 44139 | jjdelcerro | } |
1018 | } |
||
1019 | |||
1020 | @Override
|
||
1021 | public ArgsBuilder args_names(String... args) { |
||
1022 | ArgsBuilder x = new ArgsBuilderFromNames(args);
|
||
1023 | return x;
|
||
1024 | } |
||
1025 | |||
1026 | @Override
|
||
1027 | 44750 | jjdelcerro | public ArgsBuilder fixed_args_names(String... args) { |
1028 | ArgsBuilder x = new FixedArgsBuilderFromNames(args);
|
||
1029 | return x;
|
||
1030 | } |
||
1031 | |||
1032 | @Override
|
||
1033 | 44139 | jjdelcerro | public ArgsBuilder args_expand(String... args) { |
1034 | ArgsBuilder x = new ArgsBuilderExpand(args);
|
||
1035 | return x;
|
||
1036 | } |
||
1037 | |||
1038 | @Override
|
||
1039 | 44384 | jjdelcerro | public void code(final String id, final ArgsBuilder argsBuilder) { |
1040 | this.builder(new StatementBuilderBase(id, argsBuilder)); |
||
1041 | 44139 | jjdelcerro | } |
1042 | |||
1043 | 44738 | jjdelcerro | @Override
|
1044 | 44384 | jjdelcerro | public void builder(StatementBuilder builder) { |
1045 | this.stmtBuilder = builder;
|
||
1046 | } |
||
1047 | |||
1048 | 44139 | jjdelcerro | @Override
|
1049 | public Code parse(StatementContext context) {
|
||
1050 | 44738 | jjdelcerro | context.trace(this.getName()+".parse"); |
1051 | 44139 | jjdelcerro | for (Rule rule : rules) {
|
1052 | rule.parse(context); |
||
1053 | } |
||
1054 | 44384 | jjdelcerro | Code code = this.stmtBuilder.build(context);
|
1055 | 44738 | jjdelcerro | context.trace(this.getName()+".return "+code); |
1056 | 44139 | jjdelcerro | return code;
|
1057 | } |
||
1058 | |||
1059 | @Override
|
||
1060 | public String toString() { |
||
1061 | return this.getName() + " " + StringUtils.join(this.rules, ";"); |
||
1062 | |||
1063 | } |
||
1064 | 44738 | jjdelcerro | |
1065 | @Override
|
||
1066 | public CompoundRule repeat() {
|
||
1067 | return new RuleRepeat(); |
||
1068 | } |
||
1069 | |||
1070 | @Override
|
||
1071 | 44750 | jjdelcerro | public Rule fail() {
|
1072 | return new RuleFail(); |
||
1073 | } |
||
1074 | |||
1075 | @Override
|
||
1076 | 44738 | jjdelcerro | public Rule break_loop() {
|
1077 | return new RuleBreakLoop(); |
||
1078 | } |
||
1079 | |||
1080 | @Override
|
||
1081 | public SwichTokenRule switch_token() {
|
||
1082 | return new RuleSwitchToken(); |
||
1083 | } |
||
1084 | |||
1085 | 44139 | jjdelcerro | } |