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

History | View | Annotate | Download (34.5 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.CodeBuilder;
12
import org.gvsig.expressionevaluator.Codes;
13
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_LIST;
14
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
import org.gvsig.expressionevaluator.Code.Callable;
24
import org.gvsig.expressionevaluator.ExpressionBuilder;
25
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_TUPLE;
26

    
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
    private StatementBuilder stmtBuilder;
36
//    private String codeId;
37
//    private ArgsBuilder argsBuilder;
38

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

    
45
        public String getClassifier();
46
    }
47

    
48
    public class RuleRequireAnyToken implements IsApplicableRule {
49

    
50
        private final String[] required_token;
51
        private String id;
52

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

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

    
83
        @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
        }
90

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

    
96
    }
97

    
98
    public class RuleRequireTokens implements Rule {
99

    
100
        private final String[] required_tokens;
101
        private String id;
102

    
103
        public RuleRequireTokens(String... required_token) {
104
            this.required_tokens = required_token;
105
        }
106
        
107
        @Override
108
        public RuleRequireTokens capture_as(String... ids) {
109
          this.id = ids[0];
110
          return this;
111
        }
112

    
113
        @Override
114
        public void parse(StatementContext context) {
115
            context.trace(this.toString()+".parse");
116
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
117
            Token token = context.look_token();
118
            
119
            for (String required_token : this.required_tokens) {
120
                String token_literal = (String) token.getLiteral();
121
                if( !StringUtils.equals(required_token, token_literal) ) {
122
                    throw new ExpressionSyntaxException(
123
                            I18N.An_identifier_was_expected_and_XliteralX_was_found(token_literal),
124
                            context.getLexicalAnalyzer()
125
                    );
126
                }
127
                context.next_token();
128
                token = context.look_token();
129
            }
130
            if( this.id!=null ) {
131
              Code code = context.getCodeBuilder().constant(true);
132
              context.setCode(id, code);
133
            }
134
        }
135

    
136
        @Override
137
        public String toString() {
138
            return "require_tokens(" + StringUtils.join(this.required_tokens) + ")";
139
        }
140

    
141
    }
142

    
143
    public class RuleRequireIdentifier implements IsApplicableRule {
144

    
145
        private String id;
146

    
147
        public RuleRequireIdentifier() {
148
        }
149

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

    
156
        @Override
157
        public void parse(StatementContext context) {
158
            context.trace(this.toString()+".parse");
159
            Token token = context.look_token();
160
            if (token.getType() != Token.IDENTIFIER) {
161
                throw new ExpressionSyntaxException(
162
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
163
                        context.getLexicalAnalyzer()
164
                );
165
            }
166
            if( this.id!=null ) {
167
              String identifier = (String) token.getLiteral();
168
              Code code = context.getCodeBuilder().constant(identifier);
169
              context.setCode(id, code);
170
            }
171
            context.next_token();
172
        }
173

    
174
        @Override
175
        public boolean isApplicable(StatementContext context) {
176
            Token token = context.next_token();
177
            boolean r = token.getType() == Token.IDENTIFIER;
178
            context.trace(this.toString()+".isApplicable return "+r);
179
            return r;
180
        }
181
        
182
        @Override
183
        public String toString() {
184
            return "require_identifier('" + this.id + "')";
185
        }
186
    }
187

    
188
    public class RuleRequireLiteralString implements Rule {
189

    
190
        private String id;
191

    
192
        public RuleRequireLiteralString() {
193
        }
194

    
195
        @Override
196
        public Rule capture_as(String... ids) {
197
          this.id = ids[0];
198
          return this;
199
        }
200

    
201
        @Override
202
        public void parse(StatementContext context) {
203
            context.trace(this.toString()+".parse");
204
            Token token = context.look_token();
205
            if (token.getType() != Token.STRING_LITERAL) {
206
                throw new ExpressionSyntaxException(
207
                        I18N.A_string_literal_was_expected(),
208
                        context.getLexicalAnalyzer()
209
                );
210
            }
211
            if( this.id!=null ) {
212
              String identifier = (String) token.getValue();
213
              Code code = context.getCodeBuilder().constant(identifier);
214
              context.setCode(id, code);
215
              context.next_token();
216
            }
217
        }
218

    
219
        @Override
220
        public String toString() {
221
            return "require_literal_string('" + this.id + "')";
222
        }
223
    }
224

    
225
    public class RuleRequireExpression implements Rule {
226

    
227
        private String id;
228
        boolean allow_assignement;
229

    
230
        public RuleRequireExpression(boolean allow_assignement) {
231
            this.allow_assignement = allow_assignement;
232
        }
233

    
234
        @Override
235
        public Rule capture_as(String... ids) {
236
          this.id = ids[0];
237
          return this;
238
        }
239

    
240
        @Override
241
        public void parse(StatementContext context) {
242
            context.trace(this.toString()+".parse");
243
            Code code = context.parse_expression(allow_assignement);
244
            if (code == null) {
245
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
246
            }
247
            if( this.id!=null ) {
248
              context.setCode(id, code);
249
            }
250
        }
251

    
252
        @Override
253
        public String toString() {
254
            return "require_expression('" + this.id + "')";
255
        }
256
    }
257

    
258

    
259
    public class RuleSetExpression implements Rule {
260

    
261
        private final String id;
262
        private final Object value;
263

    
264
        public RuleSetExpression(String id, Object value) {
265
            this.id = id;
266
            this.value = value;
267
        }
268

    
269
        @Override
270
        public Rule capture_as(String... ids) {
271
          throw new UnsupportedOperationException("Unsupported operation.");
272
        }
273

    
274
        @Override
275
        public void parse(StatementContext context) {
276
            context.trace(this.toString()+".parse");
277
            if( this.value instanceof Code ) {
278
                context.setCode(id, (Code) this.value);
279
            } else {
280
                context.setCode(id, context.getCodeBuilder().constant(value));
281
            }
282
        }
283

    
284
        @Override
285
        public String toString() {
286
            return "set_expression('" + this.id + "', "+Objects.toString(value)+")";
287
        }
288
    }
289

    
290
    public class RuleRequiereExpressions implements Rule {
291

    
292
        private String id;
293
        private final String separator;
294

    
295
        public RuleRequiereExpressions(String separator) {
296
            this.separator = separator;
297
        }
298

    
299
        @Override
300
        public Rule capture_as(String... ids) {
301
          this.id = ids[0];
302
          return this;
303
        }
304
        
305
        @Override
306
        public void parse(StatementContext context) {
307
            context.trace(this.toString()+".parse");
308
            Codes codes = context.parse_expressions(this.separator);
309
            if (codes == null) {
310
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
311
            }
312
            if( this.id!=null ) {
313
              Code code;
314
              if( codes.size()==1 ) {
315
                  code = codes.get(0);
316
              } else {
317
                  code = context.getCodeBuilder().function(CodeBlockFunction.NAME, codes);
318
              }
319
              context.setCode(id, code);
320
            }
321
        }
322

    
323
        @Override
324
        public String toString() {
325
            return "require_expressions('" + this.id + "', '" + this.separator + "')";
326
        }
327
    }
328

    
329
    public abstract class AbstractConditionalRule implements ConditionalRule {
330

    
331
        protected final List<Rule> onTrueRules;
332
        protected final List<Rule> onFalseRules;
333

    
334
        public AbstractConditionalRule() {
335
            this.onTrueRules = new ArrayList<>();
336
            this.onFalseRules = new ArrayList<>();
337
        }
338

    
339
        @Override
340
        public ConditionalRule capture_as(String... ids) {
341
          throw new UnsupportedOperationException("Operation not suppted.");
342
        }
343

    
344
        protected void parseOnTrueRules(StatementContext context) {
345
            for (Rule rule : this.onTrueRules) {
346
                rule.parse(context);
347
            }
348
        }
349

    
350
        protected void parseOnFalseRules(StatementContext context) {
351
            for (Rule rule : this.onFalseRules) {
352
                rule.parse(context);
353
            }
354
        }
355

    
356
        @Override
357
        public ConditionalRule addRuleOnTrue(Rule rule) {
358
            this.onTrueRules.add(rule);
359
            return this;
360
        }
361

    
362
        @Override
363
        public ConditionalRule addRuleOnFalse(Rule rule) {
364
            this.onFalseRules.add(rule);
365
            return this;
366
        }
367

    
368
    }
369

    
370
    public class RuleOptionalAnyToken implements ConditionalRule {
371

    
372
        private final String[] optional_token;
373
        private final List<Rule> onTrueRules;
374
        private final List<Rule> onFalseRules;
375
        private String id;
376

    
377
        public RuleOptionalAnyToken(String... optional_token) {
378
            this.optional_token = optional_token;
379
            this.onTrueRules = new ArrayList<>();
380
            this.onFalseRules = new ArrayList<>();
381
        }
382

    
383
        @Override
384
        public ConditionalRule capture_as(String... ids) {
385
          this.id = ids[0];
386
          return this;
387
        }
388
        
389
        @Override
390
        public void parse(StatementContext context) {
391
            context.trace(this.toString()+".parse");
392
            Token token = context.look_token();
393
            if (token.is(this.optional_token)) {
394
                if( this.id!=null ) {
395
                  Code code = context.getCodeBuilder().constant(token.getValue());
396
                  context.setCode(id, code);
397
                }
398
                context.next_token();
399
                for (Rule rule : this.onTrueRules) {
400
                    rule.parse(context);
401
                }
402
            } else {
403
                for (Rule rule : this.onFalseRules) {
404
                    rule.parse(context);
405
                }
406
            }
407
        }
408

    
409
        @Override
410
        public RuleOptionalAnyToken addRuleOnTrue(Rule rule) {
411
            this.onTrueRules.add(rule);
412
            return this;
413
        }
414

    
415
        @Override
416
        public RuleOptionalAnyToken addRuleOnFalse(Rule rule) {
417
            this.onFalseRules.add(rule);
418
            return this;
419
        }
420

    
421
        @Override
422
        public String toString() {
423
            return "optional_token(" + StringUtils.join(this.optional_token) + ") onTrue:" + StringUtils.join(onTrueRules, ",")+", onFalse:" + StringUtils.join(onFalseRules, ",");
424
        }
425
    }
426

    
427
    public class RuleSwitchToken implements SwichTokenRule {
428

    
429
        private final List<Pair<String,Rule[]>> caseRules;
430
        private Rule[] defaultRule;
431

    
432
        public RuleSwitchToken() {
433
            this.caseRules = new ArrayList<>();
434
        }
435

    
436
        @Override
437
        public Rule capture_as(String... ids) {
438
          throw new UnsupportedOperationException("Unsupported operation.");
439
        }
440

    
441
        @Override
442
        public void parse(StatementContext context) {
443
            context.trace(this.toString()+".parse");
444
            Token token = context.look_token();
445
            for (Pair<String, Rule[]> caseRule : caseRules) {
446
              if( token.is(caseRule.getKey()) ) {
447
                context.next_token();
448
                for (Rule rule : caseRule.getValue()) {
449
                  rule.parse(context);
450
                }
451
                return;
452
              }
453
            }
454
            if( defaultRule!=null ) {
455
              for (Rule rule : defaultRule) {
456
                rule.parse(context);
457
              }
458
            }
459
        }
460

    
461
        @Override
462
        public SwichTokenRule addCase(String token, Rule... rules) {
463
            this.caseRules.add(new ImmutablePair(token,rules));
464
            return this;
465
        }
466

    
467
        @Override
468
        public SwichTokenRule addDefault(Rule... rules) {
469
            this.defaultRule = rules;
470
            return this;
471
        }
472

    
473
        @Override
474
        public String toString() {
475
            return "switch_token() rules:" + StringUtils.join(this.caseRules,",") + " default: " + defaultRule;
476
        }
477
    }
478

    
479
    public class RuleRepeatUntilAnyTokens implements RepeatRule {
480

    
481
        private final String[] exit_tokens;
482
        private final List<Rule> rules;
483
        private int counter;
484

    
485
        public RuleRepeatUntilAnyTokens(String[] exit_tokens) {
486
            this.exit_tokens = exit_tokens;
487
            this.rules = new ArrayList<>();
488
        }
489

    
490
        @Override
491
        public Rule capture_as(String... ids) {
492
          throw new UnsupportedOperationException("Operation not suppted.");
493
        }
494
        
495
        @Override
496
        public void parse(StatementContext context) {
497
            context.trace(this.toString()+".parse");
498
            String save = context.getCodeClassifier();
499
            try {
500
                this.counter = 1;
501
                while (true) {
502
                    Token token = context.look_token();
503
                    if (token.is(this.exit_tokens)) {
504
                        break;
505
                    }
506
                    context.setCodeClassifier(String.valueOf(counter).trim());
507
                    context.setOtherValues(counter);
508
                    for (Rule rule : rules) {
509
                        rule.parse(context);
510
                    }
511
                    this.counter = (int) context.getOtherValues();
512
                    this.counter = this.counter + 1;
513
                }
514
            } finally {
515
                context.setCodeClassifier(save);
516
            }
517
        }
518

    
519
        @Override
520
        public RuleRepeatUntilAnyTokens addRule(Rule rule) {
521
            this.rules.add(rule);
522
            return this;
523
        }
524

    
525
        @Override
526
        public String getClassifier() {
527
            String s = String.valueOf(counter).trim();
528
            return s;
529
        }
530

    
531
        @Override
532
        public String toString() {
533
            return "repeat_until_tokens('" + ArrayUtils.toString(this.exit_tokens) + "') rules:" + StringUtils.join(rules, ",");
534
        }
535
    }
536

    
537
    public class RuleRepeat implements RepeatRule {
538

    
539
        private final List<Rule> rules;
540
        private int counter;
541

    
542
        public RuleRepeat() {
543
            this.rules = new ArrayList<>();
544
        }
545
        
546
        @Override
547
        public Rule capture_as(String... ids) {
548
          throw new UnsupportedOperationException("Operation not suppted.");
549
        }
550
        
551
        @Override
552
        public void parse(StatementContext context) {
553
            context.trace(this.toString()+".parse");
554
            String saveCodeClassifier = context.getCodeClassifier();
555
            try {
556
                this.counter = 1;
557
                boolean breakloop = false;
558
                while (!breakloop) {
559
                    context.setCodeClassifier(String.valueOf(counter).trim());
560
                    context.setOtherValues(counter);
561
                    for (Rule rule : rules) {
562
                      try {
563
                        rule.parse(context);
564
                      } catch(BreakLoopException ex) {
565
                        breakloop = true;
566
                        break;
567
                      }
568
                    }
569
                    this.counter = (int) context.getOtherValues();
570
                    this.counter = this.counter + 1;
571
                }
572
            } finally {
573
                context.setCodeClassifier(saveCodeClassifier);
574
            }
575
        }
576

    
577
        @Override
578
        public RuleRepeat addRule(Rule rule) {
579
            this.rules.add(rule);
580
            return this;
581
        }
582

    
583
        @Override
584
        public String getClassifier() {
585
            String s = String.valueOf(counter).trim();
586
            return s;
587
        }
588

    
589
        @Override
590
        public String toString() {
591
            return "repeat() rules:" + StringUtils.join(rules, ",");
592
        }
593
    }
594

    
595
    public static class BreakLoopException extends RuntimeException {
596
      
597
    }
598
    
599
    public static class RuleBreakLoop implements Rule {
600

    
601
        public RuleBreakLoop() {
602
        }
603

    
604
        @Override
605
        public Rule capture_as(String... ids) {
606
          throw new UnsupportedOperationException("Operation not suppted.");
607
        }
608

    
609
        @Override
610
        public void parse(StatementContext context) {
611
          context.trace(this.toString()+".parse");
612
          throw new BreakLoopException();
613
        }
614

    
615
        @Override
616
        public String toString() {
617
            return "break_loop()";
618
        }
619
    }
620

    
621
        public static class RuleFail implements Rule {
622

    
623
        public RuleFail() {
624
        }
625

    
626
        @Override
627
        public Rule capture_as(String... ids) {
628
          throw new UnsupportedOperationException("Operation not suppted.");
629
        }
630

    
631
        @Override
632
        public void parse(StatementContext context) {
633
          context.trace(this.toString()+".parse");
634
          throw new ExpressionSyntaxException();
635
        }
636

    
637
        @Override
638
        public String toString() {
639
            return "fail()";
640
        }
641
    }
642

    
643
    public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule {
644

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

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

    
653
        @Override
654
        public ConditionalRule 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
              if( this.id!=null ) {
681
                Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
682
                context.setCode(id, code);
683
              }
684
              this.parseOnTrueRules(context);
685
            } else {
686
                this.parseOnFalseRules(context);
687
            }
688
        }
689

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

    
696
    public class RuleRequireIdentifiers implements Rule {
697

    
698
        private String id;
699
        private final String separator;
700

    
701
        public RuleRequireIdentifiers(String separator) {
702
            super();
703
            this.separator = separator;
704
        }
705

    
706
        @Override
707
        public Rule capture_as(String... ids) {
708
          this.id = ids[0];
709
          return this;
710
        }
711

    
712
        @Override
713
        public void parse(StatementContext context) {
714
            context.trace(this.toString()+".parse");
715
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
716
            Token token = context.look_token();
717
            while (token.getType() == Token.IDENTIFIER) {
718
                String identifier = (String) token.getLiteral();
719
                if( context.isReservedWord(identifier) ) {
720
                    break;
721
                }
722
                Code code = context.getCodeBuilder().identifier(identifier);
723
                args.add(code);
724
                context.next_token();
725
                token = context.look_token();
726
                if (!token.is(this.separator)) {
727
                    break;
728
                }
729
                context.next_token();
730
                token = context.look_token();
731
            }
732
            if (args.size() == 0) {
733
                throw new ExpressionSyntaxException(
734
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
735
                        context.getLexicalAnalyzer()
736
                );
737
            }
738
            if( this.id!=null ) {
739
              Code code = context.getCodeBuilder().function(FUNCTION_TUPLE, args);
740
              context.setCode(id, code);
741
            }
742
        }
743

    
744
        @Override
745
        public String toString() {
746
            return "require_identifiers('" + id + "', '" + this.separator + "')";
747
        }
748
    }
749

    
750
    public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule {
751

    
752
        private String id;
753

    
754
        public RuleOptionalLiteralString() {
755
            super();
756
        }
757

    
758
        @Override
759
        public ConditionalRule capture_as(String... ids) {
760
          this.id = ids[0];
761
          return this;
762
        }
763
        
764
        @Override
765
        public void parse(StatementContext context) {
766
            context.trace(this.toString()+".parse");
767
            Token token = context.look_token();
768
            if (token.getType() == Token.STRING_LITERAL) {
769
                if( this.id!=null ) {
770
                  String s = (String) token.getValue();
771
                  Code code = context.getCodeBuilder().constant(s);
772
                  context.setCode(id, code);
773
                  context.next_token();
774
                }
775
                this.parseOnTrueRules(context);
776
            } else {
777
                this.parseOnFalseRules(context);
778
            }
779
        }
780

    
781
        @Override
782
        public String toString() {
783
            return "optional_literal_string('" + id + "')";
784
        }
785
    }
786

    
787
    public static class ArgsBuilderFromNames implements ArgsBuilder {
788

    
789
        protected final String[] argNames;
790

    
791
        public ArgsBuilderFromNames(String... argNames) {
792
            this.argNames = argNames;
793
        }
794

    
795
        @Override
796
        public String toString() {
797
          return "args_names("+StringUtils.join(argNames,",")+")";
798
        }
799
        
800
        @Override
801
        public Codes build(StatementContext context) {
802
            context.trace(this.toString()+".build");
803
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
804
            for (String argName : argNames) {
805
                if (argName.contains("#")) {
806
                    Code code = context.getCode(argName);
807
                    if (code == null) {
808
                        int n = 1;
809
                        while (true) {
810
                            String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
811
                            code = context.getCode(argNameX);
812
                            if (code == null) {
813
                                break;
814
                            }
815
                            args.add(code);
816
                            n++;
817
                        }
818
                    } else {
819
                        args.add(code);
820
                    }
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
    public static class FixedArgsBuilderFromNames implements ArgsBuilder {
834

    
835
        protected final String[] argNames;
836

    
837
        public FixedArgsBuilderFromNames(String... argNames) {
838
            this.argNames = argNames;
839
        }
840

    
841
        @Override
842
        public String toString() {
843
          return "fixed_args_names("+StringUtils.join(argNames,",")+")";
844
        }
845
        
846
        @Override
847
        public Codes build(StatementContext context) {
848
            context.trace(this.toString()+".build");
849
            CodeBuilder codeBuilder = context.getCodeBuilder();
850
            BaseCodes args = (BaseCodes) codeBuilder.args();
851
            for (String argName : argNames) {
852
                if (argName.contains("#")) {
853
                    int n = 1;
854
                    BaseCodes argsX = (BaseCodes) codeBuilder.args();
855
                    while (true) {
856
                        String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
857
                        Code code = context.getCode(argNameX);
858
                        if (code == null) {
859
                            break;
860
                        }
861
                        argsX.add(code);
862
                        n++;
863
                    }
864
                    
865
                    args.add(codeBuilder.tuple(argsX));
866
                } else {
867
                    Code code = context.getCode(argName);
868
                    if( code == null) {
869
                        code = context.getCodeBuilder().constant(null);
870
                    }
871
                    args.add(code);
872
                }
873
            }
874
            return args;
875
        }
876
    }
877

    
878
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
879

    
880
        public ArgsBuilderExpand(String... argNames) {
881
            super(argNames);
882
        }
883

    
884
        @Override
885
        public String toString() {
886
          return "args_expand("+StringUtils.join(argNames,",")+")";
887
        }
888
        
889
        @Override
890
        public Codes build(StatementContext context) {
891
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
892
            
893
            Codes base_args = super.build(context);
894
            for (Code arg : base_args) {
895
                if( arg.code() == Code.CALLABLE && 
896
                    ((Callable)arg).name().equals(CodeBlockFunction.NAME) ) {
897
                    Codes block_args = ((Callable)arg).parameters();
898
                    for (Code block_arg : block_args) {
899
                        args.add(block_arg);
900
                    }
901
                } else {
902
                    args.add(arg);
903
                }
904
            }
905
            return args;
906
        }
907
    }
908

    
909
    public static class StatementBuilderBase implements StatementBuilder {
910
        protected ArgsBuilder argsBuilder;
911
        protected String codeID;
912
        
913
        public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) {
914
            this.codeID = codeID;
915
            this.argsBuilder = argsBuilder;
916
        }
917
        
918
        @Override
919
        public String getCodeID() {
920
            return this.codeID;
921
        }
922

    
923
        @Override
924
        public ArgsBuilder getArgsBuilder() {
925
            return this.argsBuilder;
926
        }
927

    
928
        @Override
929
        public Code build(StatementContext context) {
930
            Codes args = this.getArgsBuilder().build(context);
931
            Code code = null;
932
            if (this.getCodeID() == null) {
933
                code = args.get(0);
934
            } else {
935
                if (args.size() == 0) {
936
                    code = context.getCodeBuilder().function(this.getCodeID(), null);
937
                } else {
938
                    // Si es un bloque dentro de otro, dejamos solo uno.
939
                    if( args.size()==1 && 
940
                        StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,this.getCodeID()) ) {
941
                        Code code0 = args.get(0);
942
                        if( code0.code() == Code.CALLABLE && 
943
                                StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Callable)code0).name())
944
                                ) {
945
                            code = code0;
946
                        }
947
                    }
948
                    if( code == null ) {
949
                        code = context.getCodeBuilder().function(this.getCodeID(), args);
950
                    }
951
                }
952
            }
953
            return code;
954
        }
955
    }
956
    
957
    public DefaultStatement(String name) {
958
        this.rules = new ArrayList<>();
959
        this.stmtBuilder = null;
960
        this.name = name;
961
    }
962

    
963
    @Override
964
    public String getName() {
965
        return name;
966
    }
967

    
968
    @Override
969
    public Rule require_any_token(String... token) {
970
        return new RuleRequireAnyToken(token);
971
    }
972

    
973
    @Override
974
    public Rule require_tokens(String... token) {
975
        return new RuleRequireTokens(token);
976
    }
977

    
978
    @Override
979
    public Rule require_identifier() {
980
        return new RuleRequireIdentifier();
981
    }
982

    
983
    @Override
984
    public Rule require_identifiers(String sep) {
985
        return new RuleRequireIdentifiers(sep);
986
    }
987

    
988
    @Override
989
    public Rule require_literal_string() {
990
        return new RuleRequireLiteralString();
991
    }
992

    
993
    @Override
994
    public Rule set_expression(String id, Object value) {
995
        return new RuleSetExpression(id, value);
996
    }
997

    
998
    @Override
999
    public Rule require_expression() {
1000
        return this.require_expression(true);
1001
    }
1002

    
1003
    @Override
1004
    public Rule require_expression(boolean allow_assignement) {
1005
        return new RuleRequireExpression(allow_assignement);
1006
    }
1007

    
1008
    @Override
1009
    public Rule require_expressions(String separator) {
1010
        return new RuleRequiereExpressions(separator);
1011
    }
1012

    
1013
    @Override
1014
    public ConditionalRule optional_any_token(String... id) {
1015
        return new RuleOptionalAnyToken(id);
1016
    }
1017

    
1018
    @Override
1019
    public ConditionalRule optional_identifiers(String separator) {
1020
        return new RuleOptionalIdentifiers(separator);
1021
    }
1022

    
1023
    @Override
1024
    public ConditionalRule optional_literal_string() {
1025
        return new RuleOptionalLiteralString();
1026
    }
1027

    
1028
    @Override
1029
    public CompoundRule repeat_until_any_tokens(String... tokens) {
1030
        return new RuleRepeatUntilAnyTokens(tokens);
1031
    }
1032

    
1033
    @Override
1034
    public Statement addRule(Rule rule) {
1035
        this.rules.add(rule);
1036
        return this;
1037
    }
1038

    
1039
    @Override
1040
    public boolean isApplicable(StatementContext context) {
1041
        if (this.rules.isEmpty()) {
1042
            return false;
1043
        }
1044
        context.trace(this.getName()+".isApplicable");
1045
        context.save_state();
1046
        try {
1047
          for (Rule rule : rules) {
1048
            if( rule == null ) {
1049
              continue;
1050
            }
1051
            if (rule instanceof IsApplicableRule) {
1052
              if( !((IsApplicableRule) rule).isApplicable(context) ) {
1053
                context.trace(this.getName()+".isApplicable return false");
1054
                return false;
1055
              }
1056
            } else {
1057
              rule.parse(context);
1058
            }
1059
          }
1060
          context.trace(this.getName()+".isApplicable return true");
1061
          return true;
1062
        } catch(Exception ex) {
1063
          context.trace(this.getName()+".isApplicable return false (error)");
1064
          return false;
1065
        } finally {
1066
          context.restore_state();
1067
        }
1068
    }
1069

    
1070
    @Override
1071
    public ArgsBuilder args_names(String... args) {
1072
        ArgsBuilder x = new ArgsBuilderFromNames(args);
1073
        return x;
1074
    }
1075
    
1076
    @Override
1077
    public ArgsBuilder fixed_args_names(String... args) {
1078
        ArgsBuilder x = new FixedArgsBuilderFromNames(args);
1079
        return x;
1080
    }
1081
    
1082
    @Override
1083
    public ArgsBuilder args_expand(String... args) {
1084
        ArgsBuilder x = new ArgsBuilderExpand(args);
1085
        return x;
1086
    }
1087
    
1088
    @Override
1089
    public void code(final String id, final ArgsBuilder argsBuilder) {
1090
        this.builder(new StatementBuilderBase(id, argsBuilder));
1091
    }
1092

    
1093
    @Override
1094
    public void builder(StatementBuilder builder) {
1095
        this.stmtBuilder = builder;
1096
    }
1097
    
1098
    @Override
1099
    public Code parse(StatementContext context) {
1100
        context.trace(this.getName()+".parse");
1101
        for (Rule rule : rules) {
1102
            rule.parse(context);
1103
        }
1104
        Code code = this.stmtBuilder.build(context);
1105
        context.trace(this.getName()+".return "+code);
1106
        return code;
1107
    }
1108

    
1109
    @Override
1110
    public String toString() {
1111
        return this.getName() + " " + StringUtils.join(this.rules, ";");
1112

    
1113
    }
1114

    
1115
    @Override
1116
    public CompoundRule repeat() {
1117
      return new RuleRepeat();
1118
    }
1119

    
1120
    @Override
1121
    public Rule fail() {
1122
      return new RuleFail();
1123
    }
1124

    
1125
    @Override
1126
    public Rule break_loop() {
1127
      return new RuleBreakLoop();
1128
    }
1129
    
1130
    @Override
1131
    public SwichTokenRule switch_token() {
1132
      return new RuleSwitchToken();
1133
    }
1134

    
1135
}