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

History | View | Annotate | Download (8.4 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.impl.function.operator.BinaryOperator;
20
import org.gvsig.expressionevaluator.impl.function.obj.InvokeMethodFunction;
21
import org.gvsig.expressionevaluator.impl.function.operator.UnaryOperator;
22

    
23
public class DefaultInterpreter implements Interpreter {
24

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

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

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

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

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

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

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

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

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

    
107
    @Override
108
    public SymbolTable getSymbolTable() {
109
        if( this.symbolTable==null ) {
110
            this.symbolTable = new DefaultSymbolTable();
111
        }
112
        return this.symbolTable;
113
    }
114
    @Override
115
    public Double getAccuracy() {
116
        return this.accuracy;
117
    }
118
    
119
    @Override
120
    public void setAccuracy(Double accuracy) {
121
        this.accuracy = accuracy;
122
    }
123
    
124
    @Override
125
    public Object run(Code code) {
126
        try {
127
            return this.runCode(code);
128
        } catch (Exception ex) {
129
            throw new RuntimeException(ex);
130
        }
131
    }
132

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

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

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

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

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

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

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

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