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

History | View | Annotate | Download (32 KB)

1 44139 jjdelcerro
package org.gvsig.expressionevaluator.impl;
2
3
import java.util.ArrayList;
4
import java.util.List;
5 44379 jjdelcerro
import java.util.Objects;
6 44139 jjdelcerro
import org.apache.commons.lang3.ArrayUtils;
7
import org.apache.commons.lang3.StringUtils;
8 44738 jjdelcerro
import org.apache.commons.lang3.tuple.ImmutablePair;
9
import org.apache.commons.lang3.tuple.Pair;
10 44139 jjdelcerro
import org.gvsig.expressionevaluator.Code;
11
import org.gvsig.expressionevaluator.Code.Caller;
12 44750 jjdelcerro
import org.gvsig.expressionevaluator.CodeBuilder;
13 44139 jjdelcerro
import org.gvsig.expressionevaluator.Codes;
14 44262 jjdelcerro
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_LIST;
15 44139 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
16
import org.gvsig.expressionevaluator.LexicalAnalyzer.Token;
17
import org.gvsig.expressionevaluator.Statement;
18
import org.gvsig.expressionevaluator.Statement.CompoundRule;
19
import org.gvsig.expressionevaluator.Statement.ConditionalRule;
20
import org.gvsig.expressionevaluator.Statement.Rule;
21
import org.gvsig.expressionevaluator.Statement.StatementContext;
22
import org.gvsig.expressionevaluator.impl.function.programming.CodeBlockFunction;
23
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseCodes;
24
25
/**
26
 *
27
 * @author jjdelcerro
28
 */
29
public class DefaultStatement implements Statement {
30
31
    private final List<Rule> rules;
32
    private final String name;
33 44384 jjdelcerro
    private StatementBuilder stmtBuilder;
34
//    private String codeId;
35
//    private ArgsBuilder argsBuilder;
36 44139 jjdelcerro
37 44738 jjdelcerro
    public interface IsApplicableRule extends Rule {
38
      public boolean isApplicable(StatementContext context);
39
    }
40
41 44139 jjdelcerro
    public interface RepeatRule extends CompoundRule {
42
43
        public String getClassifier();
44
    }
45
46 44738 jjdelcerro
    public class RuleRequireAnyToken implements IsApplicableRule {
47 44139 jjdelcerro
48
        private final String[] required_token;
49 44750 jjdelcerro
        private String id;
50 44139 jjdelcerro
51 44144 jjdelcerro
        public RuleRequireAnyToken(String... required_token) {
52 44139 jjdelcerro
            this.required_token = required_token;
53
        }
54 44750 jjdelcerro
55
        @Override
56
        public RuleRequireAnyToken capture_as(String... ids) {
57
          this.id = ids[0];
58
          return this;
59
        }
60 44139 jjdelcerro
61 44379 jjdelcerro
        @Override
62 44139 jjdelcerro
        public void parse(StatementContext context) {
63 44738 jjdelcerro
            context.trace(this.toString()+".parse");
64 44139 jjdelcerro
            Token token = context.look_token();
65
            if (!token.is(this.required_token)) {
66
                throw new ExpressionSyntaxException(
67
                        I18N.A_XTokenX_was_expected_and_XliteralX_was_found(
68 44384 jjdelcerro
                                StringUtils.join(this.required_token,", "),
69 44139 jjdelcerro
                                token.getLiteral()
70
                        ),
71
                        context.getLexicalAnalyzer()
72
                );
73
            }
74 44750 jjdelcerro
            if( this.id != null ) {
75
              Code code = context.getCodeBuilder().constant(token.getValue());
76
              context.setCode(id, code);
77
            }
78 44139 jjdelcerro
            context.next_token();
79
        }
80
81 44738 jjdelcerro
        @Override
82
        public boolean isApplicable(StatementContext context) {
83
            Token token = context.next_token();
84
            boolean r = token.is(this.required_token);
85
            context.trace(this.toString()+".isApplicable return "+r);
86
            return r;
87 44139 jjdelcerro
        }
88
89
        @Override
90
        public String toString() {
91
            return "require_token(" + StringUtils.join(this.required_token) + ")";
92
        }
93
94
    }
95
96 44738 jjdelcerro
    public class RuleRequireIdentifier implements IsApplicableRule {
97 44139 jjdelcerro
98 44750 jjdelcerro
        private String id;
99 44139 jjdelcerro
100 44750 jjdelcerro
        public RuleRequireIdentifier() {
101 44139 jjdelcerro
        }
102
103 44379 jjdelcerro
        @Override
104 44750 jjdelcerro
        public Rule capture_as(String... ids) {
105
          this.id = ids[0];
106
          return this;
107
        }
108
109
        @Override
110 44139 jjdelcerro
        public void parse(StatementContext context) {
111 44738 jjdelcerro
            context.trace(this.toString()+".parse");
112 44139 jjdelcerro
            Token token = context.look_token();
113
            if (token.getType() != Token.IDENTIFIER) {
114
                throw new ExpressionSyntaxException(
115
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
116
                        context.getLexicalAnalyzer()
117
                );
118
            }
119 44750 jjdelcerro
            if( this.id!=null ) {
120
              String identifier = (String) token.getLiteral();
121
              Code code = context.getCodeBuilder().constant(identifier);
122
              context.setCode(id, code);
123
            }
124 44139 jjdelcerro
            context.next_token();
125
        }
126
127
        @Override
128 44738 jjdelcerro
        public boolean isApplicable(StatementContext context) {
129
            Token token = context.next_token();
130
            boolean r = token.getType() == Token.IDENTIFIER;
131
            context.trace(this.toString()+".isApplicable return "+r);
132
            return r;
133
        }
134
135
        @Override
136 44139 jjdelcerro
        public String toString() {
137
            return "require_identifier('" + this.id + "')";
138
        }
139
    }
140
141 44533 jjdelcerro
    public class RuleRequireLiteralString implements Rule {
142
143 44750 jjdelcerro
        private String id;
144 44533 jjdelcerro
145 44750 jjdelcerro
        public RuleRequireLiteralString() {
146 44533 jjdelcerro
        }
147
148
        @Override
149 44750 jjdelcerro
        public Rule capture_as(String... ids) {
150
          this.id = ids[0];
151
          return this;
152
        }
153
154
        @Override
155 44533 jjdelcerro
        public void parse(StatementContext context) {
156 44738 jjdelcerro
            context.trace(this.toString()+".parse");
157 44533 jjdelcerro
            Token token = context.look_token();
158
            if (token.getType() != Token.STRING_LITERAL) {
159
                throw new ExpressionSyntaxException(
160
                        I18N.A_string_literal_was_expected(),
161
                        context.getLexicalAnalyzer()
162
                );
163
            }
164 44750 jjdelcerro
            if( this.id!=null ) {
165
              String identifier = (String) token.getValue();
166
              Code code = context.getCodeBuilder().constant(identifier);
167
              context.setCode(id, code);
168
              context.next_token();
169
            }
170 44533 jjdelcerro
        }
171
172
        @Override
173
        public String toString() {
174
            return "require_literal_string('" + this.id + "')";
175
        }
176
    }
177
178 44139 jjdelcerro
    public class RuleRequireExpression implements Rule {
179
180 44750 jjdelcerro
        private String id;
181 44139 jjdelcerro
182 44750 jjdelcerro
        public RuleRequireExpression() {
183 44139 jjdelcerro
        }
184
185 44379 jjdelcerro
        @Override
186 44750 jjdelcerro
        public Rule capture_as(String... ids) {
187
          this.id = ids[0];
188
          return this;
189
        }
190
191
        @Override
192 44139 jjdelcerro
        public void parse(StatementContext context) {
193 44738 jjdelcerro
            context.trace(this.toString()+".parse");
194 44139 jjdelcerro
            Code code = context.parse_expression();
195
            if (code == null) {
196
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
197
            }
198 44750 jjdelcerro
            if( this.id!=null ) {
199
              context.setCode(id, code);
200
            }
201 44139 jjdelcerro
        }
202
203
        @Override
204
        public String toString() {
205
            return "require_expression('" + this.id + "')";
206
        }
207
    }
208
209 44379 jjdelcerro
210
    public class RuleSetExpression implements Rule {
211
212
        private final String id;
213
        private final Object value;
214
215
        public RuleSetExpression(String id, Object value) {
216
            this.id = id;
217
            this.value = value;
218
        }
219
220
        @Override
221 44750 jjdelcerro
        public Rule capture_as(String... ids) {
222
          throw new UnsupportedOperationException("Unsupported operation.");
223
        }
224
225
        @Override
226 44379 jjdelcerro
        public void parse(StatementContext context) {
227 44738 jjdelcerro
            context.trace(this.toString()+".parse");
228 44379 jjdelcerro
            if( this.value instanceof Code ) {
229
                context.setCode(id, (Code) this.value);
230
            } else {
231
                context.setCode(id, context.getCodeBuilder().constant(value));
232
            }
233
        }
234
235
        @Override
236
        public String toString() {
237
            return "set_expression('" + this.id + "', "+Objects.toString(value)+")";
238
        }
239
    }
240
241 44139 jjdelcerro
    public class RuleRequiereExpressions implements Rule {
242
243 44750 jjdelcerro
        private String id;
244 44139 jjdelcerro
        private final String separator;
245
246 44750 jjdelcerro
        public RuleRequiereExpressions(String separator) {
247 44139 jjdelcerro
            this.separator = separator;
248
        }
249
250 44379 jjdelcerro
        @Override
251 44750 jjdelcerro
        public Rule capture_as(String... ids) {
252
          this.id = ids[0];
253
          return this;
254
        }
255
256
        @Override
257 44139 jjdelcerro
        public void parse(StatementContext context) {
258 44738 jjdelcerro
            context.trace(this.toString()+".parse");
259 44139 jjdelcerro
            Codes codes = context.parse_expressions(this.separator);
260
            if (codes == null) {
261
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
262
            }
263 44750 jjdelcerro
            if( this.id!=null ) {
264
              Code code;
265
              if( codes.size()==1 ) {
266
                  code = codes.get(0);
267
              } else {
268
                  code = context.getCodeBuilder().function(CodeBlockFunction.NAME, codes);
269
              }
270
              context.setCode(id, code);
271 44379 jjdelcerro
            }
272 44139 jjdelcerro
        }
273
274
        @Override
275
        public String toString() {
276
            return "require_expressions('" + this.id + "', '" + this.separator + "')";
277
        }
278
    }
279
280 44533 jjdelcerro
    public abstract class AbstractConditionalRule implements ConditionalRule {
281
282
        protected final List<Rule> onTrueRules;
283
        protected final List<Rule> onFalseRules;
284
285
        public AbstractConditionalRule() {
286
            this.onTrueRules = new ArrayList<>();
287
            this.onFalseRules = new ArrayList<>();
288
        }
289
290 44750 jjdelcerro
        @Override
291
        public ConditionalRule capture_as(String... ids) {
292
          throw new UnsupportedOperationException("Operation not suppted.");
293
        }
294
295 44533 jjdelcerro
        protected void parseOnTrueRules(StatementContext context) {
296
            for (Rule rule : this.onTrueRules) {
297
                rule.parse(context);
298
            }
299
        }
300
301
        protected void parseOnFalseRules(StatementContext context) {
302
            for (Rule rule : this.onFalseRules) {
303
                rule.parse(context);
304
            }
305
        }
306
307
        @Override
308
        public ConditionalRule addRuleOnTrue(Rule rule) {
309
            this.onTrueRules.add(rule);
310
            return this;
311
        }
312
313
        @Override
314
        public ConditionalRule addRuleOnFalse(Rule rule) {
315
            this.onFalseRules.add(rule);
316
            return this;
317
        }
318
319
    }
320
321 44144 jjdelcerro
    public class RuleOptionalAnyToken implements ConditionalRule {
322 44139 jjdelcerro
323
        private final String[] optional_token;
324
        private final List<Rule> onTrueRules;
325
        private final List<Rule> onFalseRules;
326 44750 jjdelcerro
        private String id;
327 44139 jjdelcerro
328 44144 jjdelcerro
        public RuleOptionalAnyToken(String... optional_token) {
329 44139 jjdelcerro
            this.optional_token = optional_token;
330
            this.onTrueRules = new ArrayList<>();
331
            this.onFalseRules = new ArrayList<>();
332
        }
333
334 44379 jjdelcerro
        @Override
335 44750 jjdelcerro
        public ConditionalRule capture_as(String... ids) {
336
          this.id = ids[0];
337
          return this;
338
        }
339
340
        @Override
341 44139 jjdelcerro
        public void parse(StatementContext context) {
342 44738 jjdelcerro
            context.trace(this.toString()+".parse");
343 44139 jjdelcerro
            Token token = context.look_token();
344
            if (token.is(this.optional_token)) {
345 44750 jjdelcerro
                if( this.id!=null ) {
346
                  Code code = context.getCodeBuilder().constant(token.getValue());
347
                  context.setCode(id, code);
348
                }
349 44139 jjdelcerro
                context.next_token();
350
                for (Rule rule : this.onTrueRules) {
351
                    rule.parse(context);
352
                }
353
            } else {
354
                for (Rule rule : this.onFalseRules) {
355
                    rule.parse(context);
356
                }
357
            }
358
        }
359
360 44379 jjdelcerro
        @Override
361 44144 jjdelcerro
        public RuleOptionalAnyToken addRuleOnTrue(Rule rule) {
362 44139 jjdelcerro
            this.onTrueRules.add(rule);
363
            return this;
364
        }
365
366 44379 jjdelcerro
        @Override
367 44144 jjdelcerro
        public RuleOptionalAnyToken addRuleOnFalse(Rule rule) {
368 44139 jjdelcerro
            this.onFalseRules.add(rule);
369
            return this;
370
        }
371
372
        @Override
373
        public String toString() {
374 44738 jjdelcerro
            return "optional_token(" + StringUtils.join(this.optional_token) + ") onTrue:" + StringUtils.join(onTrueRules, ",")+", onFalse:" + StringUtils.join(onFalseRules, ",");
375 44139 jjdelcerro
        }
376
    }
377
378 44738 jjdelcerro
    public class RuleSwitchToken implements SwichTokenRule {
379
380
        private final List<Pair<String,Rule[]>> caseRules;
381
        private Rule[] defaultRule;
382
383
        public RuleSwitchToken() {
384
            this.caseRules = new ArrayList<>();
385
        }
386
387
        @Override
388 44750 jjdelcerro
        public Rule capture_as(String... ids) {
389
          throw new UnsupportedOperationException("Unsupported operation.");
390
        }
391
392
        @Override
393 44738 jjdelcerro
        public void parse(StatementContext context) {
394
            context.trace(this.toString()+".parse");
395
            Token token = context.look_token();
396
            for (Pair<String, Rule[]> caseRule : caseRules) {
397
              if( token.is(caseRule.getKey()) ) {
398
                context.next_token();
399
                for (Rule rule : caseRule.getValue()) {
400
                  rule.parse(context);
401
                }
402
                return;
403
              }
404
            }
405
            if( defaultRule!=null ) {
406
              for (Rule rule : defaultRule) {
407
                rule.parse(context);
408
              }
409
            }
410
        }
411
412
        @Override
413
        public SwichTokenRule addCase(String token, Rule... rules) {
414
            this.caseRules.add(new ImmutablePair(token,rules));
415
            return this;
416
        }
417
418
        @Override
419
        public SwichTokenRule addDefault(Rule... rules) {
420
            this.defaultRule = rules;
421
            return this;
422
        }
423
424
        @Override
425
        public String toString() {
426
            return "switch_token() rules:" + StringUtils.join(this.caseRules,",") + " default: " + defaultRule;
427
        }
428
    }
429
430 44144 jjdelcerro
    public class RuleRepeatUntilAnyTokens implements RepeatRule {
431 44139 jjdelcerro
432
        private final String[] exit_tokens;
433
        private final List<Rule> rules;
434
        private int counter;
435
436 44144 jjdelcerro
        public RuleRepeatUntilAnyTokens(String[] exit_tokens) {
437 44139 jjdelcerro
            this.exit_tokens = exit_tokens;
438
            this.rules = new ArrayList<>();
439
        }
440
441 44379 jjdelcerro
        @Override
442 44750 jjdelcerro
        public Rule capture_as(String... ids) {
443
          throw new UnsupportedOperationException("Operation not suppted.");
444
        }
445
446
        @Override
447 44139 jjdelcerro
        public void parse(StatementContext context) {
448 44738 jjdelcerro
            context.trace(this.toString()+".parse");
449 44139 jjdelcerro
            String save = context.getCodeClassifier();
450
            try {
451
                this.counter = 1;
452
                while (true) {
453
                    Token token = context.look_token();
454
                    if (token.is(this.exit_tokens)) {
455
                        break;
456
                    }
457
                    context.setCodeClassifier(String.valueOf(counter).trim());
458
                    for (Rule rule : rules) {
459
                        rule.parse(context);
460
                    }
461
                    this.counter = this.counter + 1;
462
                }
463
            } finally {
464
                context.setCodeClassifier(save);
465
            }
466
        }
467
468 44379 jjdelcerro
        @Override
469 44144 jjdelcerro
        public RuleRepeatUntilAnyTokens addRule(Rule rule) {
470 44139 jjdelcerro
            this.rules.add(rule);
471
            return this;
472
        }
473
474
        @Override
475
        public String getClassifier() {
476
            String s = String.valueOf(counter).trim();
477
            return s;
478
        }
479
480
        @Override
481
        public String toString() {
482
            return "repeat_until_tokens('" + ArrayUtils.toString(this.exit_tokens) + "') rules:" + StringUtils.join(rules, ",");
483
        }
484
    }
485
486 44738 jjdelcerro
    public class RuleRepeat implements RepeatRule {
487
488
        private final List<Rule> rules;
489
        private int counter;
490
491
        public RuleRepeat() {
492
            this.rules = new ArrayList<>();
493
        }
494 44750 jjdelcerro
495 44738 jjdelcerro
        @Override
496 44750 jjdelcerro
        public Rule capture_as(String... ids) {
497
          throw new UnsupportedOperationException("Operation not suppted.");
498
        }
499
500
        @Override
501 44738 jjdelcerro
        public void parse(StatementContext context) {
502
            context.trace(this.toString()+".parse");
503
            String save = context.getCodeClassifier();
504
            try {
505
                this.counter = 1;
506
                boolean breakloop = false;
507
                while (!breakloop) {
508
                    context.setCodeClassifier(String.valueOf(counter).trim());
509
                    for (Rule rule : rules) {
510
                      try {
511
                        rule.parse(context);
512
                      } catch(BreakLoopException ex) {
513
                        breakloop = true;
514
                        break;
515
                      }
516
                    }
517
                    this.counter = this.counter + 1;
518
                }
519
            } finally {
520
                context.setCodeClassifier(save);
521
            }
522
        }
523
524
        @Override
525
        public RuleRepeat addRule(Rule rule) {
526
            this.rules.add(rule);
527
            return this;
528
        }
529
530
        @Override
531
        public String getClassifier() {
532
            String s = String.valueOf(counter).trim();
533
            return s;
534
        }
535
536
        @Override
537
        public String toString() {
538
            return "repeat() rules:" + StringUtils.join(rules, ",");
539
        }
540
    }
541
542
    public static class BreakLoopException extends RuntimeException {
543
544
    }
545
546
    public static class RuleBreakLoop implements Rule {
547
548
        public RuleBreakLoop() {
549
        }
550
551
        @Override
552 44750 jjdelcerro
        public Rule capture_as(String... ids) {
553
          throw new UnsupportedOperationException("Operation not suppted.");
554
        }
555
556
        @Override
557 44738 jjdelcerro
        public void parse(StatementContext context) {
558
          context.trace(this.toString()+".parse");
559
          throw new BreakLoopException();
560
        }
561
562
        @Override
563
        public String toString() {
564
            return "break_loop()";
565
        }
566
    }
567
568 44750 jjdelcerro
        public static class RuleFail implements Rule {
569
570
        public RuleFail() {
571
        }
572
573
        @Override
574
        public Rule capture_as(String... ids) {
575
          throw new UnsupportedOperationException("Operation not suppted.");
576
        }
577
578
        @Override
579
        public void parse(StatementContext context) {
580
          context.trace(this.toString()+".parse");
581
          throw new ExpressionSyntaxException();
582
        }
583
584
        @Override
585
        public String toString() {
586
            return "fail()";
587
        }
588
    }
589
590 44533 jjdelcerro
    public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule {
591 44139 jjdelcerro
592 44750 jjdelcerro
        private String id;
593 44139 jjdelcerro
        private final String separator;
594
595 44750 jjdelcerro
        public RuleOptionalIdentifiers(String separator) {
596 44533 jjdelcerro
            super();
597 44139 jjdelcerro
            this.separator = separator;
598
        }
599
600 44379 jjdelcerro
        @Override
601 44750 jjdelcerro
        public ConditionalRule capture_as(String... ids) {
602
          this.id = ids[0];
603
          return this;
604
        }
605
606
        @Override
607 44139 jjdelcerro
        public void parse(StatementContext context) {
608 44738 jjdelcerro
            context.trace(this.toString()+".parse");
609 44139 jjdelcerro
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
610
            Token token = context.look_token();
611
            while (token.getType() == Token.IDENTIFIER) {
612
                String identifier = (String) token.getLiteral();
613 44384 jjdelcerro
                if( context.isReservedWord(identifier) ) {
614
                    break;
615
                }
616 44139 jjdelcerro
                Code code = context.getCodeBuilder().constant(identifier);
617
                args.add(code);
618
                context.next_token();
619
                token = context.look_token();
620
                if (!token.is(this.separator)) {
621
                    break;
622
                }
623
                context.next_token();
624
                token = context.look_token();
625
            }
626
            if (args.size() != 0) {
627 44750 jjdelcerro
              if( this.id!=null ) {
628 44533 jjdelcerro
                Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
629
                context.setCode(id, code);
630 44750 jjdelcerro
              }
631
              this.parseOnTrueRules(context);
632 44533 jjdelcerro
            } else {
633
                this.parseOnFalseRules(context);
634 44139 jjdelcerro
            }
635
        }
636
637
        @Override
638
        public String toString() {
639
            return "optional_identifiers('" + id + "', '" + this.separator + "')";
640
        }
641
    }
642
643 44740 jjdelcerro
    public class RuleRequireIdentifiers implements Rule {
644
645 44750 jjdelcerro
        private String id;
646 44740 jjdelcerro
        private final String separator;
647
648 44750 jjdelcerro
        public RuleRequireIdentifiers(String separator) {
649 44740 jjdelcerro
            super();
650
            this.separator = separator;
651
        }
652
653
        @Override
654 44750 jjdelcerro
        public Rule capture_as(String... ids) {
655
          this.id = ids[0];
656
          return this;
657
        }
658
659
        @Override
660 44740 jjdelcerro
        public void parse(StatementContext context) {
661
            context.trace(this.toString()+".parse");
662
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
663
            Token token = context.look_token();
664
            while (token.getType() == Token.IDENTIFIER) {
665
                String identifier = (String) token.getLiteral();
666
                if( context.isReservedWord(identifier) ) {
667
                    break;
668
                }
669
                Code code = context.getCodeBuilder().constant(identifier);
670
                args.add(code);
671
                context.next_token();
672
                token = context.look_token();
673
                if (!token.is(this.separator)) {
674
                    break;
675
                }
676
                context.next_token();
677
                token = context.look_token();
678
            }
679
            if (args.size() == 0) {
680
                throw new ExpressionSyntaxException(
681
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
682
                        context.getLexicalAnalyzer()
683
                );
684
            }
685 44750 jjdelcerro
            if( this.id!=null ) {
686
              Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
687
              context.setCode(id, code);
688
            }
689 44740 jjdelcerro
        }
690
691
        @Override
692
        public String toString() {
693
            return "require_identifiers('" + id + "', '" + this.separator + "')";
694
        }
695
    }
696
697 44533 jjdelcerro
    public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule {
698
699 44750 jjdelcerro
        private String id;
700 44533 jjdelcerro
701 44750 jjdelcerro
        public RuleOptionalLiteralString() {
702 44533 jjdelcerro
            super();
703
        }
704
705
        @Override
706 44750 jjdelcerro
        public ConditionalRule capture_as(String... ids) {
707
          this.id = ids[0];
708
          return this;
709
        }
710
711
        @Override
712 44533 jjdelcerro
        public void parse(StatementContext context) {
713 44738 jjdelcerro
            context.trace(this.toString()+".parse");
714 44533 jjdelcerro
            Token token = context.look_token();
715
            if (token.getType() == Token.STRING_LITERAL) {
716 44750 jjdelcerro
                if( this.id!=null ) {
717
                  String s = (String) token.getValue();
718
                  Code code = context.getCodeBuilder().constant(s);
719
                  context.setCode(id, code);
720
                  context.next_token();
721
                }
722 44533 jjdelcerro
                this.parseOnTrueRules(context);
723
            } else {
724
                this.parseOnFalseRules(context);
725
            }
726
        }
727
728
        @Override
729
        public String toString() {
730
            return "optional_literal_string('" + id + "')";
731
        }
732
    }
733
734 44384 jjdelcerro
    public static class ArgsBuilderFromNames implements ArgsBuilder {
735 44139 jjdelcerro
736 44738 jjdelcerro
        protected final String[] argNames;
737 44139 jjdelcerro
738 44384 jjdelcerro
        public ArgsBuilderFromNames(String... argNames) {
739 44139 jjdelcerro
            this.argNames = argNames;
740
        }
741
742 44379 jjdelcerro
        @Override
743 44738 jjdelcerro
        public String toString() {
744
          return "args_names("+StringUtils.join(argNames,",")+")";
745
        }
746
747
        @Override
748 44139 jjdelcerro
        public Codes build(StatementContext context) {
749 44738 jjdelcerro
            context.trace(this.toString()+".build");
750 44139 jjdelcerro
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
751
            for (String argName : argNames) {
752
                if (argName.contains("#")) {
753
                    int n = 1;
754
                    while (true) {
755
                        String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
756
                        Code code = context.getCode(argNameX);
757
                        if (code == null) {
758
                            break;
759
                        }
760 44750 jjdelcerro
                        args.add(code);
761 44139 jjdelcerro
                        n++;
762
                    }
763
                } else {
764
                    Code code = context.getCode(argName);
765 44592 jjdelcerro
//                    if( code == null) {
766
//                        code = context.getCodeBuilder().constant(null);
767
//                    }
768 44750 jjdelcerro
                    args.add(code);
769 44139 jjdelcerro
                }
770
            }
771
            return args;
772
        }
773
    }
774
775 44750 jjdelcerro
    public static class FixedArgsBuilderFromNames implements ArgsBuilder {
776
777
        protected final String[] argNames;
778
779
        public FixedArgsBuilderFromNames(String... argNames) {
780
            this.argNames = argNames;
781
        }
782
783
        @Override
784
        public String toString() {
785
          return "fixed_args_names("+StringUtils.join(argNames,",")+")";
786
        }
787
788
        @Override
789
        public Codes build(StatementContext context) {
790
            context.trace(this.toString()+".build");
791
            CodeBuilder codeBuilder = context.getCodeBuilder();
792
            BaseCodes args = (BaseCodes) codeBuilder.args();
793
            for (String argName : argNames) {
794
                if (argName.contains("#")) {
795
                    int n = 1;
796
                    BaseCodes argsX = (BaseCodes) codeBuilder.args();
797
                    while (true) {
798
                        String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
799
                        Code code = context.getCode(argNameX);
800
                        if (code == null) {
801
                            break;
802
                        }
803
                        argsX.add(code);
804
                        n++;
805
                    }
806
807
                    args.add(codeBuilder.tuple(argsX));
808
                } else {
809
                    Code code = context.getCode(argName);
810
                    if( code == null) {
811
                        code = context.getCodeBuilder().constant(null);
812
                    }
813
                    args.add(code);
814
                }
815
            }
816
            return args;
817
        }
818
    }
819
820 44384 jjdelcerro
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
821 44139 jjdelcerro
822 44384 jjdelcerro
        public ArgsBuilderExpand(String... argNames) {
823 44139 jjdelcerro
            super(argNames);
824
        }
825
826 44379 jjdelcerro
        @Override
827 44738 jjdelcerro
        public String toString() {
828
          return "args_expand("+StringUtils.join(argNames,",")+")";
829
        }
830
831
        @Override
832 44139 jjdelcerro
        public Codes build(StatementContext context) {
833
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
834
835
            Codes base_args = super.build(context);
836
            for (Code arg : base_args) {
837
                if( arg.code() == Code.CALLER &&
838
                    ((Caller)arg).name().equals(CodeBlockFunction.NAME) ) {
839 44198 jjdelcerro
                    Codes block_args = ((Caller)arg).parameters();
840 44139 jjdelcerro
                    for (Code block_arg : block_args) {
841
                        args.add(block_arg);
842
                    }
843
                } else {
844
                    args.add(arg);
845
                }
846
            }
847
            return args;
848
        }
849
    }
850
851 44384 jjdelcerro
    public static class StatementBuilderBase implements StatementBuilder {
852
        protected ArgsBuilder argsBuilder;
853
        protected String codeID;
854
855
        public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) {
856
            this.codeID = codeID;
857
            this.argsBuilder = argsBuilder;
858
        }
859
860
        @Override
861
        public String getCodeID() {
862
            return this.codeID;
863
        }
864
865
        @Override
866
        public ArgsBuilder getArgsBuilder() {
867
            return this.argsBuilder;
868
        }
869
870
        @Override
871
        public Code build(StatementContext context) {
872
            Codes args = this.getArgsBuilder().build(context);
873
            Code code = null;
874
            if (this.getCodeID() == null) {
875
                code = args.get(0);
876
            } else {
877
                if (args.size() == 0) {
878
                    code = context.getCodeBuilder().function(this.getCodeID(), null);
879
                } else {
880
                    // Si es un bloque dentro de otro, dejamos solo uno.
881
                    if( args.size()==1 &&
882
                        StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,this.getCodeID()) ) {
883
                        Code code0 = args.get(0);
884
                        if( code0.code() == Code.CALLER &&
885
                                StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Caller)code0).name())
886
                                ) {
887
                            code = code0;
888
                        }
889
                    }
890
                    if( code == null ) {
891
                        code = context.getCodeBuilder().function(this.getCodeID(), args);
892
                    }
893
                }
894
            }
895
            return code;
896
        }
897
    }
898
899 44139 jjdelcerro
    public DefaultStatement(String name) {
900
        this.rules = new ArrayList<>();
901 44384 jjdelcerro
        this.stmtBuilder = null;
902 44139 jjdelcerro
        this.name = name;
903
    }
904
905 44379 jjdelcerro
    @Override
906 44139 jjdelcerro
    public String getName() {
907
        return name;
908
    }
909
910
    @Override
911 44144 jjdelcerro
    public Rule require_any_token(String... token) {
912
        return new RuleRequireAnyToken(token);
913 44139 jjdelcerro
    }
914
915
    @Override
916 44750 jjdelcerro
    public Rule require_identifier() {
917
        return new RuleRequireIdentifier();
918 44139 jjdelcerro
    }
919
920
    @Override
921 44750 jjdelcerro
    public Rule require_identifiers(String sep) {
922
        return new RuleRequireIdentifiers(sep);
923 44740 jjdelcerro
    }
924
925
    @Override
926 44750 jjdelcerro
    public Rule require_literal_string() {
927
        return new RuleRequireLiteralString();
928 44533 jjdelcerro
    }
929
930
    @Override
931 44379 jjdelcerro
    public Rule set_expression(String id, Object value) {
932
        return new RuleSetExpression(id, value);
933
    }
934
935
    @Override
936 44750 jjdelcerro
    public Rule require_expression() {
937
        return new RuleRequireExpression();
938 44139 jjdelcerro
    }
939
940
    @Override
941 44750 jjdelcerro
    public Rule require_expressions(String separator) {
942
        return new RuleRequiereExpressions(separator);
943 44139 jjdelcerro
    }
944
945
    @Override
946 44144 jjdelcerro
    public ConditionalRule optional_any_token(String... id) {
947
        return new RuleOptionalAnyToken(id);
948 44139 jjdelcerro
    }
949
950
    @Override
951 44750 jjdelcerro
    public ConditionalRule optional_identifiers(String separator) {
952
        return new RuleOptionalIdentifiers(separator);
953 44139 jjdelcerro
    }
954
955
    @Override
956 44750 jjdelcerro
    public ConditionalRule optional_literal_string() {
957
        return new RuleOptionalLiteralString();
958 44533 jjdelcerro
    }
959
960
    @Override
961 44144 jjdelcerro
    public CompoundRule repeat_until_any_tokens(String... tokens) {
962
        return new RuleRepeatUntilAnyTokens(tokens);
963 44139 jjdelcerro
    }
964
965
    @Override
966
    public Statement addRule(Rule rule) {
967
        this.rules.add(rule);
968
        return this;
969
    }
970
971
    @Override
972
    public boolean isApplicable(StatementContext context) {
973
        if (this.rules.isEmpty()) {
974
            return false;
975
        }
976 44738 jjdelcerro
        context.trace(this.getName()+".isApplicable");
977 44750 jjdelcerro
        context.save_state();
978 44738 jjdelcerro
        try {
979
          for (Rule rule : rules) {
980 44750 jjdelcerro
            if( rule == null ) {
981
              continue;
982 44738 jjdelcerro
            }
983 44750 jjdelcerro
            if (rule instanceof IsApplicableRule) {
984
              if( !((IsApplicableRule) rule).isApplicable(context) ) {
985
                context.trace(this.getName()+".isApplicable return false");
986
                return false;
987
              }
988
            } else {
989
              rule.parse(context);
990 44738 jjdelcerro
            }
991
          }
992 44750 jjdelcerro
          context.trace(this.getName()+".isApplicable return true");
993
          return true;
994
        } catch(Exception ex) {
995
          context.trace(this.getName()+".isApplicable return false (error)");
996
          return false;
997 44738 jjdelcerro
        } finally {
998 44750 jjdelcerro
          context.restore_state();
999 44139 jjdelcerro
        }
1000
    }
1001
1002
    @Override
1003
    public ArgsBuilder args_names(String... args) {
1004
        ArgsBuilder x = new ArgsBuilderFromNames(args);
1005
        return x;
1006
    }
1007
1008
    @Override
1009 44750 jjdelcerro
    public ArgsBuilder fixed_args_names(String... args) {
1010
        ArgsBuilder x = new FixedArgsBuilderFromNames(args);
1011
        return x;
1012
    }
1013
1014
    @Override
1015 44139 jjdelcerro
    public ArgsBuilder args_expand(String... args) {
1016
        ArgsBuilder x = new ArgsBuilderExpand(args);
1017
        return x;
1018
    }
1019
1020
    @Override
1021 44384 jjdelcerro
    public void code(final String id, final ArgsBuilder argsBuilder) {
1022
        this.builder(new StatementBuilderBase(id, argsBuilder));
1023 44139 jjdelcerro
    }
1024
1025 44738 jjdelcerro
    @Override
1026 44384 jjdelcerro
    public void builder(StatementBuilder builder) {
1027
        this.stmtBuilder = builder;
1028
    }
1029
1030 44139 jjdelcerro
    @Override
1031
    public Code parse(StatementContext context) {
1032 44738 jjdelcerro
        context.trace(this.getName()+".parse");
1033 44139 jjdelcerro
        for (Rule rule : rules) {
1034
            rule.parse(context);
1035
        }
1036 44384 jjdelcerro
        Code code = this.stmtBuilder.build(context);
1037 44738 jjdelcerro
        context.trace(this.getName()+".return "+code);
1038 44139 jjdelcerro
        return code;
1039
    }
1040
1041
    @Override
1042
    public String toString() {
1043
        return this.getName() + " " + StringUtils.join(this.rules, ";");
1044
1045
    }
1046 44738 jjdelcerro
1047
    @Override
1048
    public CompoundRule repeat() {
1049
      return new RuleRepeat();
1050
    }
1051
1052
    @Override
1053 44750 jjdelcerro
    public Rule fail() {
1054
      return new RuleFail();
1055
    }
1056
1057
    @Override
1058 44738 jjdelcerro
    public Rule break_loop() {
1059
      return new RuleBreakLoop();
1060
    }
1061
1062
    @Override
1063
    public SwichTokenRule switch_token() {
1064
      return new RuleSwitchToken();
1065
    }
1066
1067 44139 jjdelcerro
}