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

History | View | Annotate | Download (8.45 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.Function;
19
import org.gvsig.expressionevaluator.Optimizer;
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 (Exception ex) {
130
            throw new RuntimeException(ex);
131
        }
132
    }
133

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

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

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

    
161
        case Code.IDENTIFIER:
162
            String name = ((Identifier) code).name();
163
            if( !this.getSymbolTable().exists(name) ) {
164
                throw new RuntimeException("Variable '" + name + "' not found.");
165
            }
166
            value = this.getSymbolTable().value(name);
167
            break;
168

    
169
        case Code.METHOD: {
170
                Method method = (Method) code;
171
                Function function = method.function();
172
                if( function == null ) {
173
                    Object obj = this.runCode(method.obj());
174
                    if( obj == null ) {
175
                        throw new NullPointerException("An object pointer was expected to invoke method "+method.methodname()+" and a null was received");
176
                    }
177
                    method.function(new InvokeMethodFunction(obj, method.methodname()));
178
                }
179
            }
180
        case Code.CALLER:
181
            Caller caller = (Caller) code;
182
            Function function = caller.function();
183
            if( function == null ) {
184
                function = this.getSymbolTable().function(caller.name());
185
                if( function == null ) {
186
                    throw new RuntimeException("Function '" + caller.name() + "' not found.");
187
                }
188
                caller.function(function);
189
            }
190
            Arguments args = caller.args();
191
            try {
192
                switch( caller.type() ) {
193
                case Caller.UNARY_OPERATOR:
194
                    if( args == null || args.count() != 1 ) {
195
                        throw new RuntimeException("Number of argument mistmatch in operator '"+function.name()+"', expected 1 got " + args.count() + ".");
196
                    }
197
                    value = ((UnaryOperator) function).call(this, runCode(args.get(0)));
198
                    break;
199

    
200
                case Caller.BINARY_OPERATOR:
201
                    if( args == null || args.count() != 2 ) {
202
                        throw new RuntimeException("Number of argument mistmatch in operator '"+function.name()+"', expected 2 got " + args.count() + ".");
203
                    }
204
                    value = ((BinaryOperator) function).call(this, runCode(args.get(0)), runCode(args.get(1)));
205
                    break;
206

    
207
                case Caller.FUNCTION:
208
                    int argc = (args == null) ? 0 : args.count();
209
                    if( !function.argc().contains(argc) ) {
210
                        throw new RuntimeException("Number of argument mistmatch in function '"+function.name()+"', expected " + function.argc() + " got " + argc + ".");
211
                    }
212
                    if( function.useArgumentsInsteadObjects() ) {
213
                        value = function.call(this, args);
214
                    } else {
215
                        Object[] argvalues = new Object[argc];
216
                        if( args != null ) {
217
                            int i = 0;
218
                            for( Code arg : args ) {
219
                                argvalues[i++] = runCode(arg);
220
                            }
221
                        }
222
                        value = function.call(this, argvalues);
223
                    }
224
                }
225
            } catch (Exception ex) {
226
                String argsstr = "???";
227
                try {
228
                    argsstr = args.toString();
229
                } catch(Exception ex2) {
230
                    // Ignore.
231
                }
232
                throw new RuntimeException("Problems calling function '"+function.name()+"' with args ("+argsstr+").", ex);
233
            }
234
            break;
235
            
236
        }
237
        this.currentCode = null;
238
        return value;
239
    }
240

    
241
    @Override
242
    public Code getCurrentCode() {
243
        return this.currentCode;
244
    }
245
}