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

History | View | Annotate | Download (33.9 KB)

1
package org.gvsig.expressionevaluator.impl;
2

    
3
import java.util.HashMap;
4
import java.util.Map;
5
import java.util.Stack;
6
import java.util.function.Supplier;
7
import org.apache.commons.lang3.StringUtils;
8
import org.gvsig.expressionevaluator.Compiler;
9
import org.gvsig.expressionevaluator.LexicalAnalyzer;
10
import org.gvsig.expressionevaluator.LexicalAnalyzer.Token;
11
import org.gvsig.expressionevaluator.Code;
12
import org.gvsig.expressionevaluator.Code.Callable;
13
import org.gvsig.expressionevaluator.CodeBuilder;
14
import org.gvsig.expressionevaluator.Codes;
15
import static org.gvsig.expressionevaluator.ExpressionBuilder.FUNCTION_DICT;
16
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
17
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
18
import org.gvsig.expressionevaluator.GrammarSet;
19
import org.gvsig.expressionevaluator.MutableCodes;
20
import org.gvsig.expressionevaluator.Statement;
21
import org.gvsig.expressionevaluator.Statement.StatementContext;
22
import org.gvsig.expressionevaluator.UserOperator;
23
import static org.gvsig.expressionevaluator.UserOperator.OERATOR_PRECEDENCE_CONDITIONAL;
24
import static org.gvsig.expressionevaluator.UserOperator.OERATOR_PRECEDENCE_FACTOR;
25
import static org.gvsig.expressionevaluator.UserOperator.OERATOR_PRECEDENCE_RELATIONAL;
26
import static org.gvsig.expressionevaluator.UserOperator.OERATOR_PRECEDENCE_SUM;
27
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseConstant;
28
import org.gvsig.expressionevaluator.impl.function.operator.NegOperator;
29
import org.gvsig.expressionevaluator.impl.function.programming.$HostExpressionFunction;
30
import org.gvsig.expressionevaluator.impl.function.programming.CodeBlockFunction;
31
import org.gvsig.expressionevaluator.spi.AbstractLexicalAnalyzer;
32
import org.slf4j.Logger;
33
import org.slf4j.LoggerFactory;
34

    
35
public class DefaultCompiler implements Compiler {
36

    
37
    protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultCompiler.class);
38
    
39
    class DefaultStatementContext implements StatementContext {
40
      
41
        private class State {
42
          public String codeClassifier;
43
          public Map<String,Code> codes;
44
          public Object otherValues;
45
        }
46
        
47
        private State state;
48
        private final Stack<State> states;
49

    
50
        public DefaultStatementContext() {
51
          this.state = new State();
52
          this.states = new Stack<>();
53
        }
54
        
55
        @Override
56
        public void save_state() {
57
          this.trace("save_state");
58
          ((AbstractLexicalAnalyzer)lexer).save_state();
59
          this.states.push(state);
60
        }
61

    
62
        @Override
63
        public void restore_state() {
64
          ((AbstractLexicalAnalyzer)lexer).restore_state();
65
          state = this.states.pop();
66
          this.trace("restore_state");
67
        }
68

    
69
        @Override
70
        public void drop_state() {
71
          ((AbstractLexicalAnalyzer)lexer).drop_state();
72
          this.states.pop();
73
          this.trace("drop_state");
74
        }
75
        
76
        @Override
77
        public Compiler getCompiler() {
78
            return DefaultCompiler.this;
79
        }
80

    
81
        @Override
82
        public LexicalAnalyzer getLexicalAnalyzer() {
83
            return lexer;
84
        }
85

    
86
        @Override
87
        public void setCode(String id, Code code) {
88
            if( this.state.codes == null ) {
89
                this.state.codes = new HashMap<>();
90
            }
91
            if( !StringUtils.isBlank(this.state.codeClassifier) ) {
92
                if( id.contains("#") ) {
93
                    id = StringUtils.replace(id,"#",this.state.codeClassifier,1);
94
                }
95
            }
96
            this.state.codes.put(id.toUpperCase(), code);
97
        }
98

    
99
        @Override
100
        public Code getCode(String id) {
101
            if( this.state==null || this.state.codes==null ) {
102
                return null;
103
            }
104
            if( StringUtils.isBlank(id) ) {
105
                return null;
106
            }
107
            return this.state.codes.get(id.toUpperCase());
108
        }
109
        
110
        @Override
111
        public void setOtherValues(Object otherValues) {
112
            this.state.otherValues = otherValues;
113
        }
114
        
115
        @Override
116
        public void setCodeClassifier(String classifier) {
117
            this.state.codeClassifier = classifier;
118
        }
119

    
120
        @Override
121
        public Object getOtherValues() {
122
            return this.state.otherValues;
123
        }
124
        
125
        @Override
126
        public String getCodeClassifier() {
127
            return this.state.codeClassifier;
128
        }
129

    
130
        @Override
131
        public CodeBuilder getCodeBuilder() {
132
            return codeBuilder;
133
        }
134

    
135
        @Override
136
        public Token look_token() {
137
            return lexer.look();
138
        }
139

    
140
        @Override
141
        public Token next_token() {
142
            return lexer.next();
143
        }
144

    
145
        @Override
146
        public Code parse_expression(boolean allow_assignement) {
147
            return DefaultCompiler.this.parse_expression(allow_assignement);
148
        }
149

    
150
        @Override
151
        public Codes parse_expressions(String separator) {
152
            return DefaultCompiler.this.parse_expressions(separator);
153
        }
154
        
155
        @Override
156
        public Codes parse_expressions(String separator, String[] terminationTokens) {
157
            return DefaultCompiler.this.parse_expressions(separator, terminationTokens);
158
        }
159
        
160
        @Override
161
        public boolean isReservedWord(String s) {
162
            return grammars.isReservedWord(s);
163
        }
164
        
165
        @Override
166
        public void trace(String msg) {
167
//            LexicalAnalyzer lex = this.getLexicalAnalyzer();
168
//            String s = StringUtils.left(lex.getSource(), lex.getPosition()) + "[*]" + StringUtils.mid(lex.getSource(), lex.getPosition(), 200);
169
//            if( s.length()>200 ) {
170
//                s = "..."+StringUtils.mid(s, lex.getPosition()-100, 200)+"...";
171
//            }            
172
//            System.out.println(msg+". "+s);
173
        } 
174
    }
175

    
176
    private boolean objectAccessSupported;
177
    private LexicalAnalyzer lexer;
178
    private CodeBuilder codeBuilder;
179
    private final GrammarSet grammars;
180
    protected ExpressionEvaluatorManager manager;
181
    protected Map<String,String> compatibility;
182
    //
183
    // https://www.postgresql.org/docs/9.1/static/functions.html
184
    //
185

    
186
    public DefaultCompiler(ExpressionEvaluatorManager manager) {
187
        this.manager = manager;
188
        this.grammars = new DefaultGrammarSet();
189
        this.lexer = new SQLLexicalAnalyzer();
190
        this.codeBuilder = new DefaultCodeBuilder(manager);
191
        this.objectAccessSupported = true;
192
    }
193

    
194
    @Override
195
    public Compiler clone() throws CloneNotSupportedException {
196
        DefaultCompiler other = (DefaultCompiler) super.clone();
197
        other.lexer = lexer.clone();
198
        other.codeBuilder = codeBuilder.clone();
199
        
200
        return other;
201
    }
202

    
203
    @Override
204
    public void setLexicalAnalyzer(LexicalAnalyzer lexer) {
205
        this.lexer = lexer;
206
    }
207

    
208
    @Override
209
    public LexicalAnalyzer getLexicalAnalyzer() {
210
        return this.lexer;
211
    }
212
    
213
    @Override
214
    public void setCodeBuilder(CodeBuilder codeBuilder) {
215
        this.codeBuilder = codeBuilder;
216
    }
217

    
218
    @Override
219
    public CodeBuilder getCodeBuilder() {
220
        return this.codeBuilder;
221
    }
222
    
223
    @Override
224
    public boolean isObjectAccessSupported() {
225
        return this.objectAccessSupported;
226
    }
227

    
228
    @Override
229
    public void setObjectAccessSupported(boolean objectAccessSupported) {
230
        this.objectAccessSupported = objectAccessSupported;
231
    }
232

    
233
    @Override
234
    public GrammarSet getGrammars() {
235
        return this.grammars;
236
    }
237

    
238
    @Override
239
    public Code compileExpression(String expression) {
240
        if( StringUtils.isBlank(expression) ) {
241
            return this.getCodeBuilder().constant(null);
242
        }        
243
        
244
        this.lexer.setSource(expression.trim());
245
        Code code = parse_expression();
246
        if( !this.lexer.isEOF() ) {
247
            throw new ExpressionSyntaxException(lexer);
248
        }
249
        return code;
250
    }
251

    
252
    @Override
253
    public Code compileExpressionQuietly(String expression) {
254
        try {
255
            return this.compileExpression(expression);
256
        } catch(Throwable t) {
257
            return null;
258
        }
259
    }
260

    
261
    public Code parse_expression() {
262
        return this.parse_expression(true);
263
    }
264

    
265
    public Code parse_expression(boolean allow_assignement) {
266
        Code code = parse_relational();
267
        if( code != null && allow_assignement) {
268
            Token token = lexer.look();
269
            if( token.is("AS") ) {
270
                lexer.next();
271
                token = lexer.look();
272
                if( token.getType() != Token.IDENTIFIER ) {
273
                    throw new ExpressionSyntaxException(
274
                        I18N.An_identifier_was_expected_and_XliteralX_was_found(token.getLiteral()),
275
                        lexer
276
                    );                    
277
                }
278
                token = lexer.next();
279
                code = codeBuilder.let(token.getLiteral(),code);
280
            }
281
        }
282
        return code;
283
    }
284

    
285
    protected Code parse_user_operator(String precedence, Code op1, Supplier<Code>op2) {
286
        for (UserOperator operator : this.manager.getUserDefinedOperators(precedence)) {
287
            Code userop = operator.parse(lexer, codeBuilder, op1, op2);
288
            if( userop != null ) {
289
                return userop;
290
            }
291
        }
292
        return op1;
293
    }
294
        
295
    public Code parse_relational() {
296
        Code op1 = parse_not();
297
        Code op2;
298
        while( true ) {
299
            Token token = lexer.look();
300
            switch( token.getType() ) {
301
            case Token.PRED_IN:
302
                lexer.next();
303
                Token next = lexer.look();
304
                if( next.getType()==Token.PARENTHESIS_OPEN ) {
305
                    lexer.next();
306
                    Codes v = parse_arguments();
307
                    next = lexer.next();
308
                    switch(next.getType()) {
309
                        case Token.PARENTHESIS_CLOSE:
310
                            break;
311
                        case Token.EOF:
312
                            throw new ExpressionSyntaxException(
313
                                I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
314
                                lexer
315
                            );
316
                        default:
317
                            throw new ExpressionSyntaxException(
318
                                I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
319
                                lexer
320
                            );
321
                    }
322
                    op2 = codeBuilder.tuple(v);
323
                } else {
324
                    op2 = parse_not();
325
                }
326
                op1 = codeBuilder.in(op1, op2);
327
                break;
328
            case Token.OP_OR:
329
                lexer.next();
330
                op2 = parse_not();
331
                if( op2==null ) {
332
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_OR_operator(),lexer);
333
                }
334
                op1 = codeBuilder.or(op1, op2);
335
                break;
336
            case Token.OP_AND:
337
                lexer.next();
338
                op2 = parse_not();
339
                if( op2==null ) {
340
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_AND_operator(),lexer);
341
                }
342
                op1 = codeBuilder.and(op1, op2);
343
                break;
344
            default:
345
                op1 = parse_user_operator(OERATOR_PRECEDENCE_RELATIONAL, op1, () -> parse_not());
346
                return op1;
347
            }
348
        }
349
    }
350

    
351
    public Code parse_not() {
352
        Code op1;
353
        Token token = lexer.look();
354
        if( token.getType() == Token.OP_NOT ) {
355
            lexer.next();
356
            op1 = parse_conditional();
357
            op1 = codeBuilder.not(op1);
358
        } else {
359
            op1 = parse_conditional();
360
        }
361
        return op1;
362
    }
363

    
364
    public Code parse_conditional() {
365
        Code op1 = parse_sum();
366
        Code op2;
367
        while( true ) {
368
            Token token = lexer.look();
369
            switch( token.getType() ) {
370
            case Token.OP_LT:
371
                lexer.next();
372
                op2 = parse_sum();
373
                if( op2==null ) {
374
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LT_operator(),lexer);
375
                }
376
                op1 = codeBuilder.lt(op1, op2);
377
                break;
378
            case Token.OP_GT:
379
                lexer.next();
380
                op2 = parse_sum();
381
                if( op2==null ) {
382
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_GT_operator(),lexer);
383
                }
384
                op1 = codeBuilder.gt(op1, op2);
385
                break;
386
            case Token.OP_LE:
387
                lexer.next();
388
                op2 = parse_sum();
389
                if( op2==null ) {
390
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LE_operator(),lexer);
391
                }
392
                op1 = codeBuilder.le(op1, op2);
393
                break;
394
            case Token.OP_GE:
395
                lexer.next();
396
                op2 = parse_sum();
397
                if( op2==null ) {
398
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_GE_operator(),lexer);
399
                }
400
                op1 = codeBuilder.ge(op1, op2);
401
                break;
402
            case Token.OP_EQ:
403
                lexer.next();
404
                op2 = parse_sum();
405
                if( op2==null ) {
406
                    token = lexer.look();
407
                    String tip = null;
408
                    switch(token.getType()) {
409
                        case Token.OP_GT:
410
                            tip = I18N.The_operator_greater_than_or_equal_is_ge();
411
                            break;
412
                        case Token.OP_LT:
413
                            tip = I18N.The_operator_less_than_or_equal_is_ge();
414
                            break;
415
                    }
416
                    throw new ExpressionSyntaxException(
417
                            I18N.Cant_recognize_the_second_operand_of_EQ_operator(),
418
                            lexer,
419
                            tip
420
                    );
421
                }
422
                op1 = codeBuilder.eq(op1, op2);
423
                break;
424
            case Token.OP_NE:
425
                lexer.next();
426
                op2 = parse_sum();
427
                if( op2==null ) {
428
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_NEQ_operator(),lexer);
429
                }
430
                op1 = codeBuilder.ne(op1, op2);
431
                break;
432
            case Token.PRED_IS: {
433
                    lexer.next();
434
                    Token next = lexer.look();
435
                    switch(next.getType()) {
436
                        case Token.NOTNULL:
437
                            lexer.next();
438
                            op1 = codeBuilder.is(op1, codeBuilder.constant(null));
439
                            op1 = codeBuilder.not(op1);
440
                            break;
441
                        case Token.OP_NOT:
442
                            lexer.next();
443
                            next = lexer.look();
444
                            if( next.getType() == Token.NULL ) {
445
                                lexer.next();
446
                                op1 = codeBuilder.is(op1, codeBuilder.constant(null));
447
                            } else {
448
                                  // FIXME: https://www.postgresql.org/docs/current/functions-comparison.html
449
                                  // FIXME: Deberiamos soportar solo las constantes TRUE y FALSE
450
//                                op2 = parse_sum();
451
//                                if( op2==null ) {
452
                                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_IS_operator(),lexer);
453
//                                }
454
//                                op1 = codeBuilder.is(op1, op2);
455
                            }
456
                            op1 = codeBuilder.not(op1);
457
                            break;
458
                        case Token.NULL:
459
                            lexer.next();
460
                            op1 = codeBuilder.is(op1, codeBuilder.constant(null));
461
                            break;
462
                        default:    
463
                            // FIXME: https://www.postgresql.org/docs/current/functions-comparison.html
464
                            // FIXME: Deberiamos soportar solo las constantes TRUE y FALSE
465
//                            op2 = parse_sum();
466
//                            if( op2==null ) {
467
                                throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_IS_operator(),lexer);
468
//                            }
469
//                            op1 = codeBuilder.is(op1, op2);
470
                    }
471
                }
472
                break;
473
            case Token.ISNULL:
474
                lexer.next();
475
                op1 = codeBuilder.is(op1, codeBuilder.constant(null));
476
                break;
477
            case Token.OP_REGEXP:
478
                lexer.next();
479
                op2 = parse_sum();
480
                if( op2==null ) {
481
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_REGEXP_operator(),lexer);
482
                }
483
                op1 = codeBuilder.regexp(op1, op2);
484
                break;
485
            case Token.PRED_LIKE:
486
                lexer.next();
487
                op2 = parse_sum();
488
                if( op2==null ) {
489
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_LIKE_operator(),lexer);
490
                }
491
                op1 = codeBuilder.like(op1, op2);
492
                break;
493
            case Token.PRED_ILIKE:
494
                lexer.next();
495
                op2 = parse_sum();
496
                if( op2==null ) {
497
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_ILIKE_operator(),lexer);
498
                }
499
                op1 = codeBuilder.ilike(op1, op2);
500
                break;
501
            case Token.PRED_BETWEEN:
502
                lexer.next();
503
                op2 = parse_sum();
504
                if( op2==null ) {
505
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_operand_N_of_BETWEEN_operator(1),lexer);
506
                }
507
                Token next = lexer.next();
508
                if( next.getType() != Token.OP_AND ) {
509
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_operand_N_of_BETWEEN_operator(2),lexer);
510
                }
511
                Code op3 = parse_sum();
512
                op1 = codeBuilder.between(op1, op2, op3);
513
                break;
514

    
515
            default:
516
                op1 = parse_user_operator(OERATOR_PRECEDENCE_CONDITIONAL, op1, () -> parse_sum());
517
                return op1;
518
            }
519
        }
520
    }
521

    
522
    public Code parse_sum() {
523
        Code op1 = parse_factor();
524
        Code op2;
525
        while( true ) {
526
            Token token = lexer.look();
527
            switch( token.getType() ) {
528
            case Token.OP_CONCAT:
529
                lexer.next();
530
                op2 = parse_factor();
531
                op1 = codeBuilder.concat(op1, op2);
532
                break;
533
            case Token.OP_ADD:
534
                lexer.next();
535
                op2 = parse_factor();
536
                op1 = codeBuilder.add(op1, op2);
537
                break;
538
            case Token.OP_SUBST:
539
                lexer.next();
540
                op2 = parse_factor();
541
                op1 = codeBuilder.subst(op1, op2);
542
                break;
543
            default:
544
                op1 = parse_user_operator(OERATOR_PRECEDENCE_SUM, op1, () -> parse_factor());
545
                return op1;
546
            }
547
        }
548
    }
549

    
550
    public Code parse_factor() {
551
        Code op1 = parse_getattr();
552
        Code op2;
553
        while( true ) {
554
            Token token = lexer.look();
555
            switch( token.getType() ) {
556
            case Token.OP_MULT:
557
                lexer.next();
558
                op2 = parse_getattr();
559
                if( op2==null ) {
560
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_MULT_operator(),lexer);
561
                }
562
                op1 = codeBuilder.mult(op1, op2);
563
                break;
564
            case Token.OP_DIV:
565
                lexer.next();
566
                op2 = parse_getattr();
567
                if( op2==null ) {
568
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_DIV_operator(),lexer);
569
                }
570
                op1 = codeBuilder.div(op1, op2);
571
                break;
572
            case Token.OP_MOD:
573
                lexer.next();
574
                op2 = parse_getattr();
575
                if( op2==null ) {
576
                    throw new ExpressionSyntaxException(I18N.Cant_recognize_the_second_operand_of_MOD_operator(),lexer);
577
                }
578
                op1 = codeBuilder.mod(op1, op2);
579
                break;
580
            case Token.OPEN_BRACKET:
581
                lexer.next();
582
                Code codeIndex = parse_expression();
583
                if( codeIndex == null ) {
584
                    throw new ExpressionSyntaxException(I18N.unexpected_end_of_source(),lexer);
585
                }
586
                token = lexer.look();
587
                if( token.getType()!=Token.CLOSED_BRACKET) {
588
                    throw new ExpressionSyntaxException(I18N.A_XTokenX_was_expected_and_XliteralX_was_found("]", token.getLiteral()),lexer);
589
                }
590
                lexer.next();
591
                Code code = codeBuilder.getitem(op1, codeIndex);
592
                return code;
593
            default:
594
                op1 = parse_user_operator(OERATOR_PRECEDENCE_FACTOR, op1, () -> parse_getattr());
595
                return op1;
596
            }
597
        }
598
    }
599

    
600
    public Code parse_getattr() {
601
        Code op1 = parse_colon();
602
        if( !isObjectAccessSupported() ) {
603
            return op1;
604
        }
605
        while( true ) {
606
            Token next = lexer.look();
607
            switch( next.getType() ) {
608
            case Token.OP_GETATTR:
609
                lexer.next();
610
                next = lexer.look();
611
                if( next.getType()!=Token.IDENTIFIER ) {
612
                    throw new ExpressionSyntaxException(
613
                        I18N.An_attribute_identifier_was_expected_and_XliteralX_was_found(next.getLiteral()),
614
                        lexer
615
                    );
616
                }
617
                String id = (String) next.getLiteral();
618
                lexer.next();
619
                next = lexer.look();
620
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
621
                    lexer.next();
622
                    Codes args = parse_expressions(",");
623
                    next = lexer.next();
624
                    if( next.getType() != Token.PARENTHESIS_CLOSE ) {
625
                        throw new ExpressionSyntaxException(
626
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
627
                            lexer
628
                        );
629
                    }
630
                    op1 = codeBuilder.method(op1, id, args);
631
                } else {
632
                    op1 = codeBuilder.getattr(op1, id);
633
                }
634
                break;
635
            default:
636
                return op1;
637
            }
638
        }
639
    }    
640

    
641
    public Code parse_colon() { 
642
        Token token = lexer.look();
643
        if( token.getType() == Token.COLON ) {
644
            // Con esto pretendemos simular el uso de los ":" de SQLJ.
645
            // 
646
            // https://docs.oracle.com/cd/A87860_01/doc/java.817/a83723/blangfe3.htm
647
            // Basic Host Expression Syntax
648
            //
649
            // Solo estamos dando soporte al especificador de modo "IN".
650
            lexer.next();
651
            token = lexer.look();
652
            String mode_specifier = null;
653
            if( token.getType() == Token.IDENTIFIER )  {
654
                switch(token.getLiteral().trim().toUpperCase()) {
655
                    case $HostExpressionFunction.MODE_SPECIFIER_IN:
656
                        lexer.next();
657
                        mode_specifier = $HostExpressionFunction.MODE_SPECIFIER_IN;
658
                        break;
659
                    case $HostExpressionFunction.MODE_SPECIFIER_OUT:
660
                        lexer.next();
661
                        mode_specifier = $HostExpressionFunction.MODE_SPECIFIER_OUT;
662
                        break;
663
                    case $HostExpressionFunction.MODE_SPECIFIER_INOUT:
664
                        lexer.next();
665
                        mode_specifier = $HostExpressionFunction.MODE_SPECIFIER_INOUT;
666
                        break;
667
                    case $HostExpressionFunction.MODE_SPECIFIER_ID:
668
                        lexer.next();
669
                        mode_specifier = $HostExpressionFunction.MODE_SPECIFIER_ID;
670
                        break;
671
                }
672
            } else if( token.getType() == Token.PRED_IN )  {
673
                lexer.next();
674
                mode_specifier = $HostExpressionFunction.MODE_SPECIFIER_IN;
675
            }
676

    
677
            Code op = parse_termino();
678
            if( mode_specifier == null ) {
679
                return codeBuilder.$HostExpression(op);
680
            } 
681
            return codeBuilder.$HostExpression(op, mode_specifier);
682
        }
683
        return parse_termino();
684
    }
685
    
686
    @SuppressWarnings("UnusedAssignment")
687
    public Code parse_termino() {
688

    
689
        Token token = lexer.look();
690
        switch( token.getType() ) {
691
        case Token.PARENTHESIS_OPEN: {
692
                lexer.next();
693
                Code value = parse_expression();
694
                Token next = lexer.next();
695
                switch(next.getType()) {
696
                    case Token.PARENTHESIS_CLOSE:
697
                        break;
698
                    case Token.EOF:
699
                        throw new ExpressionSyntaxException(
700
                            I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
701
                            lexer
702
                        );
703
                    default:
704
                        throw new ExpressionSyntaxException(
705
                            I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
706
                            lexer
707
                        );
708
                }
709
                return value;
710
            }
711
        case Token.IDENTIFIER: {
712
                Code code = parse_grammars();
713
                if( code!=null ) {
714
                    return code;
715
                }
716
                if( this.grammars.isReservedWord(token.getLiteral()) ) {
717
                    return null;
718
                }
719
                lexer.next();
720
                String id = (String) token.getLiteral();
721
                Token next = lexer.look();
722
                if( next.getType() == Token.PARENTHESIS_OPEN ) {
723
                    next = lexer.next();
724
                    Codes args = parse_arguments();
725
                    next = lexer.next();
726
                    switch(next.getType()) {
727
                        case Token.PARENTHESIS_CLOSE:
728
                            break;
729
                        case Token.EOF:
730
                            throw new ExpressionSyntaxException(
731
                                I18N.Closing_parenthesis_was_expected_and_end_of_source_was_found(),
732
                                lexer
733
                            );
734
                        default:
735
                            throw new ExpressionSyntaxException(
736
                                I18N.Closing_parenthesis_was_expected_and_XliteralX_was_found(next.getLiteral()),
737
                                lexer
738
                            );
739
                    }
740
                    // Optimizacion para cuando se esta invocando a la funcion dict
741
                    if( StringUtils.equalsIgnoreCase(id, FUNCTION_DICT) && args!=null && args.size()==1 ) {
742
                        code = args.get(0);
743
                        if( code.code()==Code.CALLABLE && 
744
                            StringUtils.equalsIgnoreCase(((Callable)code).name(),FUNCTION_DICT) ) {
745
                            return code;
746
                        }
747
                    }
748
                    return codeBuilder.function(id, args);
749
                } else {
750
                    if( StringUtils.equalsIgnoreCase(id, "TRUE") ) {
751
                        return codeBuilder.constant(true);
752
                    }
753
                    if( StringUtils.equalsIgnoreCase(id, "FALSE") ) {
754
                        return codeBuilder.constant(false);
755
                    }
756
                    return codeBuilder.identifier(id);
757
                }
758
            }
759
        case Token.STRING_LITERAL: 
760
            lexer.next();
761
            return codeBuilder.constant(token.getValue());
762
        case Token.INTEGER_LITERAL:
763
            lexer.next();
764
            return codeBuilder.constant(token.getValue());
765
        case Token.FLOATING_POINT_LITERAL:
766
            lexer.next();
767
            return codeBuilder.constant(token.getValue());
768
        case Token.NULL:
769
            lexer.next();
770
            return codeBuilder.constant(null);
771
        case Token.TRUE:
772
            lexer.next();
773
            return codeBuilder.constant(true);
774
        case Token.FALSE:
775
            lexer.next();
776
            return codeBuilder.constant(false);
777
        case Token.OP_SUBST:
778
            lexer.next();
779
            Code code = parse_termino();
780
            if( code.code()==Code.CONSTANT ) {
781
                BaseConstant c = (BaseConstant)code;
782
                if( c.value() instanceof Number ) {
783
                    c.value(NegOperator.negate((Number) c.value()));
784
                    return code;
785
                }
786
                throw new ExpressionSyntaxException(I18N.A_numeric_constant_was_expected_after_the_unary_operator_minus(),lexer);
787
            }
788
            return codeBuilder.negate(code);
789
        case Token.EOF:
790
            throw new ExpressionSyntaxException(I18N.unexpected_end_of_source(),lexer);
791
        default:
792
            return parse_grammars();
793
        }
794
    }
795

    
796
    public Codes parse_expressions(String sep) {
797
        return parse_expressions(sep, null);
798
    }
799
    
800
    public Codes parse_expressions(String sep, String[] terminationTokens) {
801
        MutableCodes codes = null;
802
        while( true ) {
803
            if( terminationTokens != null ) {
804
                Token next = lexer.look();
805
                String literal = next.getLiteral();
806
                if( literal == null ) {
807
                    return codes;
808
                }
809
                if( StringUtils.containsAny(literal, terminationTokens) ) {
810
                    return codes;
811
                }
812
            }
813
            Code code = parse_expression();
814
            if( code!=null ) {
815
                if( codes == null ) {
816
                    codes = codeBuilder.args();
817
                }
818
                codes.add(code);
819
            }
820
            Token next = lexer.look();
821
            String literal = next.getLiteral();
822
            if( literal == null ) {
823
                return codes;
824
            }
825
            literal = literal.trim();
826
            if( sep.equals(literal) ) {
827
                lexer.next(); // Consume el ",".
828
            } else {
829
                return codes;
830
            }
831
        }
832
    }
833

    
834
    private String getKeyArgument() {
835
        ((AbstractLexicalAnalyzer)lexer).save_state();
836
        Token next = lexer.look();
837
        if( next.getType()==Token.IDENTIFIER ) {
838
            String key = next.getLiteral();
839
            lexer.next(); 
840
            next = lexer.next();
841
            if( next.is(":","=","=>") ) {
842
                ((AbstractLexicalAnalyzer)lexer).drop_state();
843
                return key;
844
            }
845
        }
846
        ((AbstractLexicalAnalyzer)lexer).restore_state();
847
        return null;
848
    }
849
    
850
    public Codes parse_arguments() {
851
        String sep = ",";
852
        MutableCodes codes = null;
853
        Map<String,Code> kwargs = null;
854
        while( true ) {
855
            String key = getKeyArgument();
856
            if( key == null ) {
857
                if( kwargs != null ) {
858
                    throw new ExpressionSyntaxException(I18N.nonkeyword_arg_after_keyword_arg(),lexer);
859
                }
860
                Code code = parse_expression();
861
                if( code!=null ) {
862
                    if( codes == null ) {
863
                        codes = codeBuilder.args();
864
                    }
865
                    codes.add(code);
866
                }
867
            } else {
868
                if( kwargs == null ) {
869
                    kwargs = new HashMap<>();
870
                }
871
                Code code = parse_expression();
872
                kwargs.put(key, code);
873
            }
874
            Token next = lexer.look();
875
            if( !next.is(sep) ) {
876
                break;
877
            }
878
            lexer.next(); // Consume el ",".
879
        }
880
        if( kwargs!=null ) {
881
            if( codes == null ) {
882
                codes = codeBuilder.args();
883
            }
884
            Code code = codeBuilder.dict(kwargs);
885
            codes.add(code);
886
        }
887
        return codes;
888
    }
889

    
890
    private Code parse_grammars() {
891
        StatementContext context = new DefaultStatementContext();
892
        Code code;
893
        MutableCodes args = this.codeBuilder.args();
894
        context.trace("compiler.parse_gramars");
895
        Statement stmt = this.grammars.getApplicableStatement(context);
896
        while( stmt!=null ) {
897
            code = stmt.parse(context);
898
            args.add(code);
899
            stmt = this.grammars.getApplicableStatement(context);
900
        }
901
        switch(args.size()) {
902
            case 0 :
903
                code = null;
904
                break;
905
            case 1 :
906
                code = args.get(0);
907
                break;
908
            default:
909
                code = this.codeBuilder.function(CodeBlockFunction.NAME, args);
910
                break;
911
        }
912
        return code;
913
    }
914

    
915
    @Override
916
    public void addCompatibility(String compatid, String value) {
917
        if( this.compatibility == null ) {
918
            this.compatibility = new HashMap<>();
919
        }
920
        this.compatibility.put(compatid, value);
921
    }
922

    
923
    @Override
924
    public String getCompatibility(String compatid) {
925
        if( this.compatibility == null ) {
926
            return null;
927
        }
928
        return this.compatibility.get(compatid);
929
    }
930
    
931
}