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

History | View | Annotate | Download (21.5 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.ExpressionSyntaxException;
13
import org.gvsig.expressionevaluator.GrammarSet;
14
import org.gvsig.expressionevaluator.Statement;
15
import org.gvsig.expressionevaluator.Statement.StatementContext;
16
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseCodes;
17
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseConstant;
18
import org.gvsig.expressionevaluator.impl.function.operator.NegOperator;
19
import org.gvsig.expressionevaluator.impl.function.programming.CodeBlockFunction;
20

    
21
public class DefaultCompiler implements Compiler {
22

    
23
    class DefaultStatementContext implements StatementContext {
24

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

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

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

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

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

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

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

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

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

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

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

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

    
104
    public DefaultCompiler() {
105
        this.grammars = new DefaultGrammarSet();
106
        this.lexer = new SQLLexicalAnalyzer();
107
        this.codeBuilder = new DefaultCodeBuilder();
108
        this.objectAccessSupported = true;
109
    }
110

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

    
120
    @Override
121
    public void setLexicalAnalyzer(LexicalAnalyzer lexer) {
122
        this.lexer = lexer;
123
    }
124

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

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

    
145
    @Override
146
    public void setObjectAccessSupported(boolean objectAccessSupported) {
147
        this.objectAccessSupported = objectAccessSupported;
148
    }
149

    
150
    @Override
151
    public GrammarSet getGrammars() {
152
        return this.grammars;
153
    }
154

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

    
165
    public Code parse_expression() {
166
        Code code = parse_relational();
167
        return code;
168
    }
169

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

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

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

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

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

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

    
467
    public Code parse_termino() {
468

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

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

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