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

History | View | Annotate | Download (13 KB)

1 43512 jjdelcerro
package org.gvsig.expressionevaluator.impl;
2
3
import org.gvsig.expressionevaluator.Compiler;
4
import org.gvsig.expressionevaluator.Code.Caller.Arguments;
5
import org.gvsig.expressionevaluator.LexicalAnalyzer;
6
import org.gvsig.expressionevaluator.LexicalAnalyzer.Token;
7
import org.gvsig.expressionevaluator.Code;
8
import org.gvsig.expressionevaluator.CodeBuilder;
9 43983 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
10 43512 jjdelcerro
11
public class DefaultCompiler implements Compiler {
12
13 43939 jjdelcerro
    private boolean objectAccessSupported;
14 43512 jjdelcerro
    private LexicalAnalyzer lexer;
15
    private CodeBuilder codeBuilder;
16 43532 jjdelcerro
    //
17
    // https://www.postgresql.org/docs/9.1/static/functions.html
18
    //
19 43512 jjdelcerro
20
    public DefaultCompiler() {
21
        this.lexer = new SQLLexicalAnalyzer();
22
        this.codeBuilder = new DefaultCodeBuilder();
23 43939 jjdelcerro
        this.objectAccessSupported = true;
24 43512 jjdelcerro
    }
25
26
    @Override
27 43809 jjdelcerro
    public Compiler clone() throws CloneNotSupportedException {
28
        DefaultCompiler other = (DefaultCompiler) super.clone();
29
        other.lexer = lexer.clone();
30
        other.codeBuilder = codeBuilder.clone();
31
32
        return other;
33
    }
34
35
    @Override
36 43512 jjdelcerro
    public void setLexicalAnalyzer(LexicalAnalyzer lexer) {
37
        this.lexer = lexer;
38
    }
39 43983 jjdelcerro
40
    @Override
41
    public LexicalAnalyzer getLexicalAnalyzer() {
42
        return this.lexer;
43
    }
44 43512 jjdelcerro
45
    @Override
46
    public void setCodeBuilder(CodeBuilder codeBuilder) {
47
        this.codeBuilder = codeBuilder;
48
    }
49 43809 jjdelcerro
50 43512 jjdelcerro
    @Override
51 43809 jjdelcerro
    public CodeBuilder getCodeBuilder() {
52
        return this.codeBuilder;
53
    }
54
55
    @Override
56 43939 jjdelcerro
    public boolean isObjectAccessSupported() {
57
        return this.objectAccessSupported;
58
    }
59
60
    @Override
61
    public void setObjectAccessSupported(boolean objectAccessSupported) {
62
        this.objectAccessSupported = objectAccessSupported;
63
    }
64
65
    @Override
66 43512 jjdelcerro
    public Code compileExpression(String expression) {
67 43983 jjdelcerro
        this.lexer.setSource(expression.trim());
68
        Code code = parseExpression();
69
        if( !this.lexer.isEOF() ) {
70
            throw new ExpressionSyntaxException(lexer);
71
        }
72
        return code;
73 43512 jjdelcerro
    }
74
75
    private Code parseExpression() {
76 43983 jjdelcerro
        Code code = parse_relational();
77
        return code;
78 43512 jjdelcerro
    }
79
80
    private Code parse_relational() {
81
        Code op1 = parse_not();
82
        Code op2;
83
        while( true ) {
84
            Token token = lexer.look();
85
            switch( token.getType() ) {
86
            case Token.OP_OR:
87
                lexer.next();
88
                op2 = parse_not();
89 43983 jjdelcerro
                if( op2==null ) {
90
                    throw new ExpressionSyntaxException(lexer);
91
                }
92 43512 jjdelcerro
                op1 = codeBuilder.or(op1, op2);
93
                break;
94
            case Token.OP_AND:
95
                lexer.next();
96
                op2 = parse_not();
97 43983 jjdelcerro
                if( op2==null ) {
98
                    throw new ExpressionSyntaxException(lexer);
99
                }
100 43512 jjdelcerro
                op1 = codeBuilder.and(op1, op2);
101
                break;
102
            default:
103
                return op1;
104
            }
105
        }
106
    }
107
108
    private Code parse_not() {
109
        Code op1;
110
        Token token = lexer.look();
111
        if( token.getType() == Token.OP_NOT ) {
112
            lexer.next();
113
            op1 = parse_conditional();
114
            op1 = codeBuilder.not(op1);
115
        } else {
116
            op1 = parse_conditional();
117
        }
118
        return op1;
119
    }
120
121
    private Code parse_conditional() {
122
        Code op1 = parse_sum();
123
        Code op2;
124
        while( true ) {
125
            Token token = lexer.look();
126
            switch( token.getType() ) {
127
            case Token.OP_LT:
128
                lexer.next();
129
                op2 = parse_sum();
130 43983 jjdelcerro
                if( op2==null ) {
131
                    throw new ExpressionSyntaxException(lexer);
132
                }
133 43512 jjdelcerro
                op1 = codeBuilder.lt(op1, op2);
134
                break;
135
            case Token.OP_GT:
136
                lexer.next();
137
                op2 = parse_sum();
138 43983 jjdelcerro
                if( op2==null ) {
139
                    throw new ExpressionSyntaxException(lexer);
140
                }
141 43512 jjdelcerro
                op1 = codeBuilder.gt(op1, op2);
142
                break;
143
            case Token.OP_LE:
144
                lexer.next();
145
                op2 = parse_sum();
146 43983 jjdelcerro
                if( op2==null ) {
147
                    throw new ExpressionSyntaxException(lexer);
148
                }
149 43512 jjdelcerro
                op1 = codeBuilder.le(op1, op2);
150
                break;
151
            case Token.OP_GE:
152
                lexer.next();
153
                op2 = parse_sum();
154 43983 jjdelcerro
                if( op2==null ) {
155
                    throw new ExpressionSyntaxException(lexer);
156
                }
157 43512 jjdelcerro
                op1 = codeBuilder.ge(op1, op2);
158
                break;
159
            case Token.OP_EQ:
160
                lexer.next();
161
                op2 = parse_sum();
162 43983 jjdelcerro
                if( op2==null ) {
163
                    throw new ExpressionSyntaxException(lexer);
164
                }
165 43512 jjdelcerro
                op1 = codeBuilder.eq(op1, op2);
166
                break;
167 43521 jjdelcerro
            case Token.OP_NE:
168 43512 jjdelcerro
                lexer.next();
169 43521 jjdelcerro
                op2 = parse_sum();
170 43983 jjdelcerro
                if( op2==null ) {
171
                    throw new ExpressionSyntaxException(lexer);
172
                }
173 43521 jjdelcerro
                op1 = codeBuilder.ne(op1, op2);
174
                break;
175
            case Token.PRED_IS: {
176
                    lexer.next();
177
                    Token next = lexer.look();
178
                    if( next.getType() == Token.NOTNULL ) {
179
                        op1 = codeBuilder.is(op1, codeBuilder.constant(null));
180
                        op1 = codeBuilder.not(op1);
181
                    } else {
182
                        op2 = parse_sum();
183 43983 jjdelcerro
                        if( op2==null ) {
184
                            throw new ExpressionSyntaxException(lexer);
185
                        }
186 43521 jjdelcerro
                        op1 = codeBuilder.is(op1, op2);
187
                    }
188 43512 jjdelcerro
                }
189 43521 jjdelcerro
                break;
190 43512 jjdelcerro
            case Token.ISNULL:
191
                lexer.next();
192
                op1 = codeBuilder.is(op1, codeBuilder.constant(null));
193
                break;
194 43532 jjdelcerro
            case Token.OP_REGEXP:
195
                lexer.next();
196
                op2 = parse_sum();
197 43983 jjdelcerro
                if( op2==null ) {
198
                    throw new ExpressionSyntaxException(lexer);
199
                }
200 43532 jjdelcerro
                op1 = codeBuilder.regexp(op1, op2);
201
                break;
202 43512 jjdelcerro
            case Token.PRED_LIKE:
203
                lexer.next();
204
                op2 = parse_sum();
205 43983 jjdelcerro
                if( op2==null ) {
206
                    throw new ExpressionSyntaxException(lexer);
207
                }
208 43512 jjdelcerro
                op1 = codeBuilder.like(op1, op2);
209
                break;
210
            case Token.PRED_ILIKE:
211
                lexer.next();
212
                op2 = parse_sum();
213 43983 jjdelcerro
                if( op2==null ) {
214
                    throw new ExpressionSyntaxException(lexer);
215
                }
216 43512 jjdelcerro
                op1 = codeBuilder.ilike(op1, op2);
217
                break;
218
            default:
219
                return op1;
220
            }
221
        }
222
    }
223
224
    private Code parse_sum() {
225
        Code op1 = parse_factor();
226
        Code op2;
227
        while( true ) {
228
            Token token = lexer.look();
229
            switch( token.getType() ) {
230
            case Token.OP_ADD:
231
                lexer.next();
232
                op2 = parse_factor();
233
                op1 = codeBuilder.add(op1, op2);
234
                break;
235
            case Token.OP_SUBST:
236
                lexer.next();
237
                op2 = parse_factor();
238
                op1 = codeBuilder.subst(op1, op2);
239
                break;
240
            default:
241
                return op1;
242
            }
243
        }
244
    }
245
246
    private Code parse_factor() {
247 43939 jjdelcerro
        Code op1 = parse_getattr();
248 43512 jjdelcerro
        Code op2;
249
        while( true ) {
250
            Token token = lexer.look();
251
            switch( token.getType() ) {
252
            case Token.OP_MULT:
253
                lexer.next();
254 43939 jjdelcerro
                op2 = parse_getattr();
255 43983 jjdelcerro
                if( op2==null ) {
256
                    throw new ExpressionSyntaxException(lexer);
257
                }
258 43512 jjdelcerro
                op1 = codeBuilder.mult(op1, op2);
259
                break;
260
            case Token.OP_DIV:
261
                lexer.next();
262 43939 jjdelcerro
                op2 = parse_getattr();
263 43983 jjdelcerro
                if( op2==null ) {
264
                    throw new ExpressionSyntaxException(lexer);
265
                }
266 43512 jjdelcerro
                op1 = codeBuilder.div(op1, op2);
267
                break;
268
            case Token.OP_MOD:
269
                lexer.next();
270 43939 jjdelcerro
                op2 = parse_getattr();
271 43983 jjdelcerro
                if( op2==null ) {
272
                    throw new ExpressionSyntaxException(lexer);
273
                }
274 43512 jjdelcerro
                op1 = codeBuilder.mod(op1, op2);
275
                break;
276
            default:
277
                return op1;
278
            }
279
        }
280
    }
281
282 43939 jjdelcerro
    private Code parse_getattr() {
283
        Code op1 = parse_termino();
284
        if( !isObjectAccessSupported() ) {
285
            return op1;
286
        }
287
        while( true ) {
288
            Token next = lexer.look();
289
            switch( next.getType() ) {
290
            case Token.OP_GETATTR:
291
                lexer.next();
292
                next = lexer.look();
293
                if( next.getType()!=Token.IDENTIFIER ) {
294 43983 jjdelcerro
                    throw new ExpressionSyntaxException(
295
                        "An attribute identifier was expected and '"+next.getLiteral()+"' was found",
296
                        lexer.getSource(),
297
                        lexer.getPosition()
298
                    );
299 43939 jjdelcerro
                }
300
                String id = (String) next.getLiteral();
301
                lexer.next();
302
                next = lexer.look();
303
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
304
                    lexer.next();
305
                    Arguments args = parseArgs();
306
                    next = lexer.next();
307
                    if( next.getType() != Token.PARENTHESIS_CLOSE ) {
308 43983 jjdelcerro
                        throw new ExpressionSyntaxException(
309
                            "Closing parenthesis was expected and '"+next.getLiteral()+"' was found",
310
                            lexer.getSource(),
311
                            lexer.getPosition()
312
                        );
313 43939 jjdelcerro
                    }
314
                    return codeBuilder.method(op1, id, args);
315
                } else {
316
                    return codeBuilder.getattr(op1, id);
317
                }
318
            default:
319
                return op1;
320
            }
321
        }
322
    }
323
324 43512 jjdelcerro
    private Code parse_termino() {
325
326
        Token token = lexer.look();
327
        switch( token.getType() ) {
328
        case Token.PARENTHESIS_OPEN: {
329 43521 jjdelcerro
                lexer.next();
330
                Code value = parseExpression();
331
                Token next = lexer.next();
332
                if( next.getType() != Token.PARENTHESIS_CLOSE ) {
333 43983 jjdelcerro
                    throw new ExpressionSyntaxException(
334
                        "Closing parenthesis was expected and '"+next.getLiteral()+"' was found",
335
                        lexer.getSource(),
336
                        lexer.getPosition()
337
                    );
338 43521 jjdelcerro
                }
339
                return value;
340 43512 jjdelcerro
            }
341
        case Token.IDENTIFIER: {
342
                lexer.next();
343 43521 jjdelcerro
                String id = (String) token.getLiteral();
344
                Token next = lexer.look();
345
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
346
                    lexer.next();
347
                    Arguments args = parseArgs();
348
                    next = lexer.next();
349
                    if( next.getType() != Token.PARENTHESIS_CLOSE ) {
350 43983 jjdelcerro
                        throw new ExpressionSyntaxException(
351
                            "Closing parenthesis was expected and '"+next.getLiteral()+"' was found",
352
                            lexer.getSource(),
353
                            lexer.getPosition()
354
                        );
355 43521 jjdelcerro
                    }
356
                    return codeBuilder.function(id, args);
357
                } else {
358
                    return codeBuilder.identifier(id);
359 43512 jjdelcerro
                }
360
            }
361
        case Token.STRING_LITERAL:
362
            lexer.next();
363
            return codeBuilder.constant(token.getValue());
364
        case Token.INTEGER_LITERAL:
365
            lexer.next();
366
            return codeBuilder.constant(token.getValue());
367
        case Token.FLOATING_POINT_LITERAL:
368
            lexer.next();
369
            return codeBuilder.constant(token.getValue());
370
        case Token.NULL:
371
            lexer.next();
372
            return codeBuilder.constant(null);
373
        case Token.TRUE:
374
            lexer.next();
375
            return codeBuilder.constant(true);
376
        case Token.FALSE:
377
            lexer.next();
378
            return codeBuilder.constant(false);
379
        }
380
        return null;
381
    }
382
383
    private Arguments parseArgs() {
384
        Arguments args = null;
385
        while( true ) {
386
            Code arg = parseExpression();
387 43519 jjdelcerro
            if( arg!=null ) {
388
                if( args == null ) {
389
                    args = codeBuilder.args();
390
                }
391 43809 jjdelcerro
                ((DefaultCodeBuilder.BaseArguments)args).add(arg);
392 43519 jjdelcerro
            }
393 43512 jjdelcerro
            Token next = lexer.look();
394
            switch( next.getType() ) {
395
            case Token.COMA:
396
                lexer.next(); // Consume el ",".
397
                break;
398
            default:
399
                return args;
400
            }
401
        }
402
    }
403
}