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 / DefaultInterpreter.java @ 44139

History | View | Annotate | Download (9.13 KB)

1
package org.gvsig.expressionevaluator.impl;
2

    
3
import java.util.ArrayList;
4
import java.util.Comparator;
5
import java.util.Date;
6
import java.util.HashMap;
7
import java.util.List;
8
import java.util.Map;
9
import org.apache.commons.lang3.tuple.Pair;
10
import org.gvsig.expressionevaluator.SymbolTable;
11
import org.gvsig.expressionevaluator.Interpreter;
12
import org.gvsig.expressionevaluator.Code;
13
import org.gvsig.expressionevaluator.Code.Constant;
14
import org.gvsig.expressionevaluator.Code.Identifier;
15
import org.gvsig.expressionevaluator.Code.Caller;
16
import org.gvsig.expressionevaluator.Code.Method;
17
import org.gvsig.expressionevaluator.Codes;
18
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
19
import org.gvsig.expressionevaluator.Function;
20
import org.gvsig.expressionevaluator.impl.function.operator.BinaryOperator;
21
import org.gvsig.expressionevaluator.impl.function.programming.CallMethodFunction;
22
import org.gvsig.expressionevaluator.impl.function.operator.UnaryOperator;
23
import org.gvsig.expressionevaluator.impl.function.programming.ReturnFunction.ReturnException;
24

    
25
public class DefaultInterpreter implements Interpreter {
26

    
27
    private class DefaultCache implements Cache {
28
        
29
        private Map<Pair<Object,Object>,Pair<Object,Long>> data;
30
        
31
        public DefaultCache() {
32
            this.data = new  HashMap<>();
33
        }
34
        
35
        @Override
36
        public Object get(Object context, Object key) {
37
            Pair<Object, Long> v = this.data.get( Pair.of(context, key) );
38
            if( v == null ) {
39
                return null;
40
            }
41
            return v.getLeft();
42
        }
43

    
44
        @Override
45
        public void put(Object context, Object key, Object value) {
46
            if( this.data.size()>this.getMaxElements() ) {
47
                this.reduce();
48
            }
49
            this.data.put(Pair.of(context, key), Pair.of(value, new Date().getTime()));
50
        }
51

    
52
        @Override
53
        public void remove(Object context, Object key) {
54
            this.data.remove(Pair.of(context, key));
55
        }
56

    
57
        @Override
58
        public void removeAll() {
59
            this.data = new  HashMap<>();
60
        }
61

    
62
        private int getMaxElements() {
63
            return 100;
64
        }
65

    
66
        private void reduce() {
67
            List<Map.Entry<Pair<Object, Object>, Pair<Object, Long>>> entries = 
68
                new ArrayList<>(this.data.entrySet());
69
            entries.sort(new Comparator<Map.Entry<Pair<Object, Object>, Pair<Object, Long>>>() {
70
                @Override
71
                public int compare(Map.Entry<Pair<Object, Object>, Pair<Object, Long>> o1, Map.Entry<Pair<Object, Object>, Pair<Object, Long>> o2) {
72
                    return o1.getValue().getRight().compareTo(o2.getValue().getRight());
73
                }
74
            });
75
            for( int i=0; i<this.getMaxElements()/2; i++ ) {
76
                this.data.remove(entries.get(i).getKey());
77
            }
78
        }
79
        
80
    }
81
    
82
    private SymbolTable symbolTable = null;
83
    private Double accuracy;
84
    private Code currentCode;
85
    private Cache cache;
86

    
87
    public DefaultInterpreter() {
88
        this.cache = new DefaultCache();
89
    }
90

    
91
    @Override
92
    public Interpreter clone() throws CloneNotSupportedException {
93
        DefaultInterpreter other = (DefaultInterpreter) super.clone();
94
        other.cache = new DefaultCache();
95
        if( this.symbolTable!=null ) {
96
            other.symbolTable = this.symbolTable.clone();
97
        }
98
        
99
        return other;
100
    }
101
            
102
    @Override
103
    public Cache getCache() {
104
        return this.cache;
105
    }
106

    
107
    @Override
108
    public void setSymbolTable(SymbolTable symbolTable) {
109
        this.symbolTable = symbolTable;
110
    }
111

    
112
    @Override
113
    public SymbolTable getSymbolTable() {
114
        if( this.symbolTable==null ) {
115
            this.symbolTable = new DefaultSymbolTable();
116
        }
117
        return this.symbolTable;
118
    }
119
    @Override
120
    public Double getAccuracy() {
121
        return this.accuracy;
122
    }
123
    
124
    @Override
125
    public void setAccuracy(Double accuracy) {
126
        this.accuracy = accuracy;
127
    }
128

    
129
    @Override
130
    public Object run(Code code) {
131
        try {
132
            return this.runCode(code);
133
        } catch(ReturnException ex) {
134
            return ex.getValue();
135
        } catch(RuntimeException ex) {
136
            throw ex;
137
        } catch(Exception ex) {
138
            throw new ExpressionRuntimeException(code, "", ex);
139
        }
140
    }
141

    
142
    @Override
143
    public void link(Code code) {
144
        linkCode(code);
145
    }
146

    
147
    private void linkCode(Code code) {
148
        if( code.code() == Code.CALLER ) {
149
            Caller caller = (Caller) code;
150
            if( caller.function() == null ) {
151
                caller.function(this.getSymbolTable().function(caller.name()));
152
            }
153
            if( caller.args() != null ) {
154
                for( Code arg : caller.args() ) {
155
                    linkCode(arg);
156
                }
157
            }
158
        }
159
    }
160

    
161
    public Object runCode(Code code) throws Exception {
162
        this.currentCode = code;
163
        Object value = null;
164
        switch( code.code() ) {
165
        case Code.CONSTANT:
166
            value = ((Constant) code).value();
167
            break;
168

    
169
        case Code.IDENTIFIER:
170
            String name = ((Identifier) code).name();
171
            if( !this.getSymbolTable().exists(name) ) {
172
                throw new ExpressionRuntimeException(
173
                        code, 
174
                        I18N.Undefined_variable_XIdentifierX(name),
175
                        I18N.Use_single_quotes_to_enter_literal_strings()
176
                );
177
            }
178
            value = this.getSymbolTable().value(name);
179
            break;
180

    
181
        case Code.METHOD: {
182
                Method method = (Method) code;
183
                Function function = method.function();
184
                if( function == null ) {
185
                    Object obj = this.runCode(method.obj());
186
                    if( obj == null ) {
187
                        throw new NullPointerException("An object pointer was expected to invoke method "+method.methodname()+" and a null was received");
188
                    }
189
                    method.function(new CallMethodFunction(obj, method.methodname()));
190
                }
191
            }
192
        case Code.CALLER:
193
            Caller caller = (Caller) code;
194
            Function function = caller.function();
195
            if( function == null ) {
196
                function = this.getSymbolTable().function(caller.name());
197
                if( function == null ) {
198
                    throw new ExpressionRuntimeException(code, I18N.Undefined_function_XIdentifierX(caller.name()));
199
                }
200
                caller.function(function);
201
            }
202
            Codes args = caller.args();
203
            try {
204
                switch( caller.type() ) {
205
                case Caller.UNARY_OPERATOR:
206
                    if( args == null || args.size() != 1 ) {
207
                        throw new ExpressionRuntimeException(code, I18N.Number_of_argument_mistmatch_in_operator_XIdentifierX_expected_1_got_XargcX(function.name(),args==null?0:args.size()));
208
                    }
209
                    value = ((UnaryOperator) function).call(this, runCode(args.get(0)));
210
                    break;
211

    
212
                case Caller.BINARY_OPERATOR:
213
                    if( args == null || args.size() != 2 ) {
214
                        throw new ExpressionRuntimeException(code, I18N.Number_of_argument_mistmatch_in_operator_XIdentifierX_expected_2_got_XargcX(function.name(),args==null?0:args.size()));
215
                    }
216
                    value = ((BinaryOperator) function).call(this, runCode(args.get(0)), runCode(args.get(1)));
217
                    break;
218

    
219
                case Caller.FUNCTION:
220
                    int argc = (args == null) ? 0 : args.size();
221
                    if( !function.argc().contains(argc) ) {
222
                        throw new ExpressionRuntimeException(code, I18N.Number_of_argument_mistmatch_in_function_XIdentifierX_expected_XexpectedX_got_XfoundX(function.name(),function.argc(),argc));
223
                    }
224
                    if( function.useArgumentsInsteadObjects() ) {
225
                        value = function.call(this, args);
226
                    } else {
227
                        Object[] argvalues = new Object[argc];
228
                        if( args != null ) {
229
                            int i = 0;
230
                            for( Code arg : args ) {
231
                                argvalues[i++] = runCode(arg);
232
                            }
233
                        }
234
                        value = function.call(this, argvalues);
235
                    }
236
                }
237
            } catch (RuntimeException ex) {
238
                throw ex;
239
            } catch (Exception ex) {
240
                String argsstr = "???";
241
                try {
242
                    argsstr = args.toString();
243
                } catch(Exception ex2) {
244
                    // Ignore.
245
                }
246
                throw new ExpressionRuntimeException(code, I18N.Problems_calling_function_XIdentifierX_with_args_XargsX(function.name(),argsstr));
247
            }
248
            break;
249
            
250
        }
251
        this.currentCode = null;
252
        return value;
253
    }
254

    
255
    @Override
256
    public Code getCurrentCode() {
257
        return this.currentCode;
258
    }
259
}