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

History | View | Annotate | Download (21.7 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

    
22
public class DefaultCompiler implements Compiler {
23

    
24
    class DefaultStatementContext implements StatementContext {
25

    
26
        private String codeClassifier;
27
        private Map<String,Code> codes;
28

    
29
        @Override
30
        public Compiler getCompiler() {
31
            return DefaultCompiler.this;
32
        }
33

    
34
        @Override
35
        public LexicalAnalyzer getLexicalAnalyzer() {
36
            return lexer;
37
        }
38

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

    
52
        @Override
53
        public Code getCode(String id) {
54
            return this.codes.get(id);
55
        }
56
        
57
        @Override
58
        public void setCodeClassifier(String classifier) {
59
            this.codeClassifier = classifier;
60
        }
61

    
62
        @Override
63
        public String getCodeClassifier() {
64
            return this.codeClassifier;
65
        }
66

    
67
        @Override
68
        public CodeBuilder getCodeBuilder() {
69
            return codeBuilder;
70
        }
71

    
72
        @Override
73
        public Token look_token() {
74
            return lexer.look();
75
        }
76

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

    
82
        @Override
83
        public Code parse_expression() {
84
            return DefaultCompiler.this.parse_expression();
85
        }
86

    
87
        @Override
88
        public Codes parse_expressions(String separator) {
89
            return DefaultCompiler.this.parse_expressions(separator);
90
        }
91
        
92
        public boolean isReservedWord(String s) {
93
            return grammars.isReservedWord(s);
94
        }
95
    }
96

    
97
    private boolean objectAccessSupported;
98
    private LexicalAnalyzer lexer;
99
    private CodeBuilder codeBuilder;
100
    private final GrammarSet grammars;
101
    protected ExpressionEvaluatorManager manager;
102
    //
103
    // https://www.postgresql.org/docs/9.1/static/functions.html
104
    //
105

    
106
    public DefaultCompiler(ExpressionEvaluatorManager manager) {
107
        this.manager = manager;
108
        this.grammars = new DefaultGrammarSet();
109
        this.lexer = new SQLLexicalAnalyzer();
110
        this.codeBuilder = new DefaultCodeBuilder(manager);
111
        this.objectAccessSupported = true;
112
    }
113

    
114
    @Override
115
    public Compiler clone() throws CloneNotSupportedException {
116
        DefaultCompiler other = (DefaultCompiler) super.clone();
117
        other.lexer = lexer.clone();
118
        other.codeBuilder = codeBuilder.clone();
119
        
120
        return other;
121
    }
122

    
123
    @Override
124
    public void setLexicalAnalyzer(LexicalAnalyzer lexer) {
125
        this.lexer = lexer;
126
    }
127

    
128
    @Override
129
    public LexicalAnalyzer getLexicalAnalyzer() {
130
        return this.lexer;
131
    }
132
    
133
    @Override
134
    public void setCodeBuilder(CodeBuilder codeBuilder) {
135
        this.codeBuilder = codeBuilder;
136
    }
137

    
138
    @Override
139
    public CodeBuilder getCodeBuilder() {
140
        return this.codeBuilder;
141
    }
142
    
143
    @Override
144
    public boolean isObjectAccessSupported() {
145
        return this.objectAccessSupported;
146
    }
147

    
148
    @Override
149
    public void setObjectAccessSupported(boolean objectAccessSupported) {
150
        this.objectAccessSupported = objectAccessSupported;
151
    }
152

    
153
    @Override
154
    public GrammarSet getGrammars() {
155
        return this.grammars;
156
    }
157

    
158
    @Override
159
    public Code compileExpression(String expression) {
160
        this.lexer.setSource(expression.trim());
161
        Code code = parse_expression();
162
        if( !this.lexer.isEOF() ) {
163
            throw new ExpressionSyntaxException(lexer);
164
        }
165
        return code;
166
    }
167

    
168
    public Code parse_expression() {
169
        Code code = parse_relational();
170
        return code;
171
    }
172

    
173
    public Code parse_relational() {
174
        Code op1 = parse_not();
175
        Code op2;
176
        while( true ) {
177
            Token token = lexer.look();
178
            switch( token.getType() ) {
179
            case Token.OP_OR:
180
                lexer.next();
181
                op2 = parse_not();
182
                if( op2==null ) {
183
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_OR_operator(),lexer);
184
                }
185
                op1 = codeBuilder.or(op1, op2);
186
                break;
187
            case Token.OP_AND:
188
                lexer.next();
189
                op2 = parse_not();
190
                if( op2==null ) {
191
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_AND_operator(),lexer);
192
                }
193
                op1 = codeBuilder.and(op1, op2);
194
                break;
195
            default:
196
                return op1;
197
            }
198
        }
199
    }
200

    
201
    public Code parse_not() {
202
        Code op1;
203
        Token token = lexer.look();
204
        if( token.getType() == Token.OP_NOT ) {
205
            lexer.next();
206
            op1 = parse_conditional();
207
            op1 = codeBuilder.not(op1);
208
        } else {
209
            op1 = parse_conditional();
210
        }
211
        return op1;
212
    }
213

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

    
353
    public Code parse_sum() {
354
        Code op1 = parse_factor();
355
        Code op2;
356
        while( true ) {
357
            Token token = lexer.look();
358
            switch( token.getType() ) {
359
            case Token.OP_CONCAT:
360
                lexer.next();
361
                op2 = parse_factor();
362
                op1 = codeBuilder.concat(op1, op2);
363
                break;
364
            case Token.OP_ADD:
365
                lexer.next();
366
                op2 = parse_factor();
367
                op1 = codeBuilder.add(op1, op2);
368
                break;
369
            case Token.OP_SUBST:
370
                lexer.next();
371
                op2 = parse_factor();
372
                op1 = codeBuilder.subst(op1, op2);
373
                break;
374
            default:
375
                return op1;
376
            }
377
        }
378
    }
379

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

    
429
    public Code parse_getattr() {
430
        Code op1 = parse_termino();
431
        if( !isObjectAccessSupported() ) {
432
            return op1;
433
        }
434
        while( true ) {
435
            Token next = lexer.look();
436
            switch( next.getType() ) {
437
            case Token.OP_GETATTR:
438
                lexer.next();
439
                next = lexer.look();
440
                if( next.getType()!=Token.IDENTIFIER ) {
441
                    throw new ExpressionSyntaxException(
442
                        I18N.An_attribute_identifier_was_expected_and_XliteralX_was_found(next.getLiteral()),
443
                        lexer
444
                    );
445
                }
446
                String id = (String) next.getLiteral();
447
                lexer.next();
448
                next = lexer.look();
449
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
450
                    lexer.next();
451
                    Codes args = parse_expressions(",");
452
                    next = lexer.next();
453
                    if( next.getType() != Token.PARENTHESIS_CLOSE ) {
454
                        throw new ExpressionSyntaxException(
455
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
456
                            lexer
457
                        );
458
                    }
459
                    op1 = codeBuilder.method(op1, id, args);
460
                } else {
461
                    op1 = codeBuilder.getattr(op1, id);
462
                }
463
                break;
464
            default:
465
                return op1;
466
            }
467
        }
468
    }    
469

    
470
    public Code parse_termino() {
471

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

    
571
    public Codes parse_expressions(String sep) {
572
        BaseCodes codes = null;
573
        while( true ) {
574
            Code code = parse_expression();
575
            if( code!=null ) {
576
                if( codes == null ) {
577
                    codes = (BaseCodes) codeBuilder.args();
578
                }
579
                codes.add(code);
580
            }
581
            Token next = lexer.look();
582
            String literal = next.getLiteral();
583
            if( literal == null ) {
584
                return codes;
585
            }
586
            literal = literal.trim();
587
            if( sep.equals(literal) ) {
588
                lexer.next(); // Consume el ",".
589
            } else {
590
                return codes;
591
            }
592
        }
593
    }
594

    
595
    private Code parse_grammars() {
596
        StatementContext context = new DefaultStatementContext();
597
        Code code;
598
        BaseCodes args = (BaseCodes) this.codeBuilder.args();
599
        Statement stmt = this.grammars.getApplicableStatement(context);
600
        while( stmt!=null ) {
601
            code = stmt.parse(context);
602
            args.add(code);
603
            stmt = this.grammars.getApplicableStatement(context);
604
        }
605
        switch(args.size()) {
606
            case 0 :
607
                code = null;
608
                break;
609
            case 1 :
610
                code = args.get(0);
611
                break;
612
            default:
613
                code = this.codeBuilder.function(CodeBlockFunction.NAME, args);
614
                break;
615
        }
616
        return code;
617
    }
618
}