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 / DefaultCompiler.java @ 44750

History | View | Annotate | Download (23.6 KB)

1
package org.gvsig.expressionevaluator.impl;
2

    
3
import java.util.HashMap;
4
import java.util.Map;
5
import java.util.Stack;
6
import org.apache.commons.lang3.StringUtils;
7
import org.gvsig.expressionevaluator.Compiler;
8
import org.gvsig.expressionevaluator.LexicalAnalyzer;
9
import org.gvsig.expressionevaluator.LexicalAnalyzer.Token;
10
import org.gvsig.expressionevaluator.Code;
11
import org.gvsig.expressionevaluator.CodeBuilder;
12
import org.gvsig.expressionevaluator.Codes;
13
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
14
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
15
import org.gvsig.expressionevaluator.GrammarSet;
16
import org.gvsig.expressionevaluator.Statement;
17
import org.gvsig.expressionevaluator.Statement.StatementContext;
18
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseCodes;
19
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseConstant;
20
import org.gvsig.expressionevaluator.impl.function.operator.NegOperator;
21
import org.gvsig.expressionevaluator.impl.function.programming.CodeBlockFunction;
22
import org.gvsig.expressionevaluator.spi.AbstractLexicalAnalyzer;
23
import org.slf4j.Logger;
24
import org.slf4j.LoggerFactory;
25

    
26
public class DefaultCompiler implements Compiler {
27

    
28
    protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultCompiler.class);
29
    
30
    class DefaultStatementContext implements StatementContext {
31
      
32
        private class State {
33
          public String codeClassifier;
34
          public Map<String,Code> codes;
35
        }
36
        
37
        private State state;
38
        private final Stack<State> states;
39

    
40
        public DefaultStatementContext() {
41
          this.state = new State();
42
          this.states = new Stack<>();
43
        }
44
        
45
        @Override
46
        public void save_state() {
47
          ((AbstractLexicalAnalyzer)lexer).save_state();
48
          this.states.push(state);
49
        }
50

    
51
        @Override
52
        public void restore_state() {
53
          ((AbstractLexicalAnalyzer)lexer).restore_state();
54
          state = this.states.pop();
55
        }
56

    
57
        @Override
58
        public void drop_state() {
59
          ((AbstractLexicalAnalyzer)lexer).drop_state();
60
          this.states.pop();
61
        }
62
        
63
        @Override
64
        public Compiler getCompiler() {
65
            return DefaultCompiler.this;
66
        }
67

    
68
        @Override
69
        public LexicalAnalyzer getLexicalAnalyzer() {
70
            return lexer;
71
        }
72

    
73
        @Override
74
        public void setCode(String id, Code code) {
75
            if( this.state.codes == null ) {
76
                this.state.codes = new HashMap<>();
77
            }
78
            if( !StringUtils.isBlank(this.state.codeClassifier) ) {
79
                if( id.contains("#") ) {
80
                    id = StringUtils.replace(id,"#",this.state.codeClassifier,1);
81
                }
82
            }
83
            this.state.codes.put(id.toUpperCase(), code);
84
        }
85

    
86
        @Override
87
        public Code getCode(String id) {
88
            return this.state.codes.get(id.toUpperCase());
89
        }
90
        
91
        @Override
92
        public void setCodeClassifier(String classifier) {
93
            this.state.codeClassifier = classifier;
94
        }
95

    
96
        @Override
97
        public String getCodeClassifier() {
98
            return this.state.codeClassifier;
99
        }
100

    
101
        @Override
102
        public CodeBuilder getCodeBuilder() {
103
            return codeBuilder;
104
        }
105

    
106
        @Override
107
        public Token look_token() {
108
            return lexer.look();
109
        }
110

    
111
        @Override
112
        public Token next_token() {
113
            return lexer.next();
114
        }
115

    
116
        @Override
117
        public Code parse_expression() {
118
            return DefaultCompiler.this.parse_expression();
119
        }
120

    
121
        @Override
122
        public Codes parse_expressions(String separator) {
123
            return DefaultCompiler.this.parse_expressions(separator);
124
        }
125
        
126
        @Override
127
        public boolean isReservedWord(String s) {
128
            return grammars.isReservedWord(s);
129
        }
130
        
131
        @Override
132
        public void trace(String msg) {
133
//          System.out.println(msg+". "+this.getLexicalAnalyzer().getSourceContext());
134
        } 
135
    }
136

    
137
    private boolean objectAccessSupported;
138
    private LexicalAnalyzer lexer;
139
    private CodeBuilder codeBuilder;
140
    private final GrammarSet grammars;
141
    protected ExpressionEvaluatorManager manager;
142
    //
143
    // https://www.postgresql.org/docs/9.1/static/functions.html
144
    //
145

    
146
    public DefaultCompiler(ExpressionEvaluatorManager manager) {
147
        this.manager = manager;
148
        this.grammars = new DefaultGrammarSet();
149
        this.lexer = new SQLLexicalAnalyzer();
150
        this.codeBuilder = new DefaultCodeBuilder(manager);
151
        this.objectAccessSupported = true;
152
    }
153

    
154
    @Override
155
    public Compiler clone() throws CloneNotSupportedException {
156
        DefaultCompiler other = (DefaultCompiler) super.clone();
157
        other.lexer = lexer.clone();
158
        other.codeBuilder = codeBuilder.clone();
159
        
160
        return other;
161
    }
162

    
163
    @Override
164
    public void setLexicalAnalyzer(LexicalAnalyzer lexer) {
165
        this.lexer = lexer;
166
    }
167

    
168
    @Override
169
    public LexicalAnalyzer getLexicalAnalyzer() {
170
        return this.lexer;
171
    }
172
    
173
    @Override
174
    public void setCodeBuilder(CodeBuilder codeBuilder) {
175
        this.codeBuilder = codeBuilder;
176
    }
177

    
178
    @Override
179
    public CodeBuilder getCodeBuilder() {
180
        return this.codeBuilder;
181
    }
182
    
183
    @Override
184
    public boolean isObjectAccessSupported() {
185
        return this.objectAccessSupported;
186
    }
187

    
188
    @Override
189
    public void setObjectAccessSupported(boolean objectAccessSupported) {
190
        this.objectAccessSupported = objectAccessSupported;
191
    }
192

    
193
    @Override
194
    public GrammarSet getGrammars() {
195
        return this.grammars;
196
    }
197

    
198
    @Override
199
    public Code compileExpression(String expression) {
200
        this.lexer.setSource(expression.trim());
201
        Code code = parse_expression();
202
        if( !this.lexer.isEOF() ) {
203
            throw new ExpressionSyntaxException(lexer);
204
        }
205
        return code;
206
    }
207

    
208
    public Code parse_expression() {
209
        Code code = parse_relational();
210
        return code;
211
    }
212

    
213
    public Code parse_relational() {
214
        Code op1 = parse_not();
215
        Code op2;
216
        while( true ) {
217
            Token token = lexer.look();
218
            switch( token.getType() ) {
219
            case Token.OP_OR:
220
                lexer.next();
221
                op2 = parse_not();
222
                if( op2==null ) {
223
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_OR_operator(),lexer);
224
                }
225
                op1 = codeBuilder.or(op1, op2);
226
                break;
227
            case Token.OP_AND:
228
                lexer.next();
229
                op2 = parse_not();
230
                if( op2==null ) {
231
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_AND_operator(),lexer);
232
                }
233
                op1 = codeBuilder.and(op1, op2);
234
                break;
235
            default:
236
                return op1;
237
            }
238
        }
239
    }
240

    
241
    public Code parse_not() {
242
        Code op1;
243
        Token token = lexer.look();
244
        if( token.getType() == Token.OP_NOT ) {
245
            lexer.next();
246
            op1 = parse_conditional();
247
            op1 = codeBuilder.not(op1);
248
        } else {
249
            op1 = parse_conditional();
250
        }
251
        return op1;
252
    }
253

    
254
    public Code parse_conditional() {
255
        Code op1 = parse_sum();
256
        Code op2;
257
        while( true ) {
258
            Token token = lexer.look();
259
            switch( token.getType() ) {
260
            case Token.OP_LT:
261
                lexer.next();
262
                op2 = parse_sum();
263
                if( op2==null ) {
264
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LT_operator(),lexer);
265
                }
266
                op1 = codeBuilder.lt(op1, op2);
267
                break;
268
            case Token.OP_GT:
269
                lexer.next();
270
                op2 = parse_sum();
271
                if( op2==null ) {
272
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_GT_operator(),lexer);
273
                }
274
                op1 = codeBuilder.gt(op1, op2);
275
                break;
276
            case Token.OP_LE:
277
                lexer.next();
278
                op2 = parse_sum();
279
                if( op2==null ) {
280
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LE_operator(),lexer);
281
                }
282
                op1 = codeBuilder.le(op1, op2);
283
                break;
284
            case Token.OP_GE:
285
                lexer.next();
286
                op2 = parse_sum();
287
                if( op2==null ) {
288
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_GE_operator(),lexer);
289
                }
290
                op1 = codeBuilder.ge(op1, op2);
291
                break;
292
            case Token.OP_EQ:
293
                lexer.next();
294
                op2 = parse_sum();
295
                if( op2==null ) {
296
                    token = lexer.look();
297
                    String tip = null;
298
                    switch(token.getType()) {
299
                        case Token.OP_GT:
300
                            tip = I18N.The_operator_greater_than_or_equal_is_ge();
301
                            break;
302
                        case Token.OP_LT:
303
                            tip = I18N.The_operator_less_than_or_equal_is_ge();
304
                            break;
305
                    }
306
                    throw new ExpressionSyntaxException(
307
                            I18N.Cant_recognize_the_second_operand_of_EQ_operator(),
308
                            lexer,
309
                            tip
310
                    );
311
                }
312
                op1 = codeBuilder.eq(op1, op2);
313
                break;
314
            case Token.OP_NE:
315
                lexer.next();
316
                op2 = parse_sum();
317
                if( op2==null ) {
318
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_NEQ_operator(),lexer);
319
                }
320
                op1 = codeBuilder.ne(op1, op2);
321
                break;
322
            case Token.PRED_IS: {
323
                    lexer.next();
324
                    Token next = lexer.look();
325
                    switch(next.getType()) {
326
                        case Token.NOTNULL:
327
                            lexer.next();
328
                            op1 = codeBuilder.is(op1, codeBuilder.constant(null));
329
                            op1 = codeBuilder.not(op1);
330
                            break;
331
                        case Token.OP_NOT:
332
                            lexer.next();
333
                            next = lexer.look();
334
                            if( next.getType() == Token.NULL ) {
335
                                lexer.next();
336
                                op1 = codeBuilder.is(op1, codeBuilder.constant(null));
337
                            } else {
338
                                op2 = parse_sum();
339
                                if( op2==null ) {
340
                                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_IS_operator(),lexer);
341
                                }
342
                                op1 = codeBuilder.is(op1, op2);
343
                            }
344
                            op1 = codeBuilder.not(op1);
345
                            break;
346
                        case Token.NULL:
347
                            lexer.next();
348
                            op1 = codeBuilder.is(op1, codeBuilder.constant(null));
349
                            break;
350
                        default:    
351
                            op2 = parse_sum();
352
                            if( op2==null ) {
353
                                throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_IS_operator(),lexer);
354
                            }
355
                            op1 = codeBuilder.is(op1, op2);
356
                    }
357
                }
358
                break;
359
            case Token.ISNULL:
360
                lexer.next();
361
                op1 = codeBuilder.is(op1, codeBuilder.constant(null));
362
                break;
363
            case Token.OP_REGEXP:
364
                lexer.next();
365
                op2 = parse_sum();
366
                if( op2==null ) {
367
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_REGEXP_operator(),lexer);
368
                }
369
                op1 = codeBuilder.regexp(op1, op2);
370
                break;
371
            case Token.PRED_LIKE:
372
                lexer.next();
373
                op2 = parse_sum();
374
                if( op2==null ) {
375
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LIKE_operator(),lexer);
376
                }
377
                op1 = codeBuilder.like(op1, op2);
378
                break;
379
            case Token.PRED_ILIKE:
380
                lexer.next();
381
                op2 = parse_sum();
382
                if( op2==null ) {
383
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_ILIKE_operator(),lexer);
384
                }
385
                op1 = codeBuilder.ilike(op1, op2);
386
                break;
387
            default:
388
                return op1;
389
            }
390
        }
391
    }
392

    
393
    public Code parse_sum() {
394
        Code op1 = parse_factor();
395
        Code op2;
396
        while( true ) {
397
            Token token = lexer.look();
398
            switch( token.getType() ) {
399
            case Token.OP_CONCAT:
400
                lexer.next();
401
                op2 = parse_factor();
402
                op1 = codeBuilder.concat(op1, op2);
403
                break;
404
            case Token.OP_ADD:
405
                lexer.next();
406
                op2 = parse_factor();
407
                op1 = codeBuilder.add(op1, op2);
408
                break;
409
            case Token.OP_SUBST:
410
                lexer.next();
411
                op2 = parse_factor();
412
                op1 = codeBuilder.subst(op1, op2);
413
                break;
414
            default:
415
                return op1;
416
            }
417
        }
418
    }
419

    
420
    public Code parse_factor() {
421
        Code op1 = parse_getattr();
422
        Code op2;
423
        while( true ) {
424
            Token token = lexer.look();
425
            switch( token.getType() ) {
426
            case Token.OP_MULT:
427
                lexer.next();
428
                op2 = parse_getattr();
429
                if( op2==null ) {
430
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_MULT_operator(),lexer);
431
                }
432
                op1 = codeBuilder.mult(op1, op2);
433
                break;
434
            case Token.OP_DIV:
435
                lexer.next();
436
                op2 = parse_getattr();
437
                if( op2==null ) {
438
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_DIV_operator(),lexer);
439
                }
440
                op1 = codeBuilder.div(op1, op2);
441
                break;
442
            case Token.OP_MOD:
443
                lexer.next();
444
                op2 = parse_getattr();
445
                if( op2==null ) {
446
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_MOD_operator(),lexer);
447
                }
448
                op1 = codeBuilder.mod(op1, op2);
449
                break;
450
            case Token.OPEN_BRACKET:
451
                lexer.next();
452
                Code codeIndex = parse_expression();
453
                if( codeIndex == null ) {
454
                    throw new ExpressionSyntaxException(I18N.unexpected_end_of_source(),lexer);
455
                }
456
                token = lexer.look();
457
                if( token.getType()!=Token.CLOSED_BRACKET) {
458
                    throw new ExpressionSyntaxException(I18N.A_XTokenX_was_expected_and_XliteralX_was_found("]", token.getLiteral()),lexer);
459
                }
460
                lexer.next();
461
                Code code = codeBuilder.getitem(op1, codeIndex);
462
                return code;
463
            default:
464
                return op1;
465
            }
466
        }
467
    }
468

    
469
    public Code parse_getattr() {
470
        Code op1 = parse_termino();
471
        if( !isObjectAccessSupported() ) {
472
            return op1;
473
        }
474
        while( true ) {
475
            Token next = lexer.look();
476
            switch( next.getType() ) {
477
            case Token.OP_GETATTR:
478
                lexer.next();
479
                next = lexer.look();
480
                if( next.getType()!=Token.IDENTIFIER ) {
481
                    throw new ExpressionSyntaxException(
482
                        I18N.An_attribute_identifier_was_expected_and_XliteralX_was_found(next.getLiteral()),
483
                        lexer
484
                    );
485
                }
486
                String id = (String) next.getLiteral();
487
                lexer.next();
488
                next = lexer.look();
489
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
490
                    lexer.next();
491
                    Codes args = parse_expressions(",");
492
                    next = lexer.next();
493
                    if( next.getType() != Token.PARENTHESIS_CLOSE ) {
494
                        throw new ExpressionSyntaxException(
495
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
496
                            lexer
497
                        );
498
                    }
499
                    op1 = codeBuilder.method(op1, id, args);
500
                } else {
501
                    op1 = codeBuilder.getattr(op1, id);
502
                }
503
                break;
504
            default:
505
                return op1;
506
            }
507
        }
508
    }    
509

    
510
    public Code parse_termino() {
511

    
512
        Token token = lexer.look();
513
        switch( token.getType() ) {
514
        case Token.PARENTHESIS_OPEN: {
515
                lexer.next();
516
                Code value = parse_expression();
517
                Token next = lexer.next();
518
                switch(next.getType()) {
519
                    case Token.PARENTHESIS_CLOSE:
520
                        break;
521
                    case Token.EOF:
522
                        throw new ExpressionSyntaxException(
523
                            I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
524
                            lexer
525
                        );
526
                    default:
527
                        throw new ExpressionSyntaxException(
528
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
529
                            lexer
530
                        );
531
                }
532
                return value;
533
            }
534
        case Token.IDENTIFIER: {
535
                Code code = parse_grammars();
536
                if( code!=null ) {
537
                    return code;
538
                }
539
                if( this.grammars.isReservedWord(token.getLiteral()) ) {
540
                    return null;
541
                }
542
                lexer.next();
543
                String id = (String) token.getLiteral();
544
                Token next = lexer.look();
545
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
546
                    next = lexer.next();
547
                    Codes args = parse_arguments();
548
                    next = lexer.next();
549
                    switch(next.getType()) {
550
                        case Token.PARENTHESIS_CLOSE:
551
                            break;
552
                        case Token.EOF:
553
                            throw new ExpressionSyntaxException(
554
                                I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
555
                                lexer
556
                            );
557
                        default:
558
                            throw new ExpressionSyntaxException(
559
                                I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
560
                                lexer
561
                            );
562
                    }
563
                    return codeBuilder.function(id, args);
564
                } else {
565
                    if( StringUtils.equalsIgnoreCase(id, "TRUE") ) {
566
                        return codeBuilder.constant(true);
567
                    }
568
                    if( StringUtils.equalsIgnoreCase(id, "FALSE") ) {
569
                        return codeBuilder.constant(false);
570
                    }
571
                    return codeBuilder.identifier(id);
572
                }
573
            }
574
        case Token.STRING_LITERAL:
575
            lexer.next();
576
            return codeBuilder.constant(token.getValue());
577
        case Token.INTEGER_LITERAL:
578
            lexer.next();
579
            return codeBuilder.constant(token.getValue());
580
        case Token.FLOATING_POINT_LITERAL:
581
            lexer.next();
582
            return codeBuilder.constant(token.getValue());
583
        case Token.NULL:
584
            lexer.next();
585
            return codeBuilder.constant(null);
586
        case Token.TRUE:
587
            lexer.next();
588
            return codeBuilder.constant(true);
589
        case Token.FALSE:
590
            lexer.next();
591
            return codeBuilder.constant(false);
592
        case Token.OP_SUBST:
593
            lexer.next();
594
            Code code = parse_termino();
595
            if( code.code()==Code.CONSTANT ) {
596
                BaseConstant c = (BaseConstant)code;
597
                if( c.value() instanceof Number ) {
598
                    c.value(NegOperator.negate((Number) c.value()));
599
                    return code;
600
                }
601
                throw new ExpressionSyntaxException(I18N.A_numeric_constant_was_expected_after_the_unary_operator_minus(),lexer);
602
            }
603
            return codeBuilder.negate(code);
604
        case Token.EOF:
605
            throw new ExpressionSyntaxException(I18N.unexpected_end_of_source(),lexer);
606
        default:
607
            return parse_grammars();
608
        }
609
    }
610

    
611
    public Codes parse_expressions(String sep) {
612
        BaseCodes codes = null;
613
        while( true ) {
614
            Code code = parse_expression();
615
            if( code!=null ) {
616
                if( codes == null ) {
617
                    codes = (BaseCodes) codeBuilder.args();
618
                }
619
                codes.add(code);
620
            }
621
            Token next = lexer.look();
622
            String literal = next.getLiteral();
623
            if( literal == null ) {
624
                return codes;
625
            }
626
            literal = literal.trim();
627
            if( sep.equals(literal) ) {
628
                lexer.next(); // Consume el ",".
629
            } else {
630
                return codes;
631
            }
632
        }
633
    }
634

    
635
    public Codes parse_arguments() {
636
        String sep = ",";
637
        BaseCodes codes = null;
638
        while( true ) {
639
            Code code = parse_expression();
640
            if( code!=null ) {
641
                if( codes == null ) {
642
                    codes = (BaseCodes) codeBuilder.args();
643
                }
644
                codes.add(code);
645
            }
646
            Token next = lexer.look();
647
            String literal = next.getLiteral();
648
            if( literal == null ) {
649
                return codes;
650
            }
651
            literal = literal.trim();
652
            if( sep.equals(literal) ) {
653
                lexer.next(); // Consume el ",".
654
            } else {
655
                return codes;
656
            }
657
        }
658
    }
659

    
660
    private Code parse_grammars() {
661
        StatementContext context = new DefaultStatementContext();
662
        Code code;
663
        BaseCodes args = (BaseCodes) this.codeBuilder.args();
664
        Statement stmt = this.grammars.getApplicableStatement(context);
665
        while( stmt!=null ) {
666
            code = stmt.parse(context);
667
            args.add(code);
668
            stmt = this.grammars.getApplicableStatement(context);
669
        }
670
        switch(args.size()) {
671
            case 0 :
672
                code = null;
673
                break;
674
            case 1 :
675
                code = args.get(0);
676
                break;
677
            default:
678
                code = this.codeBuilder.function(CodeBlockFunction.NAME, args);
679
                break;
680
        }
681
        return code;
682
    }
683
}