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

History | View | Annotate | Download (8.45 KB)

1 43512 jjdelcerro
package org.gvsig.expressionevaluator.impl;
2
3 43532 jjdelcerro
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 43512 jjdelcerro
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 43939 jjdelcerro
import org.gvsig.expressionevaluator.Code.Method;
18 43512 jjdelcerro
import org.gvsig.expressionevaluator.Function;
19 44009 jjdelcerro
import org.gvsig.expressionevaluator.Optimizer;
20 43512 jjdelcerro
import org.gvsig.expressionevaluator.impl.function.operator.BinaryOperator;
21 43939 jjdelcerro
import org.gvsig.expressionevaluator.impl.function.obj.InvokeMethodFunction;
22 43512 jjdelcerro
import org.gvsig.expressionevaluator.impl.function.operator.UnaryOperator;
23
24
public class DefaultInterpreter implements Interpreter {
25
26 43532 jjdelcerro
    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 43521 jjdelcerro
    private SymbolTable symbolTable = null;
79
    private Double accuracy;
80
    private Code currentCode;
81 43809 jjdelcerro
    private Cache cache;
82 43512 jjdelcerro
83
    public DefaultInterpreter() {
84 43532 jjdelcerro
        this.cache = new DefaultCache();
85 43512 jjdelcerro
    }
86
87
    @Override
88 43809 jjdelcerro
    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 43532 jjdelcerro
    public Cache getCache() {
100
        return this.cache;
101
    }
102
103
    @Override
104 43512 jjdelcerro
    public void setSymbolTable(SymbolTable symbolTable) {
105
        this.symbolTable = symbolTable;
106
    }
107
108
    @Override
109
    public SymbolTable getSymbolTable() {
110 43809 jjdelcerro
        if( this.symbolTable==null ) {
111 43939 jjdelcerro
            this.symbolTable = new DefaultSymbolTable();
112 43809 jjdelcerro
        }
113 43512 jjdelcerro
        return this.symbolTable;
114
    }
115
    @Override
116 43521 jjdelcerro
    public Double getAccuracy() {
117
        return this.accuracy;
118
    }
119
120
    @Override
121
    public void setAccuracy(Double accuracy) {
122
        this.accuracy = accuracy;
123
    }
124 44009 jjdelcerro
125 43521 jjdelcerro
    @Override
126 43512 jjdelcerro
    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 43939 jjdelcerro
        if( code.code() == Code.CALLER ) {
141 43512 jjdelcerro
            Caller caller = (Caller) code;
142
            if( caller.function() == null ) {
143 43809 jjdelcerro
                caller.function(this.getSymbolTable().function(caller.name()));
144 43512 jjdelcerro
            }
145 43521 jjdelcerro
            if( caller.args() != null ) {
146 43519 jjdelcerro
                for( Code arg : caller.args() ) {
147
                    linkCode(arg);
148
                }
149 43512 jjdelcerro
            }
150
        }
151
    }
152
153
    private Object runCode(Code code) throws Exception {
154 43521 jjdelcerro
        this.currentCode = code;
155 43512 jjdelcerro
        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 43809 jjdelcerro
            if( !this.getSymbolTable().exists(name) ) {
164 43512 jjdelcerro
                throw new RuntimeException("Variable '" + name + "' not found.");
165
            }
166 43809 jjdelcerro
            value = this.getSymbolTable().value(name);
167 43512 jjdelcerro
            break;
168
169 43939 jjdelcerro
        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 43512 jjdelcerro
        case Code.CALLER:
181
            Caller caller = (Caller) code;
182
            Function function = caller.function();
183
            if( function == null ) {
184 43809 jjdelcerro
                function = this.getSymbolTable().function(caller.name());
185 43512 jjdelcerro
                if( function == null ) {
186
                    throw new RuntimeException("Function '" + caller.name() + "' not found.");
187
                }
188
                caller.function(function);
189
            }
190
            Arguments args = caller.args();
191 43521 jjdelcerro
            try {
192
                switch( caller.type() ) {
193
                case Caller.UNARY_OPERATOR:
194
                    if( args == null || args.count() != 1 ) {
195 44006 jjdelcerro
                        throw new RuntimeException("Number of argument mistmatch in operator '"+function.name()+"', expected 1 got " + args.count() + ".");
196 43521 jjdelcerro
                    }
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 44006 jjdelcerro
                        throw new RuntimeException("Number of argument mistmatch in operator '"+function.name()+"', expected 2 got " + args.count() + ".");
203 43521 jjdelcerro
                    }
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 44006 jjdelcerro
                        throw new RuntimeException("Number of argument mistmatch in function '"+function.name()+"', expected " + function.argc() + " got " + argc + ".");
211 43521 jjdelcerro
                    }
212 43939 jjdelcerro
                    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 43521 jjdelcerro
                        }
222 43939 jjdelcerro
                        value = function.call(this, argvalues);
223 43521 jjdelcerro
                    }
224 43512 jjdelcerro
                }
225 43521 jjdelcerro
            } catch (Exception ex) {
226
                String argsstr = "???";
227
                try {
228
                    argsstr = args.toString();
229
                } catch(Exception ex2) {
230
                    // Ignore.
231 43512 jjdelcerro
                }
232 43521 jjdelcerro
                throw new RuntimeException("Problems calling function '"+function.name()+"' with args ("+argsstr+").", ex);
233 43512 jjdelcerro
            }
234 43939 jjdelcerro
            break;
235
236 43512 jjdelcerro
        }
237 43521 jjdelcerro
        this.currentCode = null;
238 43512 jjdelcerro
        return value;
239
    }
240 43521 jjdelcerro
241
    @Override
242
    public Code getCurrentCode() {
243
        return this.currentCode;
244
    }
245 43512 jjdelcerro
}