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

History | View | Annotate | Download (32.7 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
                    for (Rule rule : rules) {
463
                        rule.parse(context);
464
                    }
465
                    this.counter = this.counter + 1;
466
                }
467
            } finally {
468
                context.setCodeClassifier(save);
469
            }
470
        }
471

    
472
        @Override
473
        public RuleRepeatUntilAnyTokens addRule(Rule rule) {
474
            this.rules.add(rule);
475
            return this;
476
        }
477

    
478
        @Override
479
        public String getClassifier() {
480
            String s = String.valueOf(counter).trim();
481
            return s;
482
        }
483

    
484
        @Override
485
        public String toString() {
486
            return "repeat_until_tokens('" + ArrayUtils.toString(this.exit_tokens) + "') rules:" + StringUtils.join(rules, ",");
487
        }
488
    }
489

    
490
    public class RuleRepeat implements RepeatRule {
491

    
492
        private final List<Rule> rules;
493
        private int counter;
494

    
495
        public RuleRepeat() {
496
            this.rules = new ArrayList<>();
497
        }
498
        
499
        @Override
500
        public Rule capture_as(String... ids) {
501
          throw new UnsupportedOperationException("Operation not suppted.");
502
        }
503
        
504
        @Override
505
        public void parse(StatementContext context) {
506
            context.trace(this.toString()+".parse");
507
            String save = context.getCodeClassifier();
508
            try {
509
                this.counter = 1;
510
                boolean breakloop = false;
511
                while (!breakloop) {
512
                    context.setCodeClassifier(String.valueOf(counter).trim());
513
                    for (Rule rule : rules) {
514
                      try {
515
                        rule.parse(context);
516
                      } catch(BreakLoopException ex) {
517
                        breakloop = true;
518
                        break;
519
                      }
520
                    }
521
                    this.counter = this.counter + 1;
522
                }
523
            } finally {
524
                context.setCodeClassifier(save);
525
            }
526
        }
527

    
528
        @Override
529
        public RuleRepeat addRule(Rule rule) {
530
            this.rules.add(rule);
531
            return this;
532
        }
533

    
534
        @Override
535
        public String getClassifier() {
536
            String s = String.valueOf(counter).trim();
537
            return s;
538
        }
539

    
540
        @Override
541
        public String toString() {
542
            return "repeat() rules:" + StringUtils.join(rules, ",");
543
        }
544
    }
545

    
546
    public static class BreakLoopException extends RuntimeException {
547
      
548
    }
549
    
550
    public static class RuleBreakLoop implements Rule {
551

    
552
        public RuleBreakLoop() {
553
        }
554

    
555
        @Override
556
        public Rule capture_as(String... ids) {
557
          throw new UnsupportedOperationException("Operation not suppted.");
558
        }
559

    
560
        @Override
561
        public void parse(StatementContext context) {
562
          context.trace(this.toString()+".parse");
563
          throw new BreakLoopException();
564
        }
565

    
566
        @Override
567
        public String toString() {
568
            return "break_loop()";
569
        }
570
    }
571

    
572
        public static class RuleFail implements Rule {
573

    
574
        public RuleFail() {
575
        }
576

    
577
        @Override
578
        public Rule capture_as(String... ids) {
579
          throw new UnsupportedOperationException("Operation not suppted.");
580
        }
581

    
582
        @Override
583
        public void parse(StatementContext context) {
584
          context.trace(this.toString()+".parse");
585
          throw new ExpressionSyntaxException();
586
        }
587

    
588
        @Override
589
        public String toString() {
590
            return "fail()";
591
        }
592
    }
593

    
594
    public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule {
595

    
596
        private String id;
597
        private final String separator;
598

    
599
        public RuleOptionalIdentifiers(String separator) {
600
            super();
601
            this.separator = separator;
602
        }
603

    
604
        @Override
605
        public ConditionalRule capture_as(String... ids) {
606
          this.id = ids[0];
607
          return this;
608
        }
609

    
610
        @Override
611
        public void parse(StatementContext context) {
612
            context.trace(this.toString()+".parse");
613
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
614
            Token token = context.look_token();
615
            while (token.getType() == Token.IDENTIFIER) {
616
                String identifier = (String) token.getLiteral();
617
                if( context.isReservedWord(identifier) ) {
618
                    break;
619
                }
620
                Code code = context.getCodeBuilder().constant(identifier);
621
                args.add(code);
622
                context.next_token();
623
                token = context.look_token();
624
                if (!token.is(this.separator)) {
625
                    break;
626
                }
627
                context.next_token();
628
                token = context.look_token();
629
            }
630
            if (args.size() != 0) {
631
              if( this.id!=null ) {
632
                Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
633
                context.setCode(id, code);
634
              }
635
              this.parseOnTrueRules(context);
636
            } else {
637
                this.parseOnFalseRules(context);
638
            }
639
        }
640

    
641
        @Override
642
        public String toString() {
643
            return "optional_identifiers('" + id + "', '" + this.separator + "')";
644
        }
645
    }
646

    
647
    public class RuleRequireIdentifiers implements Rule {
648

    
649
        private String id;
650
        private final String separator;
651

    
652
        public RuleRequireIdentifiers(String separator) {
653
            super();
654
            this.separator = separator;
655
        }
656

    
657
        @Override
658
        public Rule capture_as(String... ids) {
659
          this.id = ids[0];
660
          return this;
661
        }
662

    
663
        @Override
664
        public void parse(StatementContext context) {
665
            context.trace(this.toString()+".parse");
666
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
667
            Token token = context.look_token();
668
            while (token.getType() == Token.IDENTIFIER) {
669
                String identifier = (String) token.getLiteral();
670
                if( context.isReservedWord(identifier) ) {
671
                    break;
672
                }
673
                Code code = context.getCodeBuilder().identifier(identifier);
674
                args.add(code);
675
                context.next_token();
676
                token = context.look_token();
677
                if (!token.is(this.separator)) {
678
                    break;
679
                }
680
                context.next_token();
681
                token = context.look_token();
682
            }
683
            if (args.size() == 0) {
684
                throw new ExpressionSyntaxException(
685
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
686
                        context.getLexicalAnalyzer()
687
                );
688
            }
689
            if( this.id!=null ) {
690
              Code code = context.getCodeBuilder().function(FUNCTION_TUPLE, args);
691
              context.setCode(id, code);
692
            }
693
        }
694

    
695
        @Override
696
        public String toString() {
697
            return "require_identifiers('" + id + "', '" + this.separator + "')";
698
        }
699
    }
700

    
701
    public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule {
702

    
703
        private String id;
704

    
705
        public RuleOptionalLiteralString() {
706
            super();
707
        }
708

    
709
        @Override
710
        public ConditionalRule capture_as(String... ids) {
711
          this.id = ids[0];
712
          return this;
713
        }
714
        
715
        @Override
716
        public void parse(StatementContext context) {
717
            context.trace(this.toString()+".parse");
718
            Token token = context.look_token();
719
            if (token.getType() == Token.STRING_LITERAL) {
720
                if( this.id!=null ) {
721
                  String s = (String) token.getValue();
722
                  Code code = context.getCodeBuilder().constant(s);
723
                  context.setCode(id, code);
724
                  context.next_token();
725
                }
726
                this.parseOnTrueRules(context);
727
            } else {
728
                this.parseOnFalseRules(context);
729
            }
730
        }
731

    
732
        @Override
733
        public String toString() {
734
            return "optional_literal_string('" + id + "')";
735
        }
736
    }
737

    
738
    public static class ArgsBuilderFromNames implements ArgsBuilder {
739

    
740
        protected final String[] argNames;
741

    
742
        public ArgsBuilderFromNames(String... argNames) {
743
            this.argNames = argNames;
744
        }
745

    
746
        @Override
747
        public String toString() {
748
          return "args_names("+StringUtils.join(argNames,",")+")";
749
        }
750
        
751
        @Override
752
        public Codes build(StatementContext context) {
753
            context.trace(this.toString()+".build");
754
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
755
            for (String argName : argNames) {
756
                if (argName.contains("#")) {
757
                    Code code = context.getCode(argName);
758
                    if (code == null) {
759
                        int n = 1;
760
                        while (true) {
761
                            String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
762
                            code = context.getCode(argNameX);
763
                            if (code == null) {
764
                                break;
765
                            }
766
                            args.add(code);
767
                            n++;
768
                        }
769
                    } else {
770
                        args.add(code);
771
                    }
772
                } else {
773
                    Code code = context.getCode(argName);
774
//                    if( code == null) {
775
//                        code = context.getCodeBuilder().constant(null);
776
//                    }
777
                    args.add(code);
778
                }
779
            }
780
            return args;
781
        }
782
    }
783

    
784
    public static class FixedArgsBuilderFromNames implements ArgsBuilder {
785

    
786
        protected final String[] argNames;
787

    
788
        public FixedArgsBuilderFromNames(String... argNames) {
789
            this.argNames = argNames;
790
        }
791

    
792
        @Override
793
        public String toString() {
794
          return "fixed_args_names("+StringUtils.join(argNames,",")+")";
795
        }
796
        
797
        @Override
798
        public Codes build(StatementContext context) {
799
            context.trace(this.toString()+".build");
800
            CodeBuilder codeBuilder = context.getCodeBuilder();
801
            BaseCodes args = (BaseCodes) codeBuilder.args();
802
            for (String argName : argNames) {
803
                if (argName.contains("#")) {
804
                    int n = 1;
805
                    BaseCodes argsX = (BaseCodes) codeBuilder.args();
806
                    while (true) {
807
                        String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
808
                        Code code = context.getCode(argNameX);
809
                        if (code == null) {
810
                            break;
811
                        }
812
                        argsX.add(code);
813
                        n++;
814
                    }
815
                    
816
                    args.add(codeBuilder.tuple(argsX));
817
                } else {
818
                    Code code = context.getCode(argName);
819
                    if( code == null) {
820
                        code = context.getCodeBuilder().constant(null);
821
                    }
822
                    args.add(code);
823
                }
824
            }
825
            return args;
826
        }
827
    }
828

    
829
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
830

    
831
        public ArgsBuilderExpand(String... argNames) {
832
            super(argNames);
833
        }
834

    
835
        @Override
836
        public String toString() {
837
          return "args_expand("+StringUtils.join(argNames,",")+")";
838
        }
839
        
840
        @Override
841
        public Codes build(StatementContext context) {
842
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
843
            
844
            Codes base_args = super.build(context);
845
            for (Code arg : base_args) {
846
                if( arg.code() == Code.CALLABLE && 
847
                    ((Callable)arg).name().equals(CodeBlockFunction.NAME) ) {
848
                    Codes block_args = ((Callable)arg).parameters();
849
                    for (Code block_arg : block_args) {
850
                        args.add(block_arg);
851
                    }
852
                } else {
853
                    args.add(arg);
854
                }
855
            }
856
            return args;
857
        }
858
    }
859

    
860
    public static class StatementBuilderBase implements StatementBuilder {
861
        protected ArgsBuilder argsBuilder;
862
        protected String codeID;
863
        
864
        public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) {
865
            this.codeID = codeID;
866
            this.argsBuilder = argsBuilder;
867
        }
868
        
869
        @Override
870
        public String getCodeID() {
871
            return this.codeID;
872
        }
873

    
874
        @Override
875
        public ArgsBuilder getArgsBuilder() {
876
            return this.argsBuilder;
877
        }
878

    
879
        @Override
880
        public Code build(StatementContext context) {
881
            Codes args = this.getArgsBuilder().build(context);
882
            Code code = null;
883
            if (this.getCodeID() == null) {
884
                code = args.get(0);
885
            } else {
886
                if (args.size() == 0) {
887
                    code = context.getCodeBuilder().function(this.getCodeID(), null);
888
                } else {
889
                    // Si es un bloque dentro de otro, dejamos solo uno.
890
                    if( args.size()==1 && 
891
                        StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,this.getCodeID()) ) {
892
                        Code code0 = args.get(0);
893
                        if( code0.code() == Code.CALLABLE && 
894
                                StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Callable)code0).name())
895
                                ) {
896
                            code = code0;
897
                        }
898
                    }
899
                    if( code == null ) {
900
                        code = context.getCodeBuilder().function(this.getCodeID(), args);
901
                    }
902
                }
903
            }
904
            return code;
905
        }
906
    }
907
    
908
    public DefaultStatement(String name) {
909
        this.rules = new ArrayList<>();
910
        this.stmtBuilder = null;
911
        this.name = name;
912
    }
913

    
914
    @Override
915
    public String getName() {
916
        return name;
917
    }
918

    
919
    @Override
920
    public Rule require_any_token(String... token) {
921
        return new RuleRequireAnyToken(token);
922
    }
923

    
924
    @Override
925
    public Rule require_identifier() {
926
        return new RuleRequireIdentifier();
927
    }
928

    
929
    @Override
930
    public Rule require_identifiers(String sep) {
931
        return new RuleRequireIdentifiers(sep);
932
    }
933

    
934
    @Override
935
    public Rule require_literal_string() {
936
        return new RuleRequireLiteralString();
937
    }
938

    
939
    @Override
940
    public Rule set_expression(String id, Object value) {
941
        return new RuleSetExpression(id, value);
942
    }
943

    
944
    @Override
945
    public Rule require_expression() {
946
        return this.require_expression(true);
947
    }
948

    
949
    @Override
950
    public Rule require_expression(boolean allow_assignement) {
951
        return new RuleRequireExpression(allow_assignement);
952
    }
953

    
954
    @Override
955
    public Rule require_expressions(String separator) {
956
        return new RuleRequiereExpressions(separator);
957
    }
958

    
959
    @Override
960
    public ConditionalRule optional_any_token(String... id) {
961
        return new RuleOptionalAnyToken(id);
962
    }
963

    
964
    @Override
965
    public ConditionalRule optional_identifiers(String separator) {
966
        return new RuleOptionalIdentifiers(separator);
967
    }
968

    
969
    @Override
970
    public ConditionalRule optional_literal_string() {
971
        return new RuleOptionalLiteralString();
972
    }
973

    
974
    @Override
975
    public CompoundRule repeat_until_any_tokens(String... tokens) {
976
        return new RuleRepeatUntilAnyTokens(tokens);
977
    }
978

    
979
    @Override
980
    public Statement addRule(Rule rule) {
981
        this.rules.add(rule);
982
        return this;
983
    }
984

    
985
    @Override
986
    public boolean isApplicable(StatementContext context) {
987
        if (this.rules.isEmpty()) {
988
            return false;
989
        }
990
        context.trace(this.getName()+".isApplicable");
991
        context.save_state();
992
        try {
993
          for (Rule rule : rules) {
994
            if( rule == null ) {
995
              continue;
996
            }
997
            if (rule instanceof IsApplicableRule) {
998
              if( !((IsApplicableRule) rule).isApplicable(context) ) {
999
                context.trace(this.getName()+".isApplicable return false");
1000
                return false;
1001
              }
1002
            } else {
1003
              rule.parse(context);
1004
            }
1005
          }
1006
          context.trace(this.getName()+".isApplicable return true");
1007
          return true;
1008
        } catch(Exception ex) {
1009
          context.trace(this.getName()+".isApplicable return false (error)");
1010
          return false;
1011
        } finally {
1012
          context.restore_state();
1013
        }
1014
    }
1015

    
1016
    @Override
1017
    public ArgsBuilder args_names(String... args) {
1018
        ArgsBuilder x = new ArgsBuilderFromNames(args);
1019
        return x;
1020
    }
1021
    
1022
    @Override
1023
    public ArgsBuilder fixed_args_names(String... args) {
1024
        ArgsBuilder x = new FixedArgsBuilderFromNames(args);
1025
        return x;
1026
    }
1027
    
1028
    @Override
1029
    public ArgsBuilder args_expand(String... args) {
1030
        ArgsBuilder x = new ArgsBuilderExpand(args);
1031
        return x;
1032
    }
1033
    
1034
    @Override
1035
    public void code(final String id, final ArgsBuilder argsBuilder) {
1036
        this.builder(new StatementBuilderBase(id, argsBuilder));
1037
    }
1038

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

    
1055
    @Override
1056
    public String toString() {
1057
        return this.getName() + " " + StringUtils.join(this.rules, ";");
1058

    
1059
    }
1060

    
1061
    @Override
1062
    public CompoundRule repeat() {
1063
      return new RuleRepeat();
1064
    }
1065

    
1066
    @Override
1067
    public Rule fail() {
1068
      return new RuleFail();
1069
    }
1070

    
1071
    @Override
1072
    public Rule break_loop() {
1073
      return new RuleBreakLoop();
1074
    }
1075
    
1076
    @Override
1077
    public SwichTokenRule switch_token() {
1078
      return new RuleSwitchToken();
1079
    }
1080

    
1081
}