Statistics
| Revision:

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
}