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
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 RuleRequireIdentifier implements IsApplicableRule {
99

    
100
        private String id;
101

    
102
        public RuleRequireIdentifier() {
103
        }
104

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

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

    
129
        @Override
130
        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
        public String toString() {
139
            return "require_identifier('" + this.id + "')";
140
        }
141
    }
142

    
143
    public class RuleRequireLiteralString implements Rule {
144

    
145
        private String id;
146

    
147
        public RuleRequireLiteralString() {
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.STRING_LITERAL) {
161
                throw new ExpressionSyntaxException(
162
                        I18N.A_string_literal_was_expected(),
163
                        context.getLexicalAnalyzer()
164
                );
165
            }
166
            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
        }
173

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

    
180
    public class RuleRequireExpression implements Rule {
181

    
182
        private String id;
183
        boolean allow_assignement;
184

    
185
        public RuleRequireExpression(boolean allow_assignement) {
186
            this.allow_assignement = allow_assignement;
187
        }
188

    
189
        @Override
190
        public Rule capture_as(String... ids) {
191
          this.id = ids[0];
192
          return this;
193
        }
194

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

    
207
        @Override
208
        public String toString() {
209
            return "require_expression('" + this.id + "')";
210
        }
211
    }
212

    
213

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

    
229
        @Override
230
        public void parse(StatementContext context) {
231
            context.trace(this.toString()+".parse");
232
            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
    public class RuleRequiereExpressions implements Rule {
246

    
247
        private String id;
248
        private final String separator;
249

    
250
        public RuleRequiereExpressions(String separator) {
251
            this.separator = separator;
252
        }
253

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

    
278
        @Override
279
        public String toString() {
280
            return "require_expressions('" + this.id + "', '" + this.separator + "')";
281
        }
282
    }
283

    
284
    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
        @Override
295
        public ConditionalRule capture_as(String... ids) {
296
          throw new UnsupportedOperationException("Operation not suppted.");
297
        }
298

    
299
        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
    public class RuleOptionalAnyToken implements ConditionalRule {
326

    
327
        private final String[] optional_token;
328
        private final List<Rule> onTrueRules;
329
        private final List<Rule> onFalseRules;
330
        private String id;
331

    
332
        public RuleOptionalAnyToken(String... optional_token) {
333
            this.optional_token = optional_token;
334
            this.onTrueRules = new ArrayList<>();
335
            this.onFalseRules = new ArrayList<>();
336
        }
337

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

    
370
        @Override
371
        public RuleOptionalAnyToken addRuleOnFalse(Rule rule) {
372
            this.onFalseRules.add(rule);
373
            return this;
374
        }
375

    
376
        @Override
377
        public String toString() {
378
            return "optional_token(" + StringUtils.join(this.optional_token) + ") onTrue:" + StringUtils.join(onTrueRules, ",")+", onFalse:" + StringUtils.join(onFalseRules, ",");
379
        }
380
    }
381

    
382
    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
        public Rule capture_as(String... ids) {
393
          throw new UnsupportedOperationException("Unsupported operation.");
394
        }
395

    
396
        @Override
397
        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
    public class RuleRepeatUntilAnyTokens implements RepeatRule {
435

    
436
        private final String[] exit_tokens;
437
        private final List<Rule> rules;
438
        private int counter;
439

    
440
        public RuleRepeatUntilAnyTokens(String[] exit_tokens) {
441
            this.exit_tokens = exit_tokens;
442
            this.rules = new ArrayList<>();
443
        }
444

    
445
        @Override
446
        public Rule capture_as(String... ids) {
447
          throw new UnsupportedOperationException("Operation not suppted.");
448
        }
449
        
450
        @Override
451
        public void parse(StatementContext context) {
452
            context.trace(this.toString()+".parse");
453
            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
                    context.setOtherValues(counter);
463
                    for (Rule rule : rules) {
464
                        rule.parse(context);
465
                    }
466
                    this.counter = (int) context.getOtherValues();
467
                    this.counter = this.counter + 1;
468
                }
469
            } finally {
470
                context.setCodeClassifier(save);
471
            }
472
        }
473

    
474
        @Override
475
        public RuleRepeatUntilAnyTokens addRule(Rule rule) {
476
            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
    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
        
501
        @Override
502
        public Rule capture_as(String... ids) {
503
          throw new UnsupportedOperationException("Operation not suppted.");
504
        }
505
        
506
        @Override
507
        public void parse(StatementContext context) {
508
            context.trace(this.toString()+".parse");
509
            String saveCodeClassifier = context.getCodeClassifier();
510
            try {
511
                this.counter = 1;
512
                boolean breakloop = false;
513
                while (!breakloop) {
514
                    context.setCodeClassifier(String.valueOf(counter).trim());
515
                    context.setOtherValues(counter);
516
                    for (Rule rule : rules) {
517
                      try {
518
                        rule.parse(context);
519
                      } catch(BreakLoopException ex) {
520
                        breakloop = true;
521
                        break;
522
                      }
523
                    }
524
                    this.counter = (int) context.getOtherValues();
525
                    this.counter = this.counter + 1;
526
                }
527
            } finally {
528
                context.setCodeClassifier(saveCodeClassifier);
529
            }
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
        public Rule capture_as(String... ids) {
561
          throw new UnsupportedOperationException("Operation not suppted.");
562
        }
563

    
564
        @Override
565
        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
        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
    public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule {
599

    
600
        private String id;
601
        private final String separator;
602

    
603
        public RuleOptionalIdentifiers(String separator) {
604
            super();
605
            this.separator = separator;
606
        }
607

    
608
        @Override
609
        public ConditionalRule capture_as(String... ids) {
610
          this.id = ids[0];
611
          return this;
612
        }
613

    
614
        @Override
615
        public void parse(StatementContext context) {
616
            context.trace(this.toString()+".parse");
617
            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
                if( context.isReservedWord(identifier) ) {
622
                    break;
623
                }
624
                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
              if( this.id!=null ) {
636
                Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
637
                context.setCode(id, code);
638
              }
639
              this.parseOnTrueRules(context);
640
            } else {
641
                this.parseOnFalseRules(context);
642
            }
643
        }
644

    
645
        @Override
646
        public String toString() {
647
            return "optional_identifiers('" + id + "', '" + this.separator + "')";
648
        }
649
    }
650

    
651
    public class RuleRequireIdentifiers implements Rule {
652

    
653
        private String id;
654
        private final String separator;
655

    
656
        public RuleRequireIdentifiers(String separator) {
657
            super();
658
            this.separator = separator;
659
        }
660

    
661
        @Override
662
        public Rule capture_as(String... ids) {
663
          this.id = ids[0];
664
          return this;
665
        }
666

    
667
        @Override
668
        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
                Code code = context.getCodeBuilder().identifier(identifier);
678
                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
            if( this.id!=null ) {
694
              Code code = context.getCodeBuilder().function(FUNCTION_TUPLE, args);
695
              context.setCode(id, code);
696
            }
697
        }
698

    
699
        @Override
700
        public String toString() {
701
            return "require_identifiers('" + id + "', '" + this.separator + "')";
702
        }
703
    }
704

    
705
    public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule {
706

    
707
        private String id;
708

    
709
        public RuleOptionalLiteralString() {
710
            super();
711
        }
712

    
713
        @Override
714
        public ConditionalRule capture_as(String... ids) {
715
          this.id = ids[0];
716
          return this;
717
        }
718
        
719
        @Override
720
        public void parse(StatementContext context) {
721
            context.trace(this.toString()+".parse");
722
            Token token = context.look_token();
723
            if (token.getType() == Token.STRING_LITERAL) {
724
                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
                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
    public static class ArgsBuilderFromNames implements ArgsBuilder {
743

    
744
        protected final String[] argNames;
745

    
746
        public ArgsBuilderFromNames(String... argNames) {
747
            this.argNames = argNames;
748
        }
749

    
750
        @Override
751
        public String toString() {
752
          return "args_names("+StringUtils.join(argNames,",")+")";
753
        }
754
        
755
        @Override
756
        public Codes build(StatementContext context) {
757
            context.trace(this.toString()+".build");
758
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
759
            for (String argName : argNames) {
760
                if (argName.contains("#")) {
761
                    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
                        }
773
                    } else {
774
                        args.add(code);
775
                    }
776
                } else {
777
                    Code code = context.getCode(argName);
778
//                    if( code == null) {
779
//                        code = context.getCodeBuilder().constant(null);
780
//                    }
781
                    args.add(code);
782
                }
783
            }
784
            return args;
785
        }
786
    }
787

    
788
    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
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
834

    
835
        public ArgsBuilderExpand(String... argNames) {
836
            super(argNames);
837
        }
838

    
839
        @Override
840
        public String toString() {
841
          return "args_expand("+StringUtils.join(argNames,",")+")";
842
        }
843
        
844
        @Override
845
        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
                if( arg.code() == Code.CALLABLE && 
851
                    ((Callable)arg).name().equals(CodeBlockFunction.NAME) ) {
852
                    Codes block_args = ((Callable)arg).parameters();
853
                    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
    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
                        if( code0.code() == Code.CALLABLE && 
898
                                StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Callable)code0).name())
899
                                ) {
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
    public DefaultStatement(String name) {
913
        this.rules = new ArrayList<>();
914
        this.stmtBuilder = null;
915
        this.name = name;
916
    }
917

    
918
    @Override
919
    public String getName() {
920
        return name;
921
    }
922

    
923
    @Override
924
    public Rule require_any_token(String... token) {
925
        return new RuleRequireAnyToken(token);
926
    }
927

    
928
    @Override
929
    public Rule require_identifier() {
930
        return new RuleRequireIdentifier();
931
    }
932

    
933
    @Override
934
    public Rule require_identifiers(String sep) {
935
        return new RuleRequireIdentifiers(sep);
936
    }
937

    
938
    @Override
939
    public Rule require_literal_string() {
940
        return new RuleRequireLiteralString();
941
    }
942

    
943
    @Override
944
    public Rule set_expression(String id, Object value) {
945
        return new RuleSetExpression(id, value);
946
    }
947

    
948
    @Override
949
    public Rule require_expression() {
950
        return this.require_expression(true);
951
    }
952

    
953
    @Override
954
    public Rule require_expression(boolean allow_assignement) {
955
        return new RuleRequireExpression(allow_assignement);
956
    }
957

    
958
    @Override
959
    public Rule require_expressions(String separator) {
960
        return new RuleRequiereExpressions(separator);
961
    }
962

    
963
    @Override
964
    public ConditionalRule optional_any_token(String... id) {
965
        return new RuleOptionalAnyToken(id);
966
    }
967

    
968
    @Override
969
    public ConditionalRule optional_identifiers(String separator) {
970
        return new RuleOptionalIdentifiers(separator);
971
    }
972

    
973
    @Override
974
    public ConditionalRule optional_literal_string() {
975
        return new RuleOptionalLiteralString();
976
    }
977

    
978
    @Override
979
    public CompoundRule repeat_until_any_tokens(String... tokens) {
980
        return new RuleRepeatUntilAnyTokens(tokens);
981
    }
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
        context.trace(this.getName()+".isApplicable");
995
        context.save_state();
996
        try {
997
          for (Rule rule : rules) {
998
            if( rule == null ) {
999
              continue;
1000
            }
1001
            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
            }
1009
          }
1010
          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
        } finally {
1016
          context.restore_state();
1017
        }
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
    public ArgsBuilder fixed_args_names(String... args) {
1028
        ArgsBuilder x = new FixedArgsBuilderFromNames(args);
1029
        return x;
1030
    }
1031
    
1032
    @Override
1033
    public ArgsBuilder args_expand(String... args) {
1034
        ArgsBuilder x = new ArgsBuilderExpand(args);
1035
        return x;
1036
    }
1037
    
1038
    @Override
1039
    public void code(final String id, final ArgsBuilder argsBuilder) {
1040
        this.builder(new StatementBuilderBase(id, argsBuilder));
1041
    }
1042

    
1043
    @Override
1044
    public void builder(StatementBuilder builder) {
1045
        this.stmtBuilder = builder;
1046
    }
1047
    
1048
    @Override
1049
    public Code parse(StatementContext context) {
1050
        context.trace(this.getName()+".parse");
1051
        for (Rule rule : rules) {
1052
            rule.parse(context);
1053
        }
1054
        Code code = this.stmtBuilder.build(context);
1055
        context.trace(this.getName()+".return "+code);
1056
        return code;
1057
    }
1058

    
1059
    @Override
1060
    public String toString() {
1061
        return this.getName() + " " + StringUtils.join(this.rules, ";");
1062

    
1063
    }
1064

    
1065
    @Override
1066
    public CompoundRule repeat() {
1067
      return new RuleRepeat();
1068
    }
1069

    
1070
    @Override
1071
    public Rule fail() {
1072
      return new RuleFail();
1073
    }
1074

    
1075
    @Override
1076
    public Rule break_loop() {
1077
      return new RuleBreakLoop();
1078
    }
1079
    
1080
    @Override
1081
    public SwichTokenRule switch_token() {
1082
      return new RuleSwitchToken();
1083
    }
1084

    
1085
}