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

History | View | Annotate | Download (23.2 KB)

1
package org.gvsig.expressionevaluator.impl;
2

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

    
25
public class DefaultCompiler implements Compiler {
26

    
27
    protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultCompiler.class);
28
    
29
    class DefaultStatementContext implements StatementContext {
30

    
31
        private String codeClassifier;
32
        private Map<String,Code> codes;
33

    
34
        @Override
35
        public Compiler getCompiler() {
36
            return DefaultCompiler.this;
37
        }
38

    
39
        @Override
40
        public LexicalAnalyzer getLexicalAnalyzer() {
41
            return lexer;
42
        }
43

    
44
        @Override
45
        public void setCode(String id, Code code) {
46
            if( this.codes == null ) {
47
                this.codes = new HashMap<>();
48
            }
49
            if( !StringUtils.isBlank(this.codeClassifier) ) {
50
                if( id.contains("#") ) {
51
                    id = StringUtils.replace(id,"#",this.codeClassifier,1);
52
                }
53
            }
54
            this.codes.put(id, code);
55
        }
56

    
57
        @Override
58
        public Code getCode(String id) {
59
            return this.codes.get(id);
60
        }
61
        
62
        @Override
63
        public void setCodeClassifier(String classifier) {
64
            this.codeClassifier = classifier;
65
        }
66

    
67
        @Override
68
        public String getCodeClassifier() {
69
            return this.codeClassifier;
70
        }
71

    
72
        @Override
73
        public CodeBuilder getCodeBuilder() {
74
            return codeBuilder;
75
        }
76

    
77
        @Override
78
        public Token look_token() {
79
            return lexer.look();
80
        }
81

    
82
        @Override
83
        public Token next_token() {
84
            return lexer.next();
85
        }
86

    
87
        @Override
88
        public Code parse_expression() {
89
            return DefaultCompiler.this.parse_expression();
90
        }
91

    
92
        @Override
93
        public Codes parse_expressions(String separator) {
94
            return DefaultCompiler.this.parse_expressions(separator);
95
        }
96
        
97
        @Override
98
        public boolean isReservedWord(String s) {
99
            return grammars.isReservedWord(s);
100
        }
101
        
102
        @Override
103
        public void trace(String msg) {
104
//          System.out.println(msg+". "+this.getLexicalAnalyzer().getSourceContext());
105
        } 
106
    }
107

    
108
    private boolean objectAccessSupported;
109
    private LexicalAnalyzer lexer;
110
    private CodeBuilder codeBuilder;
111
    private final GrammarSet grammars;
112
    protected ExpressionEvaluatorManager manager;
113
    //
114
    // https://www.postgresql.org/docs/9.1/static/functions.html
115
    //
116

    
117
    public DefaultCompiler(ExpressionEvaluatorManager manager) {
118
        this.manager = manager;
119
        this.grammars = new DefaultGrammarSet();
120
        this.lexer = new SQLLexicalAnalyzer();
121
        this.codeBuilder = new DefaultCodeBuilder(manager);
122
        this.objectAccessSupported = true;
123
    }
124

    
125
    @Override
126
    public Compiler clone() throws CloneNotSupportedException {
127
        DefaultCompiler other = (DefaultCompiler) super.clone();
128
        other.lexer = lexer.clone();
129
        other.codeBuilder = codeBuilder.clone();
130
        
131
        return other;
132
    }
133

    
134
    @Override
135
    public void setLexicalAnalyzer(LexicalAnalyzer lexer) {
136
        this.lexer = lexer;
137
    }
138

    
139
    @Override
140
    public LexicalAnalyzer getLexicalAnalyzer() {
141
        return this.lexer;
142
    }
143
    
144
    @Override
145
    public void setCodeBuilder(CodeBuilder codeBuilder) {
146
        this.codeBuilder = codeBuilder;
147
    }
148

    
149
    @Override
150
    public CodeBuilder getCodeBuilder() {
151
        return this.codeBuilder;
152
    }
153
    
154
    @Override
155
    public boolean isObjectAccessSupported() {
156
        return this.objectAccessSupported;
157
    }
158

    
159
    @Override
160
    public void setObjectAccessSupported(boolean objectAccessSupported) {
161
        this.objectAccessSupported = objectAccessSupported;
162
    }
163

    
164
    @Override
165
    public GrammarSet getGrammars() {
166
        return this.grammars;
167
    }
168

    
169
    @Override
170
    public Code compileExpression(String expression) {
171
        this.lexer.setSource(expression.trim());
172
        Code code = parse_expression();
173
        if( !this.lexer.isEOF() ) {
174
            throw new ExpressionSyntaxException(lexer);
175
        }
176
        return code;
177
    }
178

    
179
    public Code parse_expression() {
180
        Code code = parse_relational();
181
        return code;
182
    }
183

    
184
    public Code parse_relational() {
185
        Code op1 = parse_not();
186
        Code op2;
187
        while( true ) {
188
            Token token = lexer.look();
189
            switch( token.getType() ) {
190
            case Token.OP_OR:
191
                lexer.next();
192
                op2 = parse_not();
193
                if( op2==null ) {
194
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_OR_operator(),lexer);
195
                }
196
                op1 = codeBuilder.or(op1, op2);
197
                break;
198
            case Token.OP_AND:
199
                lexer.next();
200
                op2 = parse_not();
201
                if( op2==null ) {
202
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_AND_operator(),lexer);
203
                }
204
                op1 = codeBuilder.and(op1, op2);
205
                break;
206
            default:
207
                return op1;
208
            }
209
        }
210
    }
211

    
212
    public Code parse_not() {
213
        Code op1;
214
        Token token = lexer.look();
215
        if( token.getType() == Token.OP_NOT ) {
216
            lexer.next();
217
            op1 = parse_conditional();
218
            op1 = codeBuilder.not(op1);
219
        } else {
220
            op1 = parse_conditional();
221
        }
222
        return op1;
223
    }
224

    
225
    public Code parse_conditional() {
226
        Code op1 = parse_sum();
227
        Code op2;
228
        while( true ) {
229
            Token token = lexer.look();
230
            switch( token.getType() ) {
231
            case Token.OP_LT:
232
                lexer.next();
233
                op2 = parse_sum();
234
                if( op2==null ) {
235
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LT_operator(),lexer);
236
                }
237
                op1 = codeBuilder.lt(op1, op2);
238
                break;
239
            case Token.OP_GT:
240
                lexer.next();
241
                op2 = parse_sum();
242
                if( op2==null ) {
243
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_GT_operator(),lexer);
244
                }
245
                op1 = codeBuilder.gt(op1, op2);
246
                break;
247
            case Token.OP_LE:
248
                lexer.next();
249
                op2 = parse_sum();
250
                if( op2==null ) {
251
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LE_operator(),lexer);
252
                }
253
                op1 = codeBuilder.le(op1, op2);
254
                break;
255
            case Token.OP_GE:
256
                lexer.next();
257
                op2 = parse_sum();
258
                if( op2==null ) {
259
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_GE_operator(),lexer);
260
                }
261
                op1 = codeBuilder.ge(op1, op2);
262
                break;
263
            case Token.OP_EQ:
264
                lexer.next();
265
                op2 = parse_sum();
266
                if( op2==null ) {
267
                    token = lexer.look();
268
                    String tip = null;
269
                    switch(token.getType()) {
270
                        case Token.OP_GT:
271
                            tip = I18N.The_operator_greater_than_or_equal_is_ge();
272
                            break;
273
                        case Token.OP_LT:
274
                            tip = I18N.The_operator_less_than_or_equal_is_ge();
275
                            break;
276
                    }
277
                    throw new ExpressionSyntaxException(
278
                            I18N.Cant_recognize_the_second_operand_of_EQ_operator(),
279
                            lexer,
280
                            tip
281
                    );
282
                }
283
                op1 = codeBuilder.eq(op1, op2);
284
                break;
285
            case Token.OP_NE:
286
                lexer.next();
287
                op2 = parse_sum();
288
                if( op2==null ) {
289
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_NEQ_operator(),lexer);
290
                }
291
                op1 = codeBuilder.ne(op1, op2);
292
                break;
293
            case Token.PRED_IS: {
294
                    lexer.next();
295
                    Token next = lexer.look();
296
                    switch(next.getType()) {
297
                        case Token.NOTNULL:
298
                            lexer.next();
299
                            op1 = codeBuilder.is(op1, codeBuilder.constant(null));
300
                            op1 = codeBuilder.not(op1);
301
                            break;
302
                        case Token.OP_NOT:
303
                            lexer.next();
304
                            next = lexer.look();
305
                            if( next.getType() == Token.NULL ) {
306
                                lexer.next();
307
                                op1 = codeBuilder.is(op1, codeBuilder.constant(null));
308
                            } else {
309
                                op2 = parse_sum();
310
                                if( op2==null ) {
311
                                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_IS_operator(),lexer);
312
                                }
313
                                op1 = codeBuilder.is(op1, op2);
314
                            }
315
                            op1 = codeBuilder.not(op1);
316
                            break;
317
                        case Token.NULL:
318
                            lexer.next();
319
                            op1 = codeBuilder.is(op1, codeBuilder.constant(null));
320
                            break;
321
                        default:    
322
                            op2 = parse_sum();
323
                            if( op2==null ) {
324
                                throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_IS_operator(),lexer);
325
                            }
326
                            op1 = codeBuilder.is(op1, op2);
327
                    }
328
                }
329
                break;
330
            case Token.ISNULL:
331
                lexer.next();
332
                op1 = codeBuilder.is(op1, codeBuilder.constant(null));
333
                break;
334
            case Token.OP_REGEXP:
335
                lexer.next();
336
                op2 = parse_sum();
337
                if( op2==null ) {
338
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_REGEXP_operator(),lexer);
339
                }
340
                op1 = codeBuilder.regexp(op1, op2);
341
                break;
342
            case Token.PRED_LIKE:
343
                lexer.next();
344
                op2 = parse_sum();
345
                if( op2==null ) {
346
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LIKE_operator(),lexer);
347
                }
348
                op1 = codeBuilder.like(op1, op2);
349
                break;
350
            case Token.PRED_ILIKE:
351
                lexer.next();
352
                op2 = parse_sum();
353
                if( op2==null ) {
354
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_ILIKE_operator(),lexer);
355
                }
356
                op1 = codeBuilder.ilike(op1, op2);
357
                break;
358
            default:
359
                return op1;
360
            }
361
        }
362
    }
363

    
364
    public Code parse_sum() {
365
        Code op1 = parse_factor();
366
        Code op2;
367
        while( true ) {
368
            Token token = lexer.look();
369
            switch( token.getType() ) {
370
            case Token.OP_CONCAT:
371
                lexer.next();
372
                op2 = parse_factor();
373
                op1 = codeBuilder.concat(op1, op2);
374
                break;
375
            case Token.OP_ADD:
376
                lexer.next();
377
                op2 = parse_factor();
378
                op1 = codeBuilder.add(op1, op2);
379
                break;
380
            case Token.OP_SUBST:
381
                lexer.next();
382
                op2 = parse_factor();
383
                op1 = codeBuilder.subst(op1, op2);
384
                break;
385
            default:
386
                return op1;
387
            }
388
        }
389
    }
390

    
391
    public Code parse_factor() {
392
        Code op1 = parse_getattr();
393
        Code op2;
394
        while( true ) {
395
            Token token = lexer.look();
396
            switch( token.getType() ) {
397
            case Token.OP_MULT:
398
                lexer.next();
399
                op2 = parse_getattr();
400
                if( op2==null ) {
401
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_MULT_operator(),lexer);
402
                }
403
                op1 = codeBuilder.mult(op1, op2);
404
                break;
405
            case Token.OP_DIV:
406
                lexer.next();
407
                op2 = parse_getattr();
408
                if( op2==null ) {
409
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_DIV_operator(),lexer);
410
                }
411
                op1 = codeBuilder.div(op1, op2);
412
                break;
413
            case Token.OP_MOD:
414
                lexer.next();
415
                op2 = parse_getattr();
416
                if( op2==null ) {
417
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_MOD_operator(),lexer);
418
                }
419
                op1 = codeBuilder.mod(op1, op2);
420
                break;
421
            case Token.OPEN_BRACKET:
422
                lexer.next();
423
                Code codeIndex = parse_expression();
424
                if( codeIndex == null ) {
425
                    throw new ExpressionSyntaxException(I18N.unexpected_end_of_source(),lexer);
426
                }
427
                token = lexer.look();
428
                if( token.getType()!=Token.CLOSED_BRACKET) {
429
                    throw new ExpressionSyntaxException(I18N.A_XTokenX_was_expected_and_XliteralX_was_found("]", token.getLiteral()),lexer);
430
                }
431
                lexer.next();
432
                Code code = codeBuilder.getitem(op1, codeIndex);
433
                return code;
434
            default:
435
                return op1;
436
            }
437
        }
438
    }
439

    
440
    public Code parse_getattr() {
441
        Code op1 = parse_termino();
442
        if( !isObjectAccessSupported() ) {
443
            return op1;
444
        }
445
        while( true ) {
446
            Token next = lexer.look();
447
            switch( next.getType() ) {
448
            case Token.OP_GETATTR:
449
                lexer.next();
450
                next = lexer.look();
451
                if( next.getType()!=Token.IDENTIFIER ) {
452
                    throw new ExpressionSyntaxException(
453
                        I18N.An_attribute_identifier_was_expected_and_XliteralX_was_found(next.getLiteral()),
454
                        lexer
455
                    );
456
                }
457
                String id = (String) next.getLiteral();
458
                lexer.next();
459
                next = lexer.look();
460
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
461
                    lexer.next();
462
                    Codes args = parse_expressions(",");
463
                    next = lexer.next();
464
                    if( next.getType() != Token.PARENTHESIS_CLOSE ) {
465
                        throw new ExpressionSyntaxException(
466
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
467
                            lexer
468
                        );
469
                    }
470
                    op1 = codeBuilder.method(op1, id, args);
471
                } else {
472
                    op1 = codeBuilder.getattr(op1, id);
473
                }
474
                break;
475
            default:
476
                return op1;
477
            }
478
        }
479
    }    
480

    
481
    public Code parse_termino() {
482

    
483
        Token token = lexer.look();
484
        switch( token.getType() ) {
485
        case Token.PARENTHESIS_OPEN: {
486
                lexer.next();
487
                Code value = parse_expression();
488
                Token next = lexer.next();
489
                switch(next.getType()) {
490
                    case Token.PARENTHESIS_CLOSE:
491
                        break;
492
                    case Token.EOF:
493
                        throw new ExpressionSyntaxException(
494
                            I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
495
                            lexer
496
                        );
497
                    default:
498
                        throw new ExpressionSyntaxException(
499
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
500
                            lexer
501
                        );
502
                }
503
                return value;
504
            }
505
        case Token.IDENTIFIER: {
506
                Code code = parse_grammars();
507
                if( code!=null ) {
508
                    return code;
509
                }
510
                if( this.grammars.isReservedWord(token.getLiteral()) ) {
511
                    return null;
512
                }
513
                lexer.next();
514
                String id = (String) token.getLiteral();
515
                Token next = lexer.look();
516
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
517
                    lexer.next();
518
                    Codes args = parse_arguments();
519
                    next = lexer.next();
520
                    switch(next.getType()) {
521
                        case Token.PARENTHESIS_CLOSE:
522
                            break;
523
                        case Token.EOF:
524
                            throw new ExpressionSyntaxException(
525
                                I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
526
                                lexer
527
                            );
528
                        default:
529
                            throw new ExpressionSyntaxException(
530
                                I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
531
                                lexer
532
                            );
533
                    }
534
                    return codeBuilder.function(id, args);
535
                } else {
536
                    if( StringUtils.equalsIgnoreCase(id, "TRUE") ) {
537
                        return codeBuilder.constant(true);
538
                    }
539
                    if( StringUtils.equalsIgnoreCase(id, "FALSE") ) {
540
                        return codeBuilder.constant(false);
541
                    }
542
                    return codeBuilder.identifier(id);
543
                }
544
            }
545
        case Token.STRING_LITERAL:
546
            lexer.next();
547
            return codeBuilder.constant(token.getValue());
548
        case Token.INTEGER_LITERAL:
549
            lexer.next();
550
            return codeBuilder.constant(token.getValue());
551
        case Token.FLOATING_POINT_LITERAL:
552
            lexer.next();
553
            return codeBuilder.constant(token.getValue());
554
        case Token.NULL:
555
            lexer.next();
556
            return codeBuilder.constant(null);
557
        case Token.TRUE:
558
            lexer.next();
559
            return codeBuilder.constant(true);
560
        case Token.FALSE:
561
            lexer.next();
562
            return codeBuilder.constant(false);
563
        case Token.OP_SUBST:
564
            lexer.next();
565
            Code code = parse_termino();
566
            if( code.code()==Code.CONSTANT ) {
567
                BaseConstant c = (BaseConstant)code;
568
                if( c.value() instanceof Number ) {
569
                    c.value(NegOperator.negate((Number) c.value()));
570
                    return code;
571
                }
572
                throw new ExpressionSyntaxException(I18N.A_numeric_constant_was_expected_after_the_unary_operator_minus(),lexer);
573
            }
574
            return codeBuilder.negate(code);
575
        case Token.EOF:
576
            throw new ExpressionSyntaxException(I18N.unexpected_end_of_source(),lexer);
577
        default:
578
            return parse_grammars();
579
        }
580
    }
581

    
582
    public Codes parse_expressions(String sep) {
583
        BaseCodes codes = null;
584
        while( true ) {
585
            Code code = parse_expression();
586
            if( code!=null ) {
587
                if( codes == null ) {
588
                    codes = (BaseCodes) codeBuilder.args();
589
                }
590
                codes.add(code);
591
            }
592
            Token next = lexer.look();
593
            String literal = next.getLiteral();
594
            if( literal == null ) {
595
                return codes;
596
            }
597
            literal = literal.trim();
598
            if( sep.equals(literal) ) {
599
                lexer.next(); // Consume el ",".
600
            } else {
601
                return codes;
602
            }
603
        }
604
    }
605

    
606
    public Codes parse_arguments() {
607
        String sep = ",";
608
        BaseCodes codes = null;
609
        while( true ) {
610
            ((AbstractLexicalAnalyzer)lexer).push_state();
611
            String argName = null;
612
            Token tok0 = lexer.next();
613
            Token tok1 = lexer.next();
614
            if( tok0.getType()==Token.IDENTIFIER && tok1.is(":") ) {
615
              argName = (String) tok0.getValue();
616
            } else {
617
              ((AbstractLexicalAnalyzer)lexer).pop_state();
618
            }
619
            Code code = parse_expression();
620
            if( code!=null ) {
621
                if( codes == null ) {
622
                    codes = (BaseCodes) codeBuilder.args();
623
                }
624
                codes.add(argName, code);
625
            }
626
            Token next = lexer.look();
627
            String literal = next.getLiteral();
628
            if( literal == null ) {
629
                return codes;
630
            }
631
            literal = literal.trim();
632
            if( sep.equals(literal) ) {
633
                lexer.next(); // Consume el ",".
634
            } else {
635
                return codes;
636
            }
637
        }
638
    }
639

    
640
    private Code parse_grammars() {
641
        StatementContext context = new DefaultStatementContext();
642
        Code code;
643
        BaseCodes args = (BaseCodes) this.codeBuilder.args();
644
        Statement stmt = this.grammars.getApplicableStatement(context);
645
        while( stmt!=null ) {
646
            code = stmt.parse(context);
647
            args.add(code);
648
            stmt = this.grammars.getApplicableStatement(context);
649
        }
650
        switch(args.size()) {
651
            case 0 :
652
                code = null;
653
                break;
654
            case 1 :
655
                code = args.get(0);
656
                break;
657
            default:
658
                code = this.codeBuilder.function(CodeBlockFunction.NAME, args);
659
                break;
660
        }
661
        return code;
662
    }
663
}