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 @ 44750

History | View | Annotate | Download (32 KB)

1
package org.gvsig.expressionevaluator.impl;
2

    
3
import java.util.ArrayList;
4
import java.util.List;
5
import java.util.Objects;
6
import org.apache.commons.lang3.ArrayUtils;
7
import org.apache.commons.lang3.StringUtils;
8
import org.apache.commons.lang3.tuple.ImmutablePair;
9
import org.apache.commons.lang3.tuple.Pair;
10
import org.gvsig.expressionevaluator.Code;
11
import org.gvsig.expressionevaluator.Code.Caller;
12
import org.gvsig.expressionevaluator.CodeBuilder;
13
import org.gvsig.expressionevaluator.Codes;
14
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_LIST;
15
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
    private StatementBuilder stmtBuilder;
34
//    private String codeId;
35
//    private ArgsBuilder argsBuilder;
36

    
37
    public interface IsApplicableRule extends Rule {
38
      public boolean isApplicable(StatementContext context);
39
    }
40
    
41
    public interface RepeatRule extends CompoundRule {
42

    
43
        public String getClassifier();
44
    }
45

    
46
    public class RuleRequireAnyToken implements IsApplicableRule {
47

    
48
        private final String[] required_token;
49
        private String id;
50

    
51
        public RuleRequireAnyToken(String... required_token) {
52
            this.required_token = required_token;
53
        }
54
        
55
        @Override
56
        public RuleRequireAnyToken capture_as(String... ids) {
57
          this.id = ids[0];
58
          return this;
59
        }
60

    
61
        @Override
62
        public void parse(StatementContext context) {
63
            context.trace(this.toString()+".parse");
64
            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
                                StringUtils.join(this.required_token,", "),
69
                                token.getLiteral()
70
                        ),
71
                        context.getLexicalAnalyzer()
72
                );
73
            }
74
            if( this.id != null ) {
75
              Code code = context.getCodeBuilder().constant(token.getValue());
76
              context.setCode(id, code);
77
            }
78
            context.next_token();
79
        }
80

    
81
        @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
        }
88

    
89
        @Override
90
        public String toString() {
91
            return "require_token(" + StringUtils.join(this.required_token) + ")";
92
        }
93

    
94
    }
95

    
96
    public class RuleRequireIdentifier implements IsApplicableRule {
97

    
98
        private String id;
99

    
100
        public RuleRequireIdentifier() {
101
        }
102

    
103
        @Override
104
        public Rule capture_as(String... ids) {
105
          this.id = ids[0];
106
          return this;
107
        }
108

    
109
        @Override
110
        public void parse(StatementContext context) {
111
            context.trace(this.toString()+".parse");
112
            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
            if( this.id!=null ) {
120
              String identifier = (String) token.getLiteral();
121
              Code code = context.getCodeBuilder().constant(identifier);
122
              context.setCode(id, code);
123
            }
124
            context.next_token();
125
        }
126

    
127
        @Override
128
        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
        public String toString() {
137
            return "require_identifier('" + this.id + "')";
138
        }
139
    }
140

    
141
    public class RuleRequireLiteralString implements Rule {
142

    
143
        private String id;
144

    
145
        public RuleRequireLiteralString() {
146
        }
147

    
148
        @Override
149
        public Rule capture_as(String... ids) {
150
          this.id = ids[0];
151
          return this;
152
        }
153

    
154
        @Override
155
        public void parse(StatementContext context) {
156
            context.trace(this.toString()+".parse");
157
            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
            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
        }
171

    
172
        @Override
173
        public String toString() {
174
            return "require_literal_string('" + this.id + "')";
175
        }
176
    }
177

    
178
    public class RuleRequireExpression implements Rule {
179

    
180
        private String id;
181

    
182
        public RuleRequireExpression() {
183
        }
184

    
185
        @Override
186
        public Rule capture_as(String... ids) {
187
          this.id = ids[0];
188
          return this;
189
        }
190

    
191
        @Override
192
        public void parse(StatementContext context) {
193
            context.trace(this.toString()+".parse");
194
            Code code = context.parse_expression();
195
            if (code == null) {
196
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
197
            }
198
            if( this.id!=null ) {
199
              context.setCode(id, code);
200
            }
201
        }
202

    
203
        @Override
204
        public String toString() {
205
            return "require_expression('" + this.id + "')";
206
        }
207
    }
208

    
209

    
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
        public Rule capture_as(String... ids) {
222
          throw new UnsupportedOperationException("Unsupported operation.");
223
        }
224

    
225
        @Override
226
        public void parse(StatementContext context) {
227
            context.trace(this.toString()+".parse");
228
            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
    public class RuleRequiereExpressions implements Rule {
242

    
243
        private String id;
244
        private final String separator;
245

    
246
        public RuleRequiereExpressions(String separator) {
247
            this.separator = separator;
248
        }
249

    
250
        @Override
251
        public Rule capture_as(String... ids) {
252
          this.id = ids[0];
253
          return this;
254
        }
255
        
256
        @Override
257
        public void parse(StatementContext context) {
258
            context.trace(this.toString()+".parse");
259
            Codes codes = context.parse_expressions(this.separator);
260
            if (codes == null) {
261
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
262
            }
263
            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
            }
272
        }
273

    
274
        @Override
275
        public String toString() {
276
            return "require_expressions('" + this.id + "', '" + this.separator + "')";
277
        }
278
    }
279

    
280
    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
        @Override
291
        public ConditionalRule capture_as(String... ids) {
292
          throw new UnsupportedOperationException("Operation not suppted.");
293
        }
294

    
295
        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
    public class RuleOptionalAnyToken implements ConditionalRule {
322

    
323
        private final String[] optional_token;
324
        private final List<Rule> onTrueRules;
325
        private final List<Rule> onFalseRules;
326
        private String id;
327

    
328
        public RuleOptionalAnyToken(String... optional_token) {
329
            this.optional_token = optional_token;
330
            this.onTrueRules = new ArrayList<>();
331
            this.onFalseRules = new ArrayList<>();
332
        }
333

    
334
        @Override
335
        public ConditionalRule capture_as(String... ids) {
336
          this.id = ids[0];
337
          return this;
338
        }
339
        
340
        @Override
341
        public void parse(StatementContext context) {
342
            context.trace(this.toString()+".parse");
343
            Token token = context.look_token();
344
            if (token.is(this.optional_token)) {
345
                if( this.id!=null ) {
346
                  Code code = context.getCodeBuilder().constant(token.getValue());
347
                  context.setCode(id, code);
348
                }
349
                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
        @Override
361
        public RuleOptionalAnyToken addRuleOnTrue(Rule rule) {
362
            this.onTrueRules.add(rule);
363
            return this;
364
        }
365

    
366
        @Override
367
        public RuleOptionalAnyToken addRuleOnFalse(Rule rule) {
368
            this.onFalseRules.add(rule);
369
            return this;
370
        }
371

    
372
        @Override
373
        public String toString() {
374
            return "optional_token(" + StringUtils.join(this.optional_token) + ") onTrue:" + StringUtils.join(onTrueRules, ",")+", onFalse:" + StringUtils.join(onFalseRules, ",");
375
        }
376
    }
377

    
378
    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
        public Rule capture_as(String... ids) {
389
          throw new UnsupportedOperationException("Unsupported operation.");
390
        }
391

    
392
        @Override
393
        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
    public class RuleRepeatUntilAnyTokens implements RepeatRule {
431

    
432
        private final String[] exit_tokens;
433
        private final List<Rule> rules;
434
        private int counter;
435

    
436
        public RuleRepeatUntilAnyTokens(String[] exit_tokens) {
437
            this.exit_tokens = exit_tokens;
438
            this.rules = new ArrayList<>();
439
        }
440

    
441
        @Override
442
        public Rule capture_as(String... ids) {
443
          throw new UnsupportedOperationException("Operation not suppted.");
444
        }
445
        
446
        @Override
447
        public void parse(StatementContext context) {
448
            context.trace(this.toString()+".parse");
449
            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
        @Override
469
        public RuleRepeatUntilAnyTokens addRule(Rule rule) {
470
            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
    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
        
495
        @Override
496
        public Rule capture_as(String... ids) {
497
          throw new UnsupportedOperationException("Operation not suppted.");
498
        }
499
        
500
        @Override
501
        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
        public Rule capture_as(String... ids) {
553
          throw new UnsupportedOperationException("Operation not suppted.");
554
        }
555

    
556
        @Override
557
        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
        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
    public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule {
591

    
592
        private String id;
593
        private final String separator;
594

    
595
        public RuleOptionalIdentifiers(String separator) {
596
            super();
597
            this.separator = separator;
598
        }
599

    
600
        @Override
601
        public ConditionalRule capture_as(String... ids) {
602
          this.id = ids[0];
603
          return this;
604
        }
605

    
606
        @Override
607
        public void parse(StatementContext context) {
608
            context.trace(this.toString()+".parse");
609
            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
                if( context.isReservedWord(identifier) ) {
614
                    break;
615
                }
616
                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
              if( this.id!=null ) {
628
                Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
629
                context.setCode(id, code);
630
              }
631
              this.parseOnTrueRules(context);
632
            } else {
633
                this.parseOnFalseRules(context);
634
            }
635
        }
636

    
637
        @Override
638
        public String toString() {
639
            return "optional_identifiers('" + id + "', '" + this.separator + "')";
640
        }
641
    }
642

    
643
    public class RuleRequireIdentifiers implements Rule {
644

    
645
        private String id;
646
        private final String separator;
647

    
648
        public RuleRequireIdentifiers(String separator) {
649
            super();
650
            this.separator = separator;
651
        }
652

    
653
        @Override
654
        public Rule capture_as(String... ids) {
655
          this.id = ids[0];
656
          return this;
657
        }
658

    
659
        @Override
660
        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
            if( this.id!=null ) {
686
              Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
687
              context.setCode(id, code);
688
            }
689
        }
690

    
691
        @Override
692
        public String toString() {
693
            return "require_identifiers('" + id + "', '" + this.separator + "')";
694
        }
695
    }
696

    
697
    public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule {
698

    
699
        private String id;
700

    
701
        public RuleOptionalLiteralString() {
702
            super();
703
        }
704

    
705
        @Override
706
        public ConditionalRule capture_as(String... ids) {
707
          this.id = ids[0];
708
          return this;
709
        }
710
        
711
        @Override
712
        public void parse(StatementContext context) {
713
            context.trace(this.toString()+".parse");
714
            Token token = context.look_token();
715
            if (token.getType() == Token.STRING_LITERAL) {
716
                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
                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
    public static class ArgsBuilderFromNames implements ArgsBuilder {
735

    
736
        protected final String[] argNames;
737

    
738
        public ArgsBuilderFromNames(String... argNames) {
739
            this.argNames = argNames;
740
        }
741

    
742
        @Override
743
        public String toString() {
744
          return "args_names("+StringUtils.join(argNames,",")+")";
745
        }
746
        
747
        @Override
748
        public Codes build(StatementContext context) {
749
            context.trace(this.toString()+".build");
750
            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
                        args.add(code);
761
                        n++;
762
                    }
763
                } else {
764
                    Code code = context.getCode(argName);
765
//                    if( code == null) {
766
//                        code = context.getCodeBuilder().constant(null);
767
//                    }
768
                    args.add(code);
769
                }
770
            }
771
            return args;
772
        }
773
    }
774

    
775
    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
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
821

    
822
        public ArgsBuilderExpand(String... argNames) {
823
            super(argNames);
824
        }
825

    
826
        @Override
827
        public String toString() {
828
          return "args_expand("+StringUtils.join(argNames,",")+")";
829
        }
830
        
831
        @Override
832
        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
                    Codes block_args = ((Caller)arg).parameters();
840
                    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
    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
    public DefaultStatement(String name) {
900
        this.rules = new ArrayList<>();
901
        this.stmtBuilder = null;
902
        this.name = name;
903
    }
904

    
905
    @Override
906
    public String getName() {
907
        return name;
908
    }
909

    
910
    @Override
911
    public Rule require_any_token(String... token) {
912
        return new RuleRequireAnyToken(token);
913
    }
914

    
915
    @Override
916
    public Rule require_identifier() {
917
        return new RuleRequireIdentifier();
918
    }
919

    
920
    @Override
921
    public Rule require_identifiers(String sep) {
922
        return new RuleRequireIdentifiers(sep);
923
    }
924

    
925
    @Override
926
    public Rule require_literal_string() {
927
        return new RuleRequireLiteralString();
928
    }
929

    
930
    @Override
931
    public Rule set_expression(String id, Object value) {
932
        return new RuleSetExpression(id, value);
933
    }
934

    
935
    @Override
936
    public Rule require_expression() {
937
        return new RuleRequireExpression();
938
    }
939

    
940
    @Override
941
    public Rule require_expressions(String separator) {
942
        return new RuleRequiereExpressions(separator);
943
    }
944

    
945
    @Override
946
    public ConditionalRule optional_any_token(String... id) {
947
        return new RuleOptionalAnyToken(id);
948
    }
949

    
950
    @Override
951
    public ConditionalRule optional_identifiers(String separator) {
952
        return new RuleOptionalIdentifiers(separator);
953
    }
954

    
955
    @Override
956
    public ConditionalRule optional_literal_string() {
957
        return new RuleOptionalLiteralString();
958
    }
959

    
960
    @Override
961
    public CompoundRule repeat_until_any_tokens(String... tokens) {
962
        return new RuleRepeatUntilAnyTokens(tokens);
963
    }
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
        context.trace(this.getName()+".isApplicable");
977
        context.save_state();
978
        try {
979
          for (Rule rule : rules) {
980
            if( rule == null ) {
981
              continue;
982
            }
983
            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
            }
991
          }
992
          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
        } finally {
998
          context.restore_state();
999
        }
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
    public ArgsBuilder fixed_args_names(String... args) {
1010
        ArgsBuilder x = new FixedArgsBuilderFromNames(args);
1011
        return x;
1012
    }
1013
    
1014
    @Override
1015
    public ArgsBuilder args_expand(String... args) {
1016
        ArgsBuilder x = new ArgsBuilderExpand(args);
1017
        return x;
1018
    }
1019
    
1020
    @Override
1021
    public void code(final String id, final ArgsBuilder argsBuilder) {
1022
        this.builder(new StatementBuilderBase(id, argsBuilder));
1023
    }
1024

    
1025
    @Override
1026
    public void builder(StatementBuilder builder) {
1027
        this.stmtBuilder = builder;
1028
    }
1029
    
1030
    @Override
1031
    public Code parse(StatementContext context) {
1032
        context.trace(this.getName()+".parse");
1033
        for (Rule rule : rules) {
1034
            rule.parse(context);
1035
        }
1036
        Code code = this.stmtBuilder.build(context);
1037
        context.trace(this.getName()+".return "+code);
1038
        return code;
1039
    }
1040

    
1041
    @Override
1042
    public String toString() {
1043
        return this.getName() + " " + StringUtils.join(this.rules, ";");
1044

    
1045
    }
1046

    
1047
    @Override
1048
    public CompoundRule repeat() {
1049
      return new RuleRepeat();
1050
    }
1051

    
1052
    @Override
1053
    public Rule fail() {
1054
      return new RuleFail();
1055
    }
1056

    
1057
    @Override
1058
    public Rule break_loop() {
1059
      return new RuleBreakLoop();
1060
    }
1061
    
1062
    @Override
1063
    public SwichTokenRule switch_token() {
1064
      return new RuleSwitchToken();
1065
    }
1066

    
1067
}