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

History | View | Annotate | Download (32.2 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

    
184
        public RuleRequireExpression() {
185
        }
186

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

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

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

    
211

    
212
    public class RuleSetExpression implements Rule {
213

    
214
        private final String id;
215
        private final Object value;
216

    
217
        public RuleSetExpression(String id, Object value) {
218
            this.id = id;
219
            this.value = value;
220
        }
221

    
222
        @Override
223
        public Rule capture_as(String... ids) {
224
          throw new UnsupportedOperationException("Unsupported operation.");
225
        }
226

    
227
        @Override
228
        public void parse(StatementContext context) {
229
            context.trace(this.toString()+".parse");
230
            if( this.value instanceof Code ) {
231
                context.setCode(id, (Code) this.value);
232
            } else {
233
                context.setCode(id, context.getCodeBuilder().constant(value));
234
            }
235
        }
236

    
237
        @Override
238
        public String toString() {
239
            return "set_expression('" + this.id + "', "+Objects.toString(value)+")";
240
        }
241
    }
242

    
243
    public class RuleRequiereExpressions implements Rule {
244

    
245
        private String id;
246
        private final String separator;
247

    
248
        public RuleRequiereExpressions(String separator) {
249
            this.separator = separator;
250
        }
251

    
252
        @Override
253
        public Rule capture_as(String... ids) {
254
          this.id = ids[0];
255
          return this;
256
        }
257
        
258
        @Override
259
        public void parse(StatementContext context) {
260
            context.trace(this.toString()+".parse");
261
            Codes codes = context.parse_expressions(this.separator);
262
            if (codes == null) {
263
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
264
            }
265
            if( this.id!=null ) {
266
              Code code;
267
              if( codes.size()==1 ) {
268
                  code = codes.get(0);
269
              } else {
270
                  code = context.getCodeBuilder().function(CodeBlockFunction.NAME, codes);
271
              }
272
              context.setCode(id, code);
273
            }
274
        }
275

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

    
282
    public abstract class AbstractConditionalRule implements ConditionalRule {
283

    
284
        protected final List<Rule> onTrueRules;
285
        protected final List<Rule> onFalseRules;
286

    
287
        public AbstractConditionalRule() {
288
            this.onTrueRules = new ArrayList<>();
289
            this.onFalseRules = new ArrayList<>();
290
        }
291

    
292
        @Override
293
        public ConditionalRule capture_as(String... ids) {
294
          throw new UnsupportedOperationException("Operation not suppted.");
295
        }
296

    
297
        protected void parseOnTrueRules(StatementContext context) {
298
            for (Rule rule : this.onTrueRules) {
299
                rule.parse(context);
300
            }
301
        }
302

    
303
        protected void parseOnFalseRules(StatementContext context) {
304
            for (Rule rule : this.onFalseRules) {
305
                rule.parse(context);
306
            }
307
        }
308

    
309
        @Override
310
        public ConditionalRule addRuleOnTrue(Rule rule) {
311
            this.onTrueRules.add(rule);
312
            return this;
313
        }
314

    
315
        @Override
316
        public ConditionalRule addRuleOnFalse(Rule rule) {
317
            this.onFalseRules.add(rule);
318
            return this;
319
        }
320

    
321
    }
322

    
323
    public class RuleOptionalAnyToken implements ConditionalRule {
324

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

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

    
336
        @Override
337
        public ConditionalRule capture_as(String... ids) {
338
          this.id = ids[0];
339
          return this;
340
        }
341
        
342
        @Override
343
        public void parse(StatementContext context) {
344
            context.trace(this.toString()+".parse");
345
            Token token = context.look_token();
346
            if (token.is(this.optional_token)) {
347
                if( this.id!=null ) {
348
                  Code code = context.getCodeBuilder().constant(token.getValue());
349
                  context.setCode(id, code);
350
                }
351
                context.next_token();
352
                for (Rule rule : this.onTrueRules) {
353
                    rule.parse(context);
354
                }
355
            } else {
356
                for (Rule rule : this.onFalseRules) {
357
                    rule.parse(context);
358
                }
359
            }
360
        }
361

    
362
        @Override
363
        public RuleOptionalAnyToken addRuleOnTrue(Rule rule) {
364
            this.onTrueRules.add(rule);
365
            return this;
366
        }
367

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

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

    
380
    public class RuleSwitchToken implements SwichTokenRule {
381

    
382
        private final List<Pair<String,Rule[]>> caseRules;
383
        private Rule[] defaultRule;
384

    
385
        public RuleSwitchToken() {
386
            this.caseRules = new ArrayList<>();
387
        }
388

    
389
        @Override
390
        public Rule capture_as(String... ids) {
391
          throw new UnsupportedOperationException("Unsupported operation.");
392
        }
393

    
394
        @Override
395
        public void parse(StatementContext context) {
396
            context.trace(this.toString()+".parse");
397
            Token token = context.look_token();
398
            for (Pair<String, Rule[]> caseRule : caseRules) {
399
              if( token.is(caseRule.getKey()) ) {
400
                context.next_token();
401
                for (Rule rule : caseRule.getValue()) {
402
                  rule.parse(context);
403
                }
404
                return;
405
              }
406
            }
407
            if( defaultRule!=null ) {
408
              for (Rule rule : defaultRule) {
409
                rule.parse(context);
410
              }
411
            }
412
        }
413

    
414
        @Override
415
        public SwichTokenRule addCase(String token, Rule... rules) {
416
            this.caseRules.add(new ImmutablePair(token,rules));
417
            return this;
418
        }
419

    
420
        @Override
421
        public SwichTokenRule addDefault(Rule... rules) {
422
            this.defaultRule = rules;
423
            return this;
424
        }
425

    
426
        @Override
427
        public String toString() {
428
            return "switch_token() rules:" + StringUtils.join(this.caseRules,",") + " default: " + defaultRule;
429
        }
430
    }
431

    
432
    public class RuleRepeatUntilAnyTokens implements RepeatRule {
433

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

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

    
443
        @Override
444
        public Rule capture_as(String... ids) {
445
          throw new UnsupportedOperationException("Operation not suppted.");
446
        }
447
        
448
        @Override
449
        public void parse(StatementContext context) {
450
            context.trace(this.toString()+".parse");
451
            String save = context.getCodeClassifier();
452
            try {
453
                this.counter = 1;
454
                while (true) {
455
                    Token token = context.look_token();
456
                    if (token.is(this.exit_tokens)) {
457
                        break;
458
                    }
459
                    context.setCodeClassifier(String.valueOf(counter).trim());
460
                    for (Rule rule : rules) {
461
                        rule.parse(context);
462
                    }
463
                    this.counter = this.counter + 1;
464
                }
465
            } finally {
466
                context.setCodeClassifier(save);
467
            }
468
        }
469

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

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

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

    
488
    public class RuleRepeat implements RepeatRule {
489

    
490
        private final List<Rule> rules;
491
        private int counter;
492

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

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

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

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

    
544
    public static class BreakLoopException extends RuntimeException {
545
      
546
    }
547
    
548
    public static class RuleBreakLoop implements Rule {
549

    
550
        public RuleBreakLoop() {
551
        }
552

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

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

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

    
570
        public static class RuleFail implements Rule {
571

    
572
        public RuleFail() {
573
        }
574

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

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

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

    
592
    public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule {
593

    
594
        private String id;
595
        private final String separator;
596

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

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

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

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

    
645
    public class RuleRequireIdentifiers implements Rule {
646

    
647
        private String id;
648
        private final String separator;
649

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

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

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

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

    
699
    public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule {
700

    
701
        private String id;
702

    
703
        public RuleOptionalLiteralString() {
704
            super();
705
        }
706

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

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

    
736
    public static class ArgsBuilderFromNames implements ArgsBuilder {
737

    
738
        protected final String[] argNames;
739

    
740
        public ArgsBuilderFromNames(String... argNames) {
741
            this.argNames = argNames;
742
        }
743

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

    
777
    public static class FixedArgsBuilderFromNames implements ArgsBuilder {
778

    
779
        protected final String[] argNames;
780

    
781
        public FixedArgsBuilderFromNames(String... argNames) {
782
            this.argNames = argNames;
783
        }
784

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

    
822
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
823

    
824
        public ArgsBuilderExpand(String... argNames) {
825
            super(argNames);
826
        }
827

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

    
853
    public static class StatementBuilderBase implements StatementBuilder {
854
        protected ArgsBuilder argsBuilder;
855
        protected String codeID;
856
        
857
        public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) {
858
            this.codeID = codeID;
859
            this.argsBuilder = argsBuilder;
860
        }
861
        
862
        @Override
863
        public String getCodeID() {
864
            return this.codeID;
865
        }
866

    
867
        @Override
868
        public ArgsBuilder getArgsBuilder() {
869
            return this.argsBuilder;
870
        }
871

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

    
907
    @Override
908
    public String getName() {
909
        return name;
910
    }
911

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

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

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

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

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

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

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

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

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

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

    
962
    @Override
963
    public CompoundRule repeat_until_any_tokens(String... tokens) {
964
        return new RuleRepeatUntilAnyTokens(tokens);
965
    }
966

    
967
    @Override
968
    public Statement addRule(Rule rule) {
969
        this.rules.add(rule);
970
        return this;
971
    }
972

    
973
    @Override
974
    public boolean isApplicable(StatementContext context) {
975
        if (this.rules.isEmpty()) {
976
            return false;
977
        }
978
        context.trace(this.getName()+".isApplicable");
979
        context.save_state();
980
        try {
981
          for (Rule rule : rules) {
982
            if( rule == null ) {
983
              continue;
984
            }
985
            if (rule instanceof IsApplicableRule) {
986
              if( !((IsApplicableRule) rule).isApplicable(context) ) {
987
                context.trace(this.getName()+".isApplicable return false");
988
                return false;
989
              }
990
            } else {
991
              rule.parse(context);
992
            }
993
          }
994
          context.trace(this.getName()+".isApplicable return true");
995
          return true;
996
        } catch(Exception ex) {
997
          context.trace(this.getName()+".isApplicable return false (error)");
998
          return false;
999
        } finally {
1000
          context.restore_state();
1001
        }
1002
    }
1003

    
1004
    @Override
1005
    public ArgsBuilder args_names(String... args) {
1006
        ArgsBuilder x = new ArgsBuilderFromNames(args);
1007
        return x;
1008
    }
1009
    
1010
    @Override
1011
    public ArgsBuilder fixed_args_names(String... args) {
1012
        ArgsBuilder x = new FixedArgsBuilderFromNames(args);
1013
        return x;
1014
    }
1015
    
1016
    @Override
1017
    public ArgsBuilder args_expand(String... args) {
1018
        ArgsBuilder x = new ArgsBuilderExpand(args);
1019
        return x;
1020
    }
1021
    
1022
    @Override
1023
    public void code(final String id, final ArgsBuilder argsBuilder) {
1024
        this.builder(new StatementBuilderBase(id, argsBuilder));
1025
    }
1026

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

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

    
1047
    }
1048

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

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

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

    
1069
}