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

History | View | Annotate | Download (8.91 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.Caller.Arguments;
17
import org.gvsig.expressionevaluator.Code.Method;
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.obj.InvokeMethodFunction;
22
import org.gvsig.expressionevaluator.impl.function.operator.UnaryOperator;
23

    
24
public class DefaultInterpreter implements Interpreter {
25

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

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

    
48
        @Override
49
        public void remove(Object context, Object key) {
50
            this.data.remove(Pair.of(context, key));
51
        }
52

    
53
        @Override
54
        public void removeAll() {
55
            this.data = new  HashMap<>();
56
        }
57

    
58
        private int getMaxElements() {
59
            return 100;
60
        }
61

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

    
83
    public DefaultInterpreter() {
84
        this.cache = new DefaultCache();
85
    }
86

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

    
103
    @Override
104
    public void setSymbolTable(SymbolTable symbolTable) {
105
        this.symbolTable = symbolTable;
106
    }
107

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

    
125
    @Override
126
    public Object run(Code code) {
127
        try {
128
            return this.runCode(code);
129
        } catch(RuntimeException ex) {
130
            throw ex;
131
        } catch(Exception ex) {
132
            throw new ExpressionRuntimeException(code, "", ex);
133
        }
134
    }
135

    
136
    @Override
137
    public void link(Code code) {
138
        linkCode(code);
139
    }
140

    
141
    private void linkCode(Code code) {
142
        if( code.code() == Code.CALLER ) {
143
            Caller caller = (Caller) code;
144
            if( caller.function() == null ) {
145
                caller.function(this.getSymbolTable().function(caller.name()));
146
            }
147
            if( caller.args() != null ) {
148
                for( Code arg : caller.args() ) {
149
                    linkCode(arg);
150
                }
151
            }
152
        }
153
    }
154

    
155
    private Object runCode(Code code) throws Exception {
156
        this.currentCode = code;
157
        Object value = null;
158
        switch( code.code() ) {
159
        case Code.CONSTANT:
160
            value = ((Constant) code).value();
161
            break;
162

    
163
        case Code.IDENTIFIER:
164
            String name = ((Identifier) code).name();
165
            if( !this.getSymbolTable().exists(name) ) {
166
                throw new ExpressionRuntimeException(
167
                        code, 
168
                        I18N.Undefined_variable_XIdentifierX(name),
169
                        I18N.Use_single_quotes_to_enter_literal_strings()
170
                );
171
            }
172
            value = this.getSymbolTable().value(name);
173
            break;
174

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

    
206
                case Caller.BINARY_OPERATOR:
207
                    if( args == null || args.count() != 2 ) {
208
                        throw new ExpressionRuntimeException(code, I18N.Number_of_argument_mistmatch_in_operator_XIdentifierX_expected_2_got_XargcX(function.name(),args==null?0:args.count()));
209
                    }
210
                    value = ((BinaryOperator) function).call(this, runCode(args.get(0)), runCode(args.get(1)));
211
                    break;
212

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

    
249
    @Override
250
    public Code getCurrentCode() {
251
        return this.currentCode;
252
    }
253
}