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

History | View | Annotate | Download (40.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.Compiler;
25
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_TUPLE;
26

    
27
/**
28
 *
29
 * @author jjdelcerro
30
 */
31
public class DefaultStatement implements Statement {
32

    
33
    private final List<Rule> rules;
34
    private final String name;
35
    private StatementBuilder stmtBuilder;
36
//    private String codeId;
37
//    private ArgsBuilder argsBuilder;
38

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

    
45
        public String getClassifier();
46
    }
47

    
48
    public class RuleRequireAnyToken implements IsApplicableRule {
49

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

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

    
63
        @Override
64
        public void parse(StatementContext context) {
65
            context.trace(this.toString()+".parse");
66
            Token token = context.look_token();
67
            if (!token.is(this.required_token)) {
68
                throw new ExpressionSyntaxException(
69
                        I18N.A_XTokenX_was_expected_and_XliteralX_was_found(
70
                                StringUtils.join(this.required_token,", "),
71
                                token.getLiteral()
72
                        ),
73
                        context.getLexicalAnalyzer()
74
                );
75
            }
76
            if( this.id != null ) {
77
              Code code = context.getCodeBuilder().constant(token.getValue());
78
              context.setCode(id, code);
79
            }
80
            context.next_token();
81
        }
82

    
83
        @Override
84
        public boolean isApplicable(StatementContext context) {
85
            Token token = context.next_token();
86
            boolean r = token.is(this.required_token);
87
            context.trace(this.toString()+".isApplicable return "+r);
88
            return r;
89
        }
90

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

    
96
    }
97

    
98
    public class RuleRequireTokens implements Rule {
99

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

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

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

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

    
141
    }
142

    
143
    public class RuleRequireIdentifier implements IsApplicableRule {
144

    
145
        private String id;
146

    
147
        public RuleRequireIdentifier() {
148
        }
149

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

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

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

    
188
    public class RuleRequireLiteralString implements Rule {
189

    
190
        private String id;
191

    
192
        public RuleRequireLiteralString() {
193
        }
194

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

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

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

    
225
    public class RuleRequireExpression implements Rule {
226

    
227
        private String id;
228
        boolean allow_assignement;
229

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

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

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

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

    
258
    public class RuleOptionalExpression extends AbstractConditionalRule implements ConditionalRule {
259

    
260
        private String id;
261

    
262
        public RuleOptionalExpression() {
263
        }
264

    
265
        @Override
266
        public ConditionalRule capture_as(String... ids) {
267
          this.id = ids[0];
268
          return this;
269
        }
270

    
271
        @Override
272
        public void parse(StatementContext context) {
273
            context.trace(this.toString()+".parse");
274
            Code code = context.parse_expression(false);
275
            if (code == null) {
276
                context.setCode(id, context.getCodeBuilder().constant(null));
277
                this.parseOnFalseRules(context);
278
            } else {
279
                if( this.id!=null ) {
280
                  context.setCode(id, code);
281
                }
282
                this.parseOnTrueRules(context);
283
            }
284
        }
285

    
286
        @Override
287
        public String toString() {
288
            return "optional_expression('" + this.id + "')";
289
        }
290
    }    
291

    
292
    public class RuleSetExpression implements Rule {
293

    
294
        private final String id;
295
        private final Object value;
296

    
297
        public RuleSetExpression(String id, Object value) {
298
            this.id = id;
299
            this.value = value;
300
        }
301

    
302
        @Override
303
        public Rule capture_as(String... ids) {
304
          throw new UnsupportedOperationException("Unsupported operation.");
305
        }
306

    
307
        @Override
308
        public void parse(StatementContext context) {
309
            context.trace(this.toString()+".parse");
310
            if( this.value instanceof Code ) {
311
                context.setCode(id, (Code) this.value);
312
            } else {
313
                context.setCode(id, context.getCodeBuilder().constant(value));
314
            }
315
        }
316

    
317
        @Override
318
        public String toString() {
319
            return "set_expression('" + this.id + "', "+Objects.toString(value)+")";
320
        }
321
    }
322

    
323
    public class RuleRequiereExpressions implements Rule {
324

    
325
        private String id;
326
        private final String separator;
327
        private final String[] terminationTokens;
328
        
329

    
330
        public RuleRequiereExpressions(String separator, String... terminationTokens) {
331
            this.separator = separator;
332
            this.terminationTokens = terminationTokens;
333
        }
334

    
335
        @Override
336
        public Rule capture_as(String... ids) {
337
          this.id = ids[0];
338
          return this;
339
        }
340
        
341
        @Override
342
        public void parse(StatementContext context) {
343
            context.trace(this.toString()+".parse");
344
            Codes codes = context.parse_expressions(this.separator, this.terminationTokens);
345
            if (codes == null) {
346
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
347
            }
348
            if( this.id!=null ) {
349
              Code code;
350
              if( codes.size()==1 ) {
351
                  code = codes.get(0);
352
              } else {
353
                  code = context.getCodeBuilder().function(CodeBlockFunction.NAME, codes);
354
              }
355
              context.setCode(id, code);
356
            }
357
        }
358

    
359
        @Override
360
        public String toString() {
361
            return "require_expressions('" + this.id + "', '" + this.separator + "')";
362
        }
363
    }
364

    
365
    public abstract class AbstractConditionalRule implements ConditionalRule {
366

    
367
        protected final List<Rule> onTrueRules;
368
        protected final List<Rule> onFalseRules;
369

    
370
        public AbstractConditionalRule() {
371
            this.onTrueRules = new ArrayList<>();
372
            this.onFalseRules = new ArrayList<>();
373
        }
374

    
375
        @Override
376
        public ConditionalRule capture_as(String... ids) {
377
          throw new UnsupportedOperationException("Operation not suppted.");
378
        }
379

    
380
        protected void parseOnTrueRules(StatementContext context) {
381
            for (Rule rule : this.onTrueRules) {
382
                rule.parse(context);
383
            }
384
        }
385

    
386
        protected void parseOnFalseRules(StatementContext context) {
387
            for (Rule rule : this.onFalseRules) {
388
                rule.parse(context);
389
            }
390
        }
391

    
392
        @Override
393
        public ConditionalRule addRuleOnTrue(Rule rule) {
394
            this.onTrueRules.add(rule);
395
            return this;
396
        }
397

    
398
        @Override
399
        public ConditionalRule addRuleOnFalse(Rule rule) {
400
            this.onFalseRules.add(rule);
401
            return this;
402
        }
403

    
404
    }
405

    
406
    public class RuleOptionalAnyToken implements ConditionalRule {
407

    
408
        private final String[] optional_token;
409
        private final List<Rule> onTrueRules;
410
        private final List<Rule> onFalseRules;
411
        private String id;
412

    
413
        public RuleOptionalAnyToken(String... optional_token) {
414
            this.optional_token = optional_token;
415
            this.onTrueRules = new ArrayList<>();
416
            this.onFalseRules = new ArrayList<>();
417
        }
418

    
419
        @Override
420
        public ConditionalRule capture_as(String... ids) {
421
          this.id = ids[0];
422
          return this;
423
        }
424
        
425
        @Override
426
        public void parse(StatementContext context) {
427
            context.trace(this.toString()+".parse");
428
            Token token = context.look_token();
429
            if (token.is(this.optional_token)) {
430
                if( this.id!=null ) {
431
                  Code code = context.getCodeBuilder().constant(token.getValue());
432
                  context.setCode(id, code);
433
                }
434
                context.next_token();
435
                for (Rule rule : this.onTrueRules) {
436
                    rule.parse(context);
437
                }
438
            } else {
439
                for (Rule rule : this.onFalseRules) {
440
                    rule.parse(context);
441
                }
442
            }
443
        }
444

    
445
        @Override
446
        public RuleOptionalAnyToken addRuleOnTrue(Rule rule) {
447
            this.onTrueRules.add(rule);
448
            return this;
449
        }
450

    
451
        @Override
452
        public RuleOptionalAnyToken addRuleOnFalse(Rule rule) {
453
            this.onFalseRules.add(rule);
454
            return this;
455
        }
456

    
457
        @Override
458
        public String toString() {
459
            return "optional_token(" + StringUtils.join(this.optional_token) + ") onTrue:" + StringUtils.join(onTrueRules, ",")+", onFalse:" + StringUtils.join(onFalseRules, ",");
460
        }
461
    }
462

    
463
    public class RuleOptionalCompatibilityContains implements ConditionalRule {
464

    
465
        private final List<Rule> onTrueRules;
466
        private final List<Rule> onFalseRules;
467
        private final String compatid;
468
        private final String expected;
469
        private String id;
470

    
471
        public RuleOptionalCompatibilityContains(String compatid, String expected) {
472
            this.compatid = compatid;
473
            this.expected = expected;
474
            this.onTrueRules = new ArrayList<>();
475
            this.onFalseRules = new ArrayList<>();
476
        }
477

    
478
        @Override
479
        public ConditionalRule capture_as(String... ids) {
480
          this.id = ids[0];
481
          return this;
482
        }
483
        
484
        @Override
485
        public void parse(StatementContext context) {
486
            context.trace(this.toString()+".parse");
487
            Compiler compiler = context.getCompiler();
488
            List<Rule> theRules = this.onFalseRules;
489
            String[] values = StringUtils.split(compiler.getCompatibility(compatid), ';');
490
            if( values != null ) {
491
                for (String value : values) {
492
                    if( StringUtils.equalsIgnoreCase(value, expected) ) {
493
                        if( this.id!=null ) {
494
                            Code code = context.getCodeBuilder().constant(value);
495
                            context.setCode(id, code);
496
                        }
497
                        theRules = this.onTrueRules;
498
                        break;
499
                    }
500
                }
501
            }
502
            for (Rule rule : theRules) {
503
                rule.parse(context);
504
            }
505
        }
506

    
507
        @Override
508
        public RuleOptionalCompatibilityContains addRuleOnTrue(Rule rule) {
509
            this.onTrueRules.add(rule);
510
            return this;
511
        }
512

    
513
        @Override
514
        public RuleOptionalCompatibilityContains addRuleOnFalse(Rule rule) {
515
            this.onFalseRules.add(rule);
516
            return this;
517
        }
518

    
519
        @Override
520
        public String toString() {
521
            return "if_compatibility_contains(" + this.compatid + ", "+ this.expected + ") onTrue:" + StringUtils.join(onTrueRules, ",")+", onFalse:" + StringUtils.join(onFalseRules, ",");
522
        }
523
    }    
524
    
525
    public class RuleSwitchToken implements SwichTokenRule {
526

    
527
        private final List<Pair<String,Rule[]>> caseRules;
528
        private Rule[] defaultRule;
529

    
530
        public RuleSwitchToken() {
531
            this.caseRules = new ArrayList<>();
532
        }
533

    
534
        @Override
535
        public Rule capture_as(String... ids) {
536
          throw new UnsupportedOperationException("Unsupported operation.");
537
        }
538

    
539
        @Override
540
        public void parse(StatementContext context) {
541
            context.trace(this.toString()+".parse");
542
            Token token = context.look_token();
543
            for (Pair<String, Rule[]> caseRule : caseRules) {
544
              if( token.is(caseRule.getKey()) ) {
545
                context.next_token();
546
                for (Rule rule : caseRule.getValue()) {
547
                  rule.parse(context);
548
                }
549
                return;
550
              }
551
            }
552
            if( defaultRule!=null ) {
553
              for (Rule rule : defaultRule) {
554
                rule.parse(context);
555
              }
556
            }
557
        }
558

    
559
        @Override
560
        public SwichTokenRule addCase(String token, Rule... rules) {
561
            this.caseRules.add(new ImmutablePair(token,rules));
562
            return this;
563
        }
564

    
565
        @Override
566
        public SwichTokenRule addDefault(Rule... rules) {
567
            this.defaultRule = rules;
568
            return this;
569
        }
570

    
571
        @Override
572
        public String toString() {
573
            return "switch_token() rules:" + StringUtils.join(this.caseRules,",") + " default: " + StringUtils.join(defaultRule, ",");
574
        }
575
    }
576

    
577
    public class RuleRepeatUntilAnyTokens implements RepeatRule {
578

    
579
        private final String[] exit_tokens;
580
        private final List<Rule> rules;
581
        private int counter;
582

    
583
        public RuleRepeatUntilAnyTokens(String[] exit_tokens) {
584
            this.exit_tokens = exit_tokens;
585
            this.rules = new ArrayList<>();
586
        }
587

    
588
        @Override
589
        public Rule capture_as(String... ids) {
590
          throw new UnsupportedOperationException("Operation not suppted.");
591
        }
592
        
593
        @Override
594
        public void parse(StatementContext context) {
595
            context.trace(this.toString()+".parse");
596
            String save = context.getCodeClassifier();
597
            try {
598
                this.counter = 1;
599
                while (true) {
600
                    Token token = context.look_token();
601
                    if (token.is(this.exit_tokens)) {
602
                        break;
603
                    }
604
                    context.setCodeClassifier(String.valueOf(counter).trim());
605
                    context.setOtherValues(counter);
606
                    for (Rule rule : rules) {
607
                        rule.parse(context);
608
                    }
609
                    this.counter = (int) context.getOtherValues();
610
                    this.counter = this.counter + 1;
611
                }
612
            } finally {
613
                context.setCodeClassifier(save);
614
            }
615
        }
616

    
617
        @Override
618
        public RuleRepeatUntilAnyTokens addRule(Rule rule) {
619
            this.rules.add(rule);
620
            return this;
621
        }
622

    
623
        @Override
624
        public String getClassifier() {
625
            String s = String.valueOf(counter).trim();
626
            return s;
627
        }
628

    
629
        @Override
630
        public String toString() {
631
            return "repeat_until_tokens('" + ArrayUtils.toString(this.exit_tokens) + "') rules:" + StringUtils.join(rules, ",");
632
        }
633
    }
634

    
635
    public class RuleRepeat implements RepeatRule {
636

    
637
        private final List<Rule> rules;
638
        private int counter;
639

    
640
        public RuleRepeat() {
641
            this.rules = new ArrayList<>();
642
        }
643
        
644
        @Override
645
        public Rule capture_as(String... ids) {
646
          throw new UnsupportedOperationException("Operation not suppted.");
647
        }
648
        
649
        @Override
650
        public void parse(StatementContext context) {
651
            context.trace(this.toString()+".parse");
652
            String saveCodeClassifier = context.getCodeClassifier();
653
            try {
654
                this.counter = 1;
655
                boolean breakloop = false;
656
                while (!breakloop) {
657
                    context.setCodeClassifier(String.valueOf(counter).trim());
658
                    context.setOtherValues(counter);
659
                    for (Rule rule : rules) {
660
                      try {
661
                        rule.parse(context);
662
                      } catch(BreakLoopException ex) {
663
                        breakloop = true;
664
                        break;
665
                      }
666
                    }
667
                    this.counter = (int) context.getOtherValues();
668
                    this.counter = this.counter + 1;
669
                }
670
            } finally {
671
                context.setCodeClassifier(saveCodeClassifier);
672
            }
673
        }
674

    
675
        @Override
676
        public RuleRepeat addRule(Rule rule) {
677
            this.rules.add(rule);
678
            return this;
679
        }
680

    
681
        @Override
682
        public String getClassifier() {
683
            String s = String.valueOf(counter).trim();
684
            return s;
685
        }
686

    
687
        @Override
688
        public String toString() {
689
            return "repeat() rules:" + StringUtils.join(rules, ",");
690
        }
691
    }
692

    
693
    public static class BreakLoopException extends RuntimeException {
694
      
695
    }
696
    
697
    public static class RuleBreakLoop implements Rule {
698

    
699
        public RuleBreakLoop() {
700
        }
701

    
702
        @Override
703
        public Rule capture_as(String... ids) {
704
          throw new UnsupportedOperationException("Operation not suppted.");
705
        }
706

    
707
        @Override
708
        public void parse(StatementContext context) {
709
          context.trace(this.toString()+".parse");
710
          throw new BreakLoopException();
711
        }
712

    
713
        @Override
714
        public String toString() {
715
            return "break_loop()";
716
        }
717
    }
718

    
719
        public static class RuleFail implements Rule {
720

    
721
        public RuleFail() {
722
        }
723

    
724
        @Override
725
        public Rule capture_as(String... ids) {
726
          throw new UnsupportedOperationException("Operation not suppted.");
727
        }
728

    
729
        @Override
730
        public void parse(StatementContext context) {
731
          context.trace(this.toString()+".parse");
732
          throw new ExpressionSyntaxException();
733
        }
734

    
735
        @Override
736
        public String toString() {
737
            return "fail()";
738
        }
739
    }
740

    
741
    public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule {
742

    
743
        private String id;
744
        private final String separator;
745

    
746
        public RuleOptionalIdentifiers(String separator) {
747
            super();
748
            this.separator = separator;
749
        }
750

    
751
        @Override
752
        public ConditionalRule capture_as(String... ids) {
753
          this.id = ids[0];
754
          return this;
755
        }
756

    
757
        @Override
758
        public void parse(StatementContext context) {
759
            context.trace(this.toString()+".parse");
760
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
761
            Token token = context.look_token();
762
            while (token.getType() == Token.IDENTIFIER) {
763
                String identifier = (String) token.getLiteral();
764
                if( context.isReservedWord(identifier) ) {
765
                    break;
766
                }
767
                Code code = context.getCodeBuilder().constant(identifier);
768
                args.add(code);
769
                context.next_token();
770
                token = context.look_token();
771
                if (!token.is(this.separator)) {
772
                    break;
773
                }
774
                context.next_token();
775
                token = context.look_token();
776
            }
777
            if (args.size() != 0) {
778
              if( this.id!=null ) {
779
                Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
780
                context.setCode(id, code);
781
              }
782
              this.parseOnTrueRules(context);
783
            } else {
784
                this.parseOnFalseRules(context);
785
            }
786
        }
787

    
788
        @Override
789
        public String toString() {
790
            return "optional_identifiers('" + id + "', '" + this.separator + "')";
791
        }
792
    }
793

    
794
    public class RuleRequireIdentifiers implements Rule {
795

    
796
        private String id;
797
        private final String separator;
798

    
799
        public RuleRequireIdentifiers(String separator) {
800
            super();
801
            this.separator = separator;
802
        }
803

    
804
        @Override
805
        public Rule capture_as(String... ids) {
806
          this.id = ids[0];
807
          return this;
808
        }
809

    
810
        @Override
811
        public void parse(StatementContext context) {
812
            context.trace(this.toString()+".parse");
813
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
814
            Token token = context.look_token();
815
            while (token.getType() == Token.IDENTIFIER) {
816
                String identifier = (String) token.getLiteral();
817
                if( context.isReservedWord(identifier) ) {
818
                    break;
819
                }
820
                Code code = context.getCodeBuilder().identifier(identifier);
821
                args.add(code);
822
                context.next_token();
823
                token = context.look_token();
824
                if (!token.is(this.separator)) {
825
                    break;
826
                }
827
                context.next_token();
828
                token = context.look_token();
829
            }
830
            if (args.size() == 0) {
831
                throw new ExpressionSyntaxException(
832
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
833
                        context.getLexicalAnalyzer()
834
                );
835
            }
836
            if( this.id!=null ) {
837
              Code code = context.getCodeBuilder().function(FUNCTION_TUPLE, args);
838
              context.setCode(id, code);
839
            }
840
        }
841

    
842
        @Override
843
        public String toString() {
844
            return "require_identifiers('" + id + "', '" + this.separator + "')";
845
        }
846
    }
847

    
848
    public class RuleRequireIdentifiersAsString implements Rule {
849

    
850
        private String id;
851
        private final String separator;
852

    
853
        public RuleRequireIdentifiersAsString(String separator) {
854
            super();
855
            this.separator = separator;
856
        }
857

    
858
        @Override
859
        public Rule capture_as(String... ids) {
860
          this.id = ids[0];
861
          return this;
862
        }
863

    
864
        @Override
865
        public void parse(StatementContext context) {
866
            context.trace(this.toString()+".parse");
867
            StringBuilder sb = new StringBuilder();
868
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
869
            Token token = context.look_token();
870
            while (token.getType() == Token.IDENTIFIER) {
871
                String identifier = (String) token.getLiteral();
872
                if( context.isReservedWord(identifier) ) {
873
                    break;
874
                }
875
                if( sb.length()>0 ) {
876
                    sb.append(this.separator);
877
                }
878
                sb.append(identifier);
879
                context.next_token();
880
                token = context.look_token();
881
                if (!token.is(this.separator)) {
882
                    break;
883
                }
884
                context.next_token();
885
                token = context.look_token();
886
            }
887
            if ( StringUtils.isBlank(sb) ) {
888
                throw new ExpressionSyntaxException(
889
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
890
                        context.getLexicalAnalyzer()
891
                );
892
            }
893
            if( this.id!=null ) {
894
              Code code = context.getCodeBuilder().constant(sb.toString());
895
              context.setCode(id, code);
896
            }
897
        }
898

    
899
        @Override
900
        public String toString() {
901
            return "require_identifiers('" + id + "', '" + this.separator + "')";
902
        }
903
    }
904

    
905
    public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule {
906

    
907
        private String id;
908

    
909
        public RuleOptionalLiteralString() {
910
            super();
911
        }
912

    
913
        @Override
914
        public ConditionalRule capture_as(String... ids) {
915
          this.id = ids[0];
916
          return this;
917
        }
918
        
919
        @Override
920
        public void parse(StatementContext context) {
921
            context.trace(this.toString()+".parse");
922
            Token token = context.look_token();
923
            if (token.getType() == Token.STRING_LITERAL) {
924
                if( this.id!=null ) {
925
                  String s = (String) token.getValue();
926
                  Code code = context.getCodeBuilder().constant(s);
927
                  context.setCode(id, code);
928
                  context.next_token();
929
                }
930
                this.parseOnTrueRules(context);
931
            } else {
932
                this.parseOnFalseRules(context);
933
            }
934
        }
935

    
936
        @Override
937
        public String toString() {
938
            return "optional_literal_string('" + id + "')";
939
        }
940
    }
941

    
942
    public static class ArgsBuilderFromNames implements ArgsBuilder {
943

    
944
        protected final String[] argNames;
945

    
946
        public ArgsBuilderFromNames(String... argNames) {
947
            this.argNames = argNames;
948
        }
949

    
950
        @Override
951
        public String toString() {
952
          return "args_names("+StringUtils.join(argNames,",")+")";
953
        }
954
        
955
        @Override
956
        public Codes build(StatementContext context) {
957
            context.trace(this.toString()+".build");
958
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
959
            if( argNames != null ) {
960
                for (String argName : argNames) {
961
                    if (argName.contains("#")) {
962
                        Code code = context.getCode(argName);
963
                        if (code == null) {
964
                            int n = 1;
965
                            while (true) {
966
                                String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
967
                                code = context.getCode(argNameX);
968
                                if (code == null) {
969
                                    break;
970
                                }
971
                                args.add(code);
972
                                n++;
973
                            }
974
                        } else {
975
                            args.add(code);
976
                        }
977
                    } else {
978
                        Code code = context.getCode(argName);
979
    //                    if( code == null) {
980
    //                        code = context.getCodeBuilder().constant(null);
981
    //                    }
982
                        args.add(code);
983
                    }
984
                }
985
            }
986
            return args;
987
        }
988
    }
989

    
990
    public static class FixedArgsBuilderFromNames implements ArgsBuilder {
991

    
992
        protected final String[] argNames;
993

    
994
        public FixedArgsBuilderFromNames(String... argNames) {
995
            this.argNames = argNames;
996
        }
997

    
998
        @Override
999
        public String toString() {
1000
          return "fixed_args_names("+StringUtils.join(argNames,",")+")";
1001
        }
1002
        
1003
        @Override
1004
        public Codes build(StatementContext context) {
1005
            context.trace(this.toString()+".build");
1006
            CodeBuilder codeBuilder = context.getCodeBuilder();
1007
            BaseCodes args = (BaseCodes) codeBuilder.args();
1008
            if( argNames != null ) {
1009
                for (String argName : argNames) {
1010
                    if (argName.contains("#")) {
1011
                        int n = 1;
1012
                        BaseCodes argsX = (BaseCodes) codeBuilder.args();
1013
                        while (true) {
1014
                            String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
1015
                            Code code = context.getCode(argNameX);
1016
                            if (code == null) {
1017
                                break;
1018
                            }
1019
                            argsX.add(code);
1020
                            n++;
1021
                        }
1022

    
1023
                        args.add(codeBuilder.tuple(argsX));
1024
                    } else {
1025
                        Code code = context.getCode(argName);
1026
                        if( code == null) {
1027
                            code = context.getCodeBuilder().constant(null);
1028
                        }
1029
                        args.add(code);
1030
                    }
1031
                }
1032
            }
1033
            return args;
1034
        }
1035
    }
1036

    
1037
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
1038

    
1039
        public ArgsBuilderExpand(String... argNames) {
1040
            super(argNames);
1041
        }
1042

    
1043
        @Override
1044
        public String toString() {
1045
          return "args_expand("+StringUtils.join(argNames,",")+")";
1046
        }
1047
        
1048
        @Override
1049
        public Codes build(StatementContext context) {
1050
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
1051
            
1052
            Codes base_args = super.build(context);
1053
            for (Code arg : base_args) {
1054
                if( arg.code() == Code.CALLABLE && 
1055
                    ((Callable)arg).name().equals(CodeBlockFunction.NAME) ) {
1056
                    Codes block_args = ((Callable)arg).parameters();
1057
                    for (Code block_arg : block_args) {
1058
                        args.add(block_arg);
1059
                    }
1060
                } else {
1061
                    args.add(arg);
1062
                }
1063
            }
1064
            return args;
1065
        }
1066
    }
1067

    
1068
    public static class StatementBuilderBase implements StatementBuilder {
1069
        protected ArgsBuilder argsBuilder;
1070
        protected String codeID;
1071
        
1072
        public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) {
1073
            this.codeID = codeID;
1074
            this.argsBuilder = argsBuilder;
1075
        }
1076
        
1077
        @Override
1078
        public String getCodeID() {
1079
            return this.codeID;
1080
        }
1081

    
1082
        @Override
1083
        public ArgsBuilder getArgsBuilder() {
1084
            return this.argsBuilder;
1085
        }
1086

    
1087
        @Override
1088
        public Code build(StatementContext context) {
1089
            Codes args = this.getArgsBuilder().build(context);
1090
            Code code = null;
1091
            if (this.getCodeID() == null) {
1092
                code = args.get(0);
1093
            } else {
1094
                if (args.size() == 0) {
1095
                    code = context.getCodeBuilder().function(this.getCodeID(), null);
1096
                } else {
1097
                    // Si es un bloque dentro de otro, dejamos solo uno.
1098
                    if( args.size()==1 && 
1099
                        StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,this.getCodeID()) ) {
1100
                        Code code0 = args.get(0);
1101
                        if( code0.code() == Code.CALLABLE && 
1102
                                StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Callable)code0).name())
1103
                                ) {
1104
                            code = code0;
1105
                        }
1106
                    }
1107
                    if( code == null ) {
1108
                        code = context.getCodeBuilder().function(this.getCodeID(), args);
1109
                    }
1110
                }
1111
            }
1112
            return code;
1113
        }
1114
    }
1115

    
1116
    
1117
    public DefaultStatement(String name) {
1118
        this.rules = new ArrayList<>();
1119
        this.stmtBuilder = null;
1120
        this.name = name;
1121
    }
1122

    
1123
    @Override
1124
    public String getName() {
1125
        return name;
1126
    }
1127

    
1128
    @Override
1129
    public Rule require_any_token(String... token) {
1130
        return new RuleRequireAnyToken(token);
1131
    }
1132

    
1133
    @Override
1134
    public Rule require_tokens(String... token) {
1135
        return new RuleRequireTokens(token);
1136
    }
1137

    
1138
    @Override
1139
    public Rule require_identifier() {
1140
        return new RuleRequireIdentifier();
1141
    }
1142

    
1143
    @Override
1144
    public Rule require_identifiers(String sep) {
1145
        return new RuleRequireIdentifiers(sep);
1146
    }
1147

    
1148
    @Override
1149
    public Rule require_identifiers_as_string(String sep) {
1150
        return new RuleRequireIdentifiersAsString(sep);
1151
    }
1152

    
1153
    @Override
1154
    public Rule require_literal_string() {
1155
        return new RuleRequireLiteralString();
1156
    }
1157

    
1158
    @Override
1159
    public Rule set_expression(String id, Object value) {
1160
        return new RuleSetExpression(id, value);
1161
    }
1162

    
1163
    @Override
1164
    public Rule require_expression() {
1165
        return this.require_expression(true);
1166
    }
1167

    
1168
    @Override
1169
    public Rule require_expression(boolean allow_assignement) {
1170
        return new RuleRequireExpression(allow_assignement);
1171
    }
1172

    
1173
    @Override
1174
    public ConditionalRule optional_expression() {
1175
        return new RuleOptionalExpression();
1176
    }
1177

    
1178
    @Override
1179
    public Rule require_expressions(String separator) {
1180
        return new RuleRequiereExpressions(separator, null);
1181
    }
1182

    
1183
    @Override
1184
    public Rule require_expressions(String separator, String...terminationTokens) {
1185
        return new RuleRequiereExpressions(separator,terminationTokens);
1186
    }
1187

    
1188
    @Override
1189
    public ConditionalRule optional_any_token(String... id) {
1190
        return new RuleOptionalAnyToken(id);
1191
    }
1192

    
1193
    @Override
1194
    public ConditionalRule if_compatibility_contains(String compatid, String expected) {
1195
        return new RuleOptionalCompatibilityContains(compatid, expected);
1196
    }
1197

    
1198
    @Override
1199
    public ConditionalRule optional_identifiers(String separator) {
1200
        return new RuleOptionalIdentifiers(separator);
1201
    }
1202

    
1203
    @Override
1204
    public ConditionalRule optional_literal_string() {
1205
        return new RuleOptionalLiteralString();
1206
    }
1207

    
1208
    @Override
1209
    public CompoundRule repeat_until_any_tokens(String... tokens) {
1210
        return new RuleRepeatUntilAnyTokens(tokens);
1211
    }
1212

    
1213
    @Override
1214
    public Statement addRule(Rule rule) {
1215
        this.rules.add(rule);
1216
        return this;
1217
    }
1218

    
1219
    @Override
1220
    public boolean isApplicable(StatementContext context) {
1221
        if (this.rules.isEmpty()) {
1222
            return false;
1223
        }
1224
        context.trace(this.getName()+".isApplicable");
1225
        context.save_state();
1226
        try {
1227
          for (Rule rule : rules) {
1228
            if( rule == null ) {
1229
              continue;
1230
            }
1231
            if (rule instanceof IsApplicableRule) {
1232
              if( !((IsApplicableRule) rule).isApplicable(context) ) {
1233
                context.trace(this.getName()+".isApplicable return false");
1234
                return false;
1235
              }
1236
            } else {
1237
              rule.parse(context);
1238
            }
1239
          }
1240
          context.trace(this.getName()+".isApplicable return true");
1241
          return true;
1242
        } catch(Exception ex) {
1243
          context.trace(this.getName()+".isApplicable return false (error)");
1244
          return false;
1245
        } finally {
1246
          context.restore_state();
1247
        }
1248
    }
1249

    
1250
    @Override
1251
    public ArgsBuilder args_names(String... args) {
1252
        ArgsBuilder x = new ArgsBuilderFromNames(args);
1253
        return x;
1254
    }
1255
    
1256
    @Override
1257
    public ArgsBuilder fixed_args_names(String... args) {
1258
        ArgsBuilder x = new FixedArgsBuilderFromNames(args);
1259
        return x;
1260
    }
1261
    
1262
    @Override
1263
    public ArgsBuilder args_expand(String... args) {
1264
        ArgsBuilder x = new ArgsBuilderExpand(args);
1265
        return x;
1266
    }
1267
    
1268
    @Override
1269
    public void code(final String id, final ArgsBuilder argsBuilder) {
1270
        this.builder(new StatementBuilderBase(id, argsBuilder));
1271
    }
1272

    
1273
    @Override
1274
    public void builder(StatementBuilder builder) {
1275
        this.stmtBuilder = builder;
1276
    }
1277
    
1278
    @Override
1279
    public Code parse(StatementContext context) {
1280
        context.trace(this.getName()+".parse");
1281
        for (Rule rule : rules) {
1282
            rule.parse(context);
1283
        }
1284
        Code code = this.stmtBuilder.build(context);
1285
        context.trace(this.getName()+".return "+code);
1286
        return code;
1287
    }
1288

    
1289
    @Override
1290
    public String toString() {
1291
        return this.getName() + " " + StringUtils.join(this.rules, ";");
1292

    
1293
    }
1294

    
1295
    @Override
1296
    public CompoundRule repeat() {
1297
      return new RuleRepeat();
1298
    }
1299

    
1300
    @Override
1301
    public Rule fail() {
1302
      return new RuleFail();
1303
    }
1304

    
1305
    @Override
1306
    public Rule break_loop() {
1307
      return new RuleBreakLoop();
1308
    }
1309
    
1310
    @Override
1311
    public SwichTokenRule switch_token() {
1312
      return new RuleSwitchToken();
1313
    }
1314

    
1315
}