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

History | View | Annotate | Download (19.5 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.gvsig.expressionevaluator.Code;
9
import org.gvsig.expressionevaluator.Code.Caller;
10
import org.gvsig.expressionevaluator.Codes;
11
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_LIST;
12
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
13
import org.gvsig.expressionevaluator.LexicalAnalyzer.Token;
14
import org.gvsig.expressionevaluator.Statement;
15
import org.gvsig.expressionevaluator.Statement.CompoundRule;
16
import org.gvsig.expressionevaluator.Statement.ConditionalRule;
17
import org.gvsig.expressionevaluator.Statement.Rule;
18
import org.gvsig.expressionevaluator.Statement.StatementContext;
19
import org.gvsig.expressionevaluator.impl.function.programming.CodeBlockFunction;
20
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseCodes;
21

    
22
/**
23
 *
24
 * @author jjdelcerro
25
 */
26
public class DefaultStatement implements Statement {
27

    
28
    private final List<Rule> rules;
29
    private final String name;
30
    private StatementBuilder stmtBuilder;
31
//    private String codeId;
32
//    private ArgsBuilder argsBuilder;
33

    
34
    public interface RepeatRule extends CompoundRule {
35

    
36
        public String getClassifier();
37
    }
38

    
39
    public class RuleRequireAnyToken implements Rule {
40

    
41
        private final String[] required_token;
42

    
43
        public RuleRequireAnyToken(String... required_token) {
44
            this.required_token = required_token;
45
        }
46

    
47
        @Override
48
        public void parse(StatementContext context) {
49
            Token token = context.look_token();
50
            if (!token.is(this.required_token)) {
51
                throw new ExpressionSyntaxException(
52
                        I18N.A_XTokenX_was_expected_and_XliteralX_was_found(
53
                                StringUtils.join(this.required_token,", "),
54
                                token.getLiteral()
55
                        ),
56
                        context.getLexicalAnalyzer()
57
                );
58
            }
59
            context.next_token();
60
        }
61

    
62
        private boolean isApplicable(StatementContext context) {
63
            Token token = context.look_token();
64
            return token.is(this.required_token);
65
        }
66

    
67
        @Override
68
        public String toString() {
69
            return "require_token(" + StringUtils.join(this.required_token) + ")";
70
        }
71

    
72
    }
73

    
74
    public class RuleRequireIdentifier implements Rule {
75

    
76
        private final String id;
77

    
78
        public RuleRequireIdentifier(String id) {
79
            this.id = id;
80
        }
81

    
82
        @Override
83
        public void parse(StatementContext context) {
84
            Token token = context.look_token();
85
            if (token.getType() != Token.IDENTIFIER) {
86
                throw new ExpressionSyntaxException(
87
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
88
                        context.getLexicalAnalyzer()
89
                );
90
            }
91
            String identifier = (String) token.getLiteral();
92
            Code code = context.getCodeBuilder().constant(identifier);
93
            context.setCode(id, code);
94
            context.next_token();
95
        }
96

    
97
        @Override
98
        public String toString() {
99
            return "require_identifier('" + this.id + "')";
100
        }
101
    }
102

    
103
    public class RuleRequireLiteralString implements Rule {
104

    
105
        private final String id;
106

    
107
        public RuleRequireLiteralString(String id) {
108
            this.id = id;
109
        }
110

    
111
        @Override
112
        public void parse(StatementContext context) {
113
            Token token = context.look_token();
114
            if (token.getType() != Token.STRING_LITERAL) {
115
                throw new ExpressionSyntaxException(
116
                        I18N.A_string_literal_was_expected(),
117
                        context.getLexicalAnalyzer()
118
                );
119
            }
120
            String identifier = (String) token.getValue();
121
            Code code = context.getCodeBuilder().constant(identifier);
122
            context.setCode(id, code);
123
            context.next_token();
124
        }
125

    
126
        @Override
127
        public String toString() {
128
            return "require_literal_string('" + this.id + "')";
129
        }
130
    }
131

    
132
    public class RuleRequireExpression implements Rule {
133

    
134
        private final String id;
135

    
136
        public RuleRequireExpression(String id) {
137
            this.id = id;
138
        }
139

    
140
        @Override
141
        public void parse(StatementContext context) {
142
            Code code = context.parse_expression();
143
            if (code == null) {
144
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
145
            }
146
            context.setCode(id, code);
147
        }
148

    
149
        @Override
150
        public String toString() {
151
            return "require_expression('" + this.id + "')";
152
        }
153
    }
154

    
155

    
156
    public class RuleSetExpression implements Rule {
157

    
158
        private final String id;
159
        private final Object value;
160

    
161
        public RuleSetExpression(String id, Object value) {
162
            this.id = id;
163
            this.value = value;
164
        }
165

    
166
        @Override
167
        public void parse(StatementContext context) {
168
            if( this.value instanceof Code ) {
169
                context.setCode(id, (Code) this.value);
170
            } else {
171
                context.setCode(id, context.getCodeBuilder().constant(value));
172
            }
173
        }
174

    
175
        @Override
176
        public String toString() {
177
            return "set_expression('" + this.id + "', "+Objects.toString(value)+")";
178
        }
179
    }
180

    
181
    public class RuleRequiereExpressions implements Rule {
182

    
183
        private final String id;
184
        private final String separator;
185

    
186
        public RuleRequiereExpressions(String id, String separator) {
187
            this.id = id;
188
            this.separator = separator;
189
        }
190

    
191
        @Override
192
        public void parse(StatementContext context) {
193
            Codes codes = context.parse_expressions(this.separator);
194
            if (codes == null) {
195
                throw new ExpressionSyntaxException(context.getLexicalAnalyzer());
196
            }
197
            Code code;
198
            if( codes.size()==1 ) {
199
                code = codes.get(0);
200
            } else {
201
                code = context.getCodeBuilder().function(CodeBlockFunction.NAME, codes);
202
            }
203
            context.setCode(id, code);
204
        }
205

    
206
        @Override
207
        public String toString() {
208
            return "require_expressions('" + this.id + "', '" + this.separator + "')";
209
        }
210
    }
211

    
212
    public abstract class AbstractConditionalRule implements ConditionalRule {
213

    
214
        protected final List<Rule> onTrueRules;
215
        protected final List<Rule> onFalseRules;
216

    
217
        public AbstractConditionalRule() {
218
            this.onTrueRules = new ArrayList<>();
219
            this.onFalseRules = new ArrayList<>();
220
        }
221

    
222
        protected void parseOnTrueRules(StatementContext context) {
223
            for (Rule rule : this.onTrueRules) {
224
                rule.parse(context);
225
            }
226
        }
227

    
228
        protected void parseOnFalseRules(StatementContext context) {
229
            for (Rule rule : this.onFalseRules) {
230
                rule.parse(context);
231
            }
232
        }
233

    
234
        @Override
235
        public ConditionalRule addRuleOnTrue(Rule rule) {
236
            this.onTrueRules.add(rule);
237
            return this;
238
        }
239

    
240
        @Override
241
        public ConditionalRule addRuleOnFalse(Rule rule) {
242
            this.onFalseRules.add(rule);
243
            return this;
244
        }
245

    
246
    }
247

    
248
    public class RuleOptionalAnyToken implements ConditionalRule {
249

    
250
        private final String[] optional_token;
251
        private final List<Rule> onTrueRules;
252
        private final List<Rule> onFalseRules;
253

    
254
        public RuleOptionalAnyToken(String... optional_token) {
255
            this.optional_token = optional_token;
256
            this.onTrueRules = new ArrayList<>();
257
            this.onFalseRules = new ArrayList<>();
258
        }
259

    
260
        @Override
261
        public void parse(StatementContext context) {
262
            Token token = context.look_token();
263
            if (token.is(this.optional_token)) {
264
                context.next_token();
265
                for (Rule rule : this.onTrueRules) {
266
                    rule.parse(context);
267
                }
268
            } else {
269
                for (Rule rule : this.onFalseRules) {
270
                    rule.parse(context);
271
                }
272
            }
273
        }
274

    
275
        @Override
276
        public RuleOptionalAnyToken addRuleOnTrue(Rule rule) {
277
            this.onTrueRules.add(rule);
278
            return this;
279
        }
280

    
281
        @Override
282
        public RuleOptionalAnyToken addRuleOnFalse(Rule rule) {
283
            this.onFalseRules.add(rule);
284
            return this;
285
        }
286

    
287
        @Override
288
        public String toString() {
289
            return "optional_token(" + StringUtils.join(this.optional_token) + ") rules:" + StringUtils.join(onTrueRules, ",");
290
        }
291
    }
292

    
293
    public class RuleRepeatUntilAnyTokens implements RepeatRule {
294

    
295
        private final String[] exit_tokens;
296
        private final List<Rule> rules;
297
        private int counter;
298

    
299
        public RuleRepeatUntilAnyTokens(String[] exit_tokens) {
300
            this.exit_tokens = exit_tokens;
301
            this.rules = new ArrayList<>();
302
        }
303

    
304
        @Override
305
        public void parse(StatementContext context) {
306
            String save = context.getCodeClassifier();
307
            try {
308
                this.counter = 1;
309
                while (true) {
310
                    Token token = context.look_token();
311
                    if (token.is(this.exit_tokens)) {
312
                        break;
313
                    }
314
                    context.setCodeClassifier(String.valueOf(counter).trim());
315
                    for (Rule rule : rules) {
316
                        rule.parse(context);
317
                    }
318
                    this.counter = this.counter + 1;
319
                }
320
            } finally {
321
                context.setCodeClassifier(save);
322
            }
323
        }
324

    
325
        @Override
326
        public RuleRepeatUntilAnyTokens addRule(Rule rule) {
327
            this.rules.add(rule);
328
            return this;
329
        }
330

    
331
        @Override
332
        public String getClassifier() {
333
            String s = String.valueOf(counter).trim();
334
            return s;
335
        }
336

    
337
        @Override
338
        public String toString() {
339
            return "repeat_until_tokens('" + ArrayUtils.toString(this.exit_tokens) + "') rules:" + StringUtils.join(rules, ",");
340
        }
341
    }
342

    
343
    public class RuleOptionalIdentifiers extends AbstractConditionalRule implements ConditionalRule {
344

    
345
        private final String id;
346
        private final String separator;
347

    
348
        public RuleOptionalIdentifiers(String id, String separator) {
349
            super();
350
            this.id = id;
351
            this.separator = separator;
352
        }
353

    
354
        @Override
355
        public void parse(StatementContext context) {
356
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
357
            Token token = context.look_token();
358
            while (token.getType() == Token.IDENTIFIER) {
359
                String identifier = (String) token.getLiteral();
360
                if( context.isReservedWord(identifier) ) {
361
                    break;
362
                }
363
                Code code = context.getCodeBuilder().constant(identifier);
364
                args.add(code);
365
                context.next_token();
366
                token = context.look_token();
367
                if (!token.is(this.separator)) {
368
                    break;
369
                }
370
                context.next_token();
371
                token = context.look_token();
372
            }
373
            if (args.size() != 0) {
374
                Code code = context.getCodeBuilder().function(FUNCTION_LIST, args);
375
                context.setCode(id, code);
376
                this.parseOnTrueRules(context);
377
            } else {
378
                this.parseOnFalseRules(context);
379
            }
380
        }
381

    
382
        @Override
383
        public String toString() {
384
            return "optional_identifiers('" + id + "', '" + this.separator + "')";
385
        }
386
    }
387

    
388
    public class RuleOptionalLiteralString extends AbstractConditionalRule implements ConditionalRule {
389

    
390
        private final String id;
391

    
392
        public RuleOptionalLiteralString(String id) {
393
            super();
394
            this.id = id;
395
        }
396

    
397
        @Override
398
        public void parse(StatementContext context) {
399
            Token token = context.look_token();
400
            if (token.getType() == Token.STRING_LITERAL) {
401
                String s = (String) token.getValue();
402
                Code code = context.getCodeBuilder().constant(s);
403
                context.setCode(id, code);
404
                context.next_token();
405
                this.parseOnTrueRules(context);
406
            } else {
407
                this.parseOnFalseRules(context);
408
            }
409
        }
410

    
411
        @Override
412
        public String toString() {
413
            return "optional_literal_string('" + id + "')";
414
        }
415
    }
416

    
417
    public static class ArgsBuilderFromNames implements ArgsBuilder {
418

    
419
        private final String[] argNames;
420

    
421
        public ArgsBuilderFromNames(String... argNames) {
422
            this.argNames = argNames;
423
        }
424

    
425
        @Override
426
        public Codes build(StatementContext context) {
427
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
428
            for (String argName : argNames) {
429
                if (argName.contains("#")) {
430
                    int n = 1;
431
                    while (true) {
432
                        String argNameX = StringUtils.replace(argName, "#", String.valueOf(n).trim(), 1);
433
                        Code code = context.getCode(argNameX);
434
                        if (code == null) {
435
                            break;
436
                        }
437
                        args.add(code);
438
                        n++;
439
                    }
440
                } else {
441
                    Code code = context.getCode(argName);
442
//                    if( code == null) {
443
//                        code = context.getCodeBuilder().constant(null);
444
//                    }
445
                    args.add(code);
446
                }
447
            }
448
            return args;
449
        }
450
    }
451

    
452
    public static class ArgsBuilderExpand extends ArgsBuilderFromNames {
453

    
454
        public ArgsBuilderExpand(String... argNames) {
455
            super(argNames);
456
        }
457

    
458
        @Override
459
        public Codes build(StatementContext context) {
460
            BaseCodes args = (BaseCodes) context.getCodeBuilder().args();
461
            
462
            Codes base_args = super.build(context);
463
            for (Code arg : base_args) {
464
                if( arg.code() == Code.CALLER && 
465
                    ((Caller)arg).name().equals(CodeBlockFunction.NAME) ) {
466
                    Codes block_args = ((Caller)arg).parameters();
467
                    for (Code block_arg : block_args) {
468
                        args.add(block_arg);
469
                    }
470
                } else {
471
                    args.add(arg);
472
                }
473
            }
474
            return args;
475
        }
476
    }
477

    
478
    public static class StatementBuilderBase implements StatementBuilder {
479
        protected ArgsBuilder argsBuilder;
480
        protected String codeID;
481
        
482
        public StatementBuilderBase(String codeID, ArgsBuilder argsBuilder) {
483
            this.codeID = codeID;
484
            this.argsBuilder = argsBuilder;
485
        }
486
        
487
        @Override
488
        public String getCodeID() {
489
            return this.codeID;
490
        }
491

    
492
        @Override
493
        public ArgsBuilder getArgsBuilder() {
494
            return this.argsBuilder;
495
        }
496

    
497
        @Override
498
        public Code build(StatementContext context) {
499
            Codes args = this.getArgsBuilder().build(context);
500
            Code code = null;
501
            if (this.getCodeID() == null) {
502
                code = args.get(0);
503
            } else {
504
                if (args.size() == 0) {
505
                    code = context.getCodeBuilder().function(this.getCodeID(), null);
506
                } else {
507
                    // Si es un bloque dentro de otro, dejamos solo uno.
508
                    if( args.size()==1 && 
509
                        StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,this.getCodeID()) ) {
510
                        Code code0 = args.get(0);
511
                        if( code0.code() == Code.CALLER && 
512
                                StringUtils.equalsIgnoreCase(CodeBlockFunction.NAME,((Caller)code0).name())
513
                                ) {
514
                            code = code0;
515
                        }
516
                    }
517
                    if( code == null ) {
518
                        code = context.getCodeBuilder().function(this.getCodeID(), args);
519
                    }
520
                }
521
            }
522
            return code;
523
        }
524
    }
525
    
526
    public DefaultStatement(String name) {
527
        this.rules = new ArrayList<>();
528
        this.stmtBuilder = null;
529
        this.name = name;
530
    }
531

    
532
    @Override
533
    public String getName() {
534
        return name;
535
    }
536

    
537
    @Override
538
    public Rule require_any_token(String... token) {
539
        return new RuleRequireAnyToken(token);
540
    }
541

    
542
    @Override
543
    public Rule require_identifier(String id) {
544
        return new RuleRequireIdentifier(id);
545
    }
546

    
547
    @Override
548
    public Rule require_literal_string(String id) {
549
        return new RuleRequireLiteralString(id);
550
    }
551

    
552
    @Override
553
    public Rule set_expression(String id, Object value) {
554
        return new RuleSetExpression(id, value);
555
    }
556

    
557
    @Override
558
    public Rule require_expression(String id) {
559
        return new RuleRequireExpression(id);
560
    }
561

    
562
    @Override
563
    public Rule require_expressions(String id, String separator) {
564
        return new RuleRequiereExpressions(id, separator);
565
    }
566

    
567
    @Override
568
    public ConditionalRule optional_any_token(String... id) {
569
        return new RuleOptionalAnyToken(id);
570
    }
571

    
572
    @Override
573
    public ConditionalRule optional_identifiers(String id, String separator) {
574
        return new RuleOptionalIdentifiers(id, separator);
575
    }
576

    
577
    @Override
578
    public ConditionalRule optional_literal_string(String id) {
579
        return new RuleOptionalLiteralString(id);
580
    }
581

    
582
    @Override
583
    public CompoundRule repeat_until_any_tokens(String... tokens) {
584
        return new RuleRepeatUntilAnyTokens(tokens);
585
    }
586

    
587
    @Override
588
    public Statement addRule(Rule rule) {
589
        this.rules.add(rule);
590
        return this;
591
    }
592

    
593
    @Override
594
    public boolean isApplicable(StatementContext context) {
595
        if (this.rules.isEmpty()) {
596
            return false;
597
        }
598
        Rule rule = this.rules.get(0);
599
        if (!(rule instanceof RuleRequireAnyToken)) {
600
            return false;
601
        }
602
        return ((RuleRequireAnyToken) rule).isApplicable(context);
603
    }
604

    
605
    @Override
606
    public ArgsBuilder args_names(String... args) {
607
        ArgsBuilder x = new ArgsBuilderFromNames(args);
608
        return x;
609
    }
610
    
611
    @Override
612
    public ArgsBuilder args_expand(String... args) {
613
        ArgsBuilder x = new ArgsBuilderExpand(args);
614
        return x;
615
    }
616
    
617
    @Override
618
    public void code(final String id, final ArgsBuilder argsBuilder) {
619
        this.builder(new StatementBuilderBase(id, argsBuilder));
620
    }
621

    
622
    public void builder(StatementBuilder builder) {
623
        this.stmtBuilder = builder;
624
    }
625
    
626
    @Override
627
    public Code parse(StatementContext context) {
628
//        System.err.println("start parse "+this.getName());
629
        for (Rule rule : rules) {
630
            rule.parse(context);
631
        }
632
        Code code = this.stmtBuilder.build(context);
633
        return code;
634
    }
635

    
636
    @Override
637
    public String toString() {
638
        return this.getName() + " " + StringUtils.join(this.rules, ";");
639

    
640
    }
641
}