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

History | View | Annotate | Download (19.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.apache.commons.lang3.math.NumberUtils;
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.Code.Constant;
12
import org.gvsig.expressionevaluator.CodeBuilder;
13
import org.gvsig.expressionevaluator.Codes;
14
import org.gvsig.expressionevaluator.ExpressionBuilder;
15
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
16
import org.gvsig.expressionevaluator.GrammarSet;
17
import org.gvsig.expressionevaluator.Statement;
18
import org.gvsig.expressionevaluator.Statement.StatementContext;
19
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseCodes;
20
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseConstant;
21
import org.gvsig.expressionevaluator.impl.function.operator.NegOperator;
22

    
23
public class DefaultCompiler implements Compiler {
24

    
25
    class DefaultStatementContext implements StatementContext {
26

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

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

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

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

    
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
    }
93

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

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

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

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

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

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

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

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

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

    
163
    public Code parse_expression() {
164
        Code code = parse_relational();
165
        return code;
166
    }
167

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

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

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

    
326
    public Code parse_sum() {
327
        Code op1 = parse_factor();
328
        Code op2;
329
        while( true ) {
330
            Token token = lexer.look();
331
            switch( token.getType() ) {
332
            case Token.OP_CONCAT:
333
                lexer.next();
334
                op2 = parse_factor();
335
                op1 = codeBuilder.concat(op1, op2);
336
                break;
337
            case Token.OP_ADD:
338
                lexer.next();
339
                op2 = parse_factor();
340
                op1 = codeBuilder.add(op1, op2);
341
                break;
342
            case Token.OP_SUBST:
343
                lexer.next();
344
                op2 = parse_factor();
345
                op1 = codeBuilder.subst(op1, op2);
346
                break;
347
            default:
348
                return op1;
349
            }
350
        }
351
    }
352

    
353
    public Code parse_factor() {
354
        Code op1 = parse_getattr();
355
        Code op2;
356
        while( true ) {
357
            Token token = lexer.look();
358
            switch( token.getType() ) {
359
            case Token.OP_MULT:
360
                lexer.next();
361
                op2 = parse_getattr();
362
                if( op2==null ) {
363
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_MULT_operator(),lexer);
364
                }
365
                op1 = codeBuilder.mult(op1, op2);
366
                break;
367
            case Token.OP_DIV:
368
                lexer.next();
369
                op2 = parse_getattr();
370
                if( op2==null ) {
371
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_DIV_operator(),lexer);
372
                }
373
                op1 = codeBuilder.div(op1, op2);
374
                break;
375
            case Token.OP_MOD:
376
                lexer.next();
377
                op2 = parse_getattr();
378
                if( op2==null ) {
379
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_MOD_operator(),lexer);
380
                }
381
                op1 = codeBuilder.mod(op1, op2);
382
                break;
383
            case Token.OPEN_BRACKET:
384
                lexer.next();
385
                Code codeIndex = parse_expression();
386
                if( codeIndex == null ) {
387
                    throw new ExpressionSyntaxException(I18N.unexpected_end_of_source(),lexer);
388
                }
389
                token = lexer.look();
390
                if( token.getType()!=Token.CLOSED_BRACKET) {
391
                    throw new ExpressionSyntaxException(I18N.A_XTokenX_was_expected_and_XliteralX_was_found("]", token.getLiteral()),lexer);
392
                }
393
                lexer.next();
394
                Code code = codeBuilder.getitem(op1, codeIndex);
395
                return code;
396
            default:
397
                return op1;
398
            }
399
        }
400
    }
401

    
402
    public Code parse_getattr() {
403
        Code op1 = parse_termino();
404
        if( !isObjectAccessSupported() ) {
405
            return op1;
406
        }
407
        while( true ) {
408
            Token next = lexer.look();
409
            switch( next.getType() ) {
410
            case Token.OP_GETATTR:
411
                lexer.next();
412
                next = lexer.look();
413
                if( next.getType()!=Token.IDENTIFIER ) {
414
                    throw new ExpressionSyntaxException(
415
                        I18N.An_attribute_identifier_was_expected_and_XliteralX_was_found(next.getLiteral()),
416
                        lexer
417
                    );
418
                }
419
                String id = (String) next.getLiteral();
420
                lexer.next();
421
                next = lexer.look();
422
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
423
                    lexer.next();
424
                    Codes args = parse_expressions(",");
425
                    next = lexer.next();
426
                    if( next.getType() != Token.PARENTHESIS_CLOSE ) {
427
                        throw new ExpressionSyntaxException(
428
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
429
                            lexer
430
                        );
431
                    }
432
                    return codeBuilder.method(op1, id, args);
433
                } else {
434
                    return codeBuilder.getattr(op1, id);
435
                }
436
            default:
437
                return op1;
438
            }
439
        }
440
    }    
441

    
442
    public Code parse_termino() {
443

    
444
        Token token = lexer.look();
445
        switch( token.getType() ) {
446
        case Token.PARENTHESIS_OPEN: {
447
                lexer.next();
448
                Code value = parse_expression();
449
                Token next = lexer.next();
450
                switch(next.getType()) {
451
                    case Token.PARENTHESIS_CLOSE:
452
                        break;
453
                    case Token.EOF:
454
                        throw new ExpressionSyntaxException(
455
                            I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
456
                            lexer
457
                        );
458
                    default:
459
                        throw new ExpressionSyntaxException(
460
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
461
                            lexer
462
                        );
463
                }
464
                return value;
465
            }
466
        case Token.IDENTIFIER: {
467
                Code code = parse_grammars();
468
                if( code!=null ) {
469
                    return code;
470
                }
471
                if( this.grammars.isReservedWord(token.getLiteral()) ) {
472
                    return null;
473
                }
474
                lexer.next();
475
                String id = (String) token.getLiteral();
476
                Token next = lexer.look();
477
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
478
                    lexer.next();
479
                    Codes args = parse_expressions(",");
480
                    next = lexer.next();
481
                    switch(next.getType()) {
482
                        case Token.PARENTHESIS_CLOSE:
483
                            break;
484
                        case Token.EOF:
485
                            throw new ExpressionSyntaxException(
486
                                I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
487
                                lexer
488
                            );
489
                        default:
490
                            throw new ExpressionSyntaxException(
491
                                I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
492
                                lexer
493
                            );
494
                    }
495
                    return codeBuilder.function(id, args);
496
                } else {
497
                    return codeBuilder.identifier(id);
498
                }
499
            }
500
        case Token.STRING_LITERAL:
501
            lexer.next();
502
            return codeBuilder.constant(token.getValue());
503
        case Token.INTEGER_LITERAL:
504
            lexer.next();
505
            return codeBuilder.constant(token.getValue());
506
        case Token.FLOATING_POINT_LITERAL:
507
            lexer.next();
508
            return codeBuilder.constant(token.getValue());
509
        case Token.NULL:
510
            lexer.next();
511
            return codeBuilder.constant(null);
512
        case Token.TRUE:
513
            lexer.next();
514
            return codeBuilder.constant(true);
515
        case Token.FALSE:
516
            lexer.next();
517
            return codeBuilder.constant(false);
518
        case Token.OP_SUBST:
519
            lexer.next();
520
            Code code = parse_termino();
521
            if( code.code()==Code.CONSTANT ) {
522
                BaseConstant c = (BaseConstant)code;
523
                if( c.value() instanceof Number ) {
524
                    c.value(NegOperator.negate((Number) c.value()));
525
                    return code;
526
                }
527
                throw new ExpressionSyntaxException(I18N.A_numeric_constant_was_expected_after_the_unary_operator_minus(),lexer);
528
            }
529
            return codeBuilder.negate(code);
530
        case Token.EOF:
531
            throw new ExpressionSyntaxException(I18N.unexpected_end_of_source(),lexer);
532
        default:
533
            return parse_grammars();
534
        }
535
    }
536

    
537
    public Codes parse_expressions(String sep) {
538
        BaseCodes codes = null;
539
        while( true ) {
540
            Code code = parse_expression();
541
            if( code!=null ) {
542
                if( codes == null ) {
543
                    codes = (BaseCodes) codeBuilder.args();
544
                }
545
                codes.add(code);
546
            }
547
            Token next = lexer.look();
548
            String literal = next.getLiteral();
549
            if( literal == null ) {
550
                return codes;
551
            }
552
            literal = literal.trim();
553
            if( sep.equals(literal) ) {
554
                lexer.next(); // Consume el ",".
555
            } else {
556
                return codes;
557
            }
558
        }
559
    }
560

    
561
    private Code parse_grammars() {
562
        StatementContext context = new DefaultStatementContext();
563
        Statement stmt = this.grammars.getApplicableStatement(context);
564
        if( stmt!=null ) {
565
            Code code1 = stmt.parse(context);
566
            return code1;
567
        }
568
        return null;
569
    }
570
}