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

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