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

History | View | Annotate | Download (13.7 KB)

1 43512 jjdelcerro
package org.gvsig.expressionevaluator.impl;
2
3 44389 jjdelcerro
import java.io.OutputStreamWriter;
4
import java.io.Writer;
5 43532 jjdelcerro
import java.util.ArrayList;
6
import java.util.Comparator;
7
import java.util.Date;
8
import java.util.HashMap;
9
import java.util.List;
10
import java.util.Map;
11 44191 jjdelcerro
import java.util.Objects;
12 43532 jjdelcerro
import org.apache.commons.lang3.tuple.Pair;
13 43512 jjdelcerro
import org.gvsig.expressionevaluator.SymbolTable;
14
import org.gvsig.expressionevaluator.Interpreter;
15
import org.gvsig.expressionevaluator.Code;
16
import org.gvsig.expressionevaluator.Code.Constant;
17
import org.gvsig.expressionevaluator.Code.Identifier;
18 43939 jjdelcerro
import org.gvsig.expressionevaluator.Code.Method;
19 44139 jjdelcerro
import org.gvsig.expressionevaluator.Codes;
20 44098 jjdelcerro
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
21 43512 jjdelcerro
import org.gvsig.expressionevaluator.Function;
22 44389 jjdelcerro
import org.gvsig.expressionevaluator.MutableSymbolTable;
23 44154 jjdelcerro
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.RecursionControlSupport;
24 43512 jjdelcerro
import org.gvsig.expressionevaluator.impl.function.operator.BinaryOperator;
25
import org.gvsig.expressionevaluator.impl.function.operator.UnaryOperator;
26 44139 jjdelcerro
import org.gvsig.expressionevaluator.impl.function.programming.ReturnFunction.ReturnException;
27 44338 jjdelcerro
import org.gvsig.expressionevaluator.spi.AbstractSymbolTable;
28 44389 jjdelcerro
import org.gvsig.tools.resourcesstorage.ResourcesStorage;
29 44752 jjdelcerro
import org.gvsig.expressionevaluator.Code.Callable;
30 43512 jjdelcerro
31
public class DefaultInterpreter implements Interpreter {
32
33 44154 jjdelcerro
    public static int DEFAULT_MAX_RECURSION_LIMIT = 20;
34
35 43532 jjdelcerro
    private class DefaultCache implements Cache {
36
37
        private Map<Pair<Object,Object>,Pair<Object,Long>> data;
38
39
        public DefaultCache() {
40
            this.data = new  HashMap<>();
41
        }
42
43
        @Override
44
        public Object get(Object context, Object key) {
45
            Pair<Object, Long> v = this.data.get( Pair.of(context, key) );
46 44139 jjdelcerro
            if( v == null ) {
47
                return null;
48
            }
49 43532 jjdelcerro
            return v.getLeft();
50
        }
51
52
        @Override
53
        public void put(Object context, Object key, Object value) {
54
            if( this.data.size()>this.getMaxElements() ) {
55
                this.reduce();
56
            }
57
            this.data.put(Pair.of(context, key), Pair.of(value, new Date().getTime()));
58
        }
59
60
        @Override
61
        public void remove(Object context, Object key) {
62
            this.data.remove(Pair.of(context, key));
63
        }
64
65
        @Override
66
        public void removeAll() {
67
            this.data = new  HashMap<>();
68
        }
69
70
        private int getMaxElements() {
71
            return 100;
72
        }
73
74
        private void reduce() {
75
            List<Map.Entry<Pair<Object, Object>, Pair<Object, Long>>> entries =
76
                new ArrayList<>(this.data.entrySet());
77
            entries.sort(new Comparator<Map.Entry<Pair<Object, Object>, Pair<Object, Long>>>() {
78
                @Override
79
                public int compare(Map.Entry<Pair<Object, Object>, Pair<Object, Long>> o1, Map.Entry<Pair<Object, Object>, Pair<Object, Long>> o2) {
80
                    return o1.getValue().getRight().compareTo(o2.getValue().getRight());
81
                }
82
            });
83
            for( int i=0; i<this.getMaxElements()/2; i++ ) {
84
                this.data.remove(entries.get(i).getKey());
85
            }
86
        }
87
88
    }
89
90 43521 jjdelcerro
    private SymbolTable symbolTable = null;
91
    private Double accuracy;
92
    private Code currentCode;
93 43809 jjdelcerro
    private Cache cache;
94 44154 jjdelcerro
    private int maxRecursionLimit;
95 44191 jjdelcerro
    private boolean sqlCompatible = false;
96 44389 jjdelcerro
    private Writer writer ;
97
    private ResourcesStorage resourcesStorage;
98 43512 jjdelcerro
99
    public DefaultInterpreter() {
100 43532 jjdelcerro
        this.cache = new DefaultCache();
101 44154 jjdelcerro
        this.maxRecursionLimit = DEFAULT_MAX_RECURSION_LIMIT;
102 44389 jjdelcerro
        this.writer = new OutputStreamWriter(System.out);
103
        this.resourcesStorage = ResourcesStorage.EMPTY_RESOURCESSTORAGE;
104 43512 jjdelcerro
    }
105
106
    @Override
107 43809 jjdelcerro
    public Interpreter clone() throws CloneNotSupportedException {
108
        DefaultInterpreter other = (DefaultInterpreter) super.clone();
109
        other.cache = new DefaultCache();
110
        if( this.symbolTable!=null ) {
111
            other.symbolTable = this.symbolTable.clone();
112
        }
113
        return other;
114
    }
115 44389 jjdelcerro
116
    @Override
117
    public ResourcesStorage getResourcesStorage() {
118
        return resourcesStorage;
119
    }
120
121
    @Override
122
    public void setResourcesStorage(ResourcesStorage resourcesStorage) {
123
        if( resourcesStorage==null ) {
124
            this.resourcesStorage = ResourcesStorage.EMPTY_RESOURCESSTORAGE;
125
        } else {
126
            this.resourcesStorage = resourcesStorage;
127
        }
128
    }
129 44154 jjdelcerro
130 44338 jjdelcerro
    @Override
131 44389 jjdelcerro
    public Writer getWriter() {
132
        return this.writer;
133
    }
134
135
    @Override
136
    public void setWriter(Writer writer) {
137
        if( writer == null ) {
138
            writer = new OutputStreamWriter(System.out);
139
        }
140
        this.writer = writer;
141
    }
142
143
    @Override
144
    public Object call(SymbolTable symbolTable, String funcname, Object... args) throws Exception {
145 44838 jjdelcerro
      if( this.symbolTable==null ) {
146
        try {
147
            this.symbolTable = symbolTable;
148
            return this.call(funcname, args);
149
        } finally {
150
            this.symbolTable = null;
151
        }
152
      } else {
153 44389 jjdelcerro
        SymbolTable savedSymbolTable = this.symbolTable;
154
        try {
155
            symbolTable.addSymbolTable(this.symbolTable);
156
            this.symbolTable = symbolTable;
157
            return this.call(funcname, args);
158
        } finally {
159
            this.symbolTable = savedSymbolTable;
160
            symbolTable.removeSymbolTable(this.symbolTable);
161
        }
162 44838 jjdelcerro
      }
163 44389 jjdelcerro
    }
164
165
    @Override
166 44338 jjdelcerro
    public Object call(String function, Object... args) throws Exception {
167
        Function fn = this.symbolTable.function(function);
168
        Object value = fn.call(this, args);
169
        return value;
170
    }
171
172
    @Override
173
    public boolean hasFunction(String function) {
174 44389 jjdelcerro
        Function fn = this.getSymbolTable().function(function);
175 44338 jjdelcerro
        if( fn == null ) {
176
            return false;
177
        }
178 44533 jjdelcerro
//        if( fn instanceof AbstractSymbolTable.ScriptFunction ) {
179
//            return false;
180
//        }
181 44338 jjdelcerro
        return true;
182
    }
183
184 44154 jjdelcerro
    public int getMaxRecursionLimit() {
185
        return this.maxRecursionLimit;
186
    }
187 43809 jjdelcerro
188 44154 jjdelcerro
    public void setMaxRecursionLimit(int limit) {
189
        this.maxRecursionLimit = limit;
190
    }
191
192 43809 jjdelcerro
    @Override
193 43532 jjdelcerro
    public Cache getCache() {
194
        return this.cache;
195
    }
196
197
    @Override
198 43512 jjdelcerro
    public void setSymbolTable(SymbolTable symbolTable) {
199
        this.symbolTable = symbolTable;
200
    }
201
202
    @Override
203
    public SymbolTable getSymbolTable() {
204 43809 jjdelcerro
        if( this.symbolTable==null ) {
205 43939 jjdelcerro
            this.symbolTable = new DefaultSymbolTable();
206 43809 jjdelcerro
        }
207 43512 jjdelcerro
        return this.symbolTable;
208
    }
209
    @Override
210 43521 jjdelcerro
    public Double getAccuracy() {
211
        return this.accuracy;
212
    }
213
214
    @Override
215
    public void setAccuracy(Double accuracy) {
216
        this.accuracy = accuracy;
217
    }
218 44009 jjdelcerro
219 43521 jjdelcerro
    @Override
220 44191 jjdelcerro
    public void setSQLCompatible(boolean sqlCompatible) {
221
        this.sqlCompatible = sqlCompatible;
222
    }
223
224
    @Override
225
    public boolean isSQLCompatible() {
226
        return sqlCompatible;
227
    }
228
229
    @Override
230 44389 jjdelcerro
    public void run(MutableSymbolTable symbolTable, Code code) {
231 44838 jjdelcerro
      if( this.symbolTable==null ) {
232
        try {
233
            this.symbolTable = symbolTable;
234
            this.run(code);
235
        } finally {
236
            this.symbolTable = null;
237
        }
238
      } else {
239 44389 jjdelcerro
        SymbolTable savedSymbolTable = this.symbolTable;
240
        try {
241
            symbolTable.addSymbolTable(this.symbolTable);
242
            this.symbolTable = symbolTable;
243
            this.run(code);
244
        } finally {
245
            this.symbolTable = savedSymbolTable;
246
            symbolTable.removeSymbolTable(this.symbolTable);
247
        }
248 44838 jjdelcerro
      }
249 44389 jjdelcerro
    }
250
251
    @Override
252 43512 jjdelcerro
    public Object run(Code code) {
253
        try {
254
            return this.runCode(code);
255 44139 jjdelcerro
        } catch(ReturnException ex) {
256
            return ex.getValue();
257 44098 jjdelcerro
        } catch(RuntimeException ex) {
258
            throw ex;
259
        } catch(Exception ex) {
260
            throw new ExpressionRuntimeException(code, "", ex);
261 43512 jjdelcerro
        }
262
    }
263
264
    @Override
265
    public void link(Code code) {
266 44198 jjdelcerro
        code.link(this.getSymbolTable());
267 43512 jjdelcerro
    }
268
269 44139 jjdelcerro
    public Object runCode(Code code) throws Exception {
270 44154 jjdelcerro
        RecursionControlSupport recursionControl = null;
271
        if( code instanceof RecursionControlSupport ) {
272
            recursionControl = (RecursionControlSupport) code;
273
            if( !recursionControl.enterCode(this.maxRecursionLimit) ) {
274
                recursionControl.resetRecursionState();
275
                throw new ExpressionRuntimeException(code, I18N.Maximum_recursion_limit_exceeded());
276
            }
277
        }
278
        Object value = null;
279 43521 jjdelcerro
        this.currentCode = code;
280 44154 jjdelcerro
        try {
281
            switch( code.code() ) {
282
            case Code.CONSTANT:
283
                value = ((Constant) code).value();
284
                break;
285 43512 jjdelcerro
286 44154 jjdelcerro
            case Code.IDENTIFIER:
287
                String name = ((Identifier) code).name();
288
                if( !this.getSymbolTable().exists(name) ) {
289
                    throw new ExpressionRuntimeException(
290
                            code,
291
                            I18N.Undefined_variable_XIdentifierX(name),
292
                            I18N.Use_single_quotes_to_enter_literal_strings()
293
                    );
294
                }
295
                value = this.getSymbolTable().value(name);
296
                break;
297 43512 jjdelcerro
298 44154 jjdelcerro
            case Code.METHOD: {
299
                    Method method = (Method) code;
300 44243 jjdelcerro
                    Codes args = method.parameters();
301
                    int argc = (args == null) ? 0 : args.size();
302
                    Object[] argvalues = new Object[argc];
303
                    if( args != null ) {
304
                        int i = 0;
305
                        for( Code arg : args ) {
306
                            argvalues[i++] = runCode(arg);
307 44154 jjdelcerro
                        }
308 43939 jjdelcerro
                    }
309 44243 jjdelcerro
                    value = method.call(this, argvalues);
310
                    break;
311 43939 jjdelcerro
                }
312 44752 jjdelcerro
            case Code.CALLABLE:
313
                Callable caller = (Callable) code;
314 44154 jjdelcerro
                Function function = caller.function();
315 43512 jjdelcerro
                if( function == null ) {
316 44154 jjdelcerro
                    function = this.getSymbolTable().function(caller.name());
317
                    if( function == null ) {
318 45025 jjdelcerro
                        try {
319
                            function = (Function) this.getSymbolTable().value(caller.name());
320
                        } catch(Exception ex) {
321
                        }
322
                        if( function == null ) {
323
                            throw new ExpressionRuntimeException(code, I18N.Undefined_function_XIdentifierX(caller.name()));
324
                        }
325 44154 jjdelcerro
                    }
326
                    caller.function(function);
327 43512 jjdelcerro
                }
328 44207 jjdelcerro
//                if( !function.isSQLCompatible() && this.sqlCompatible ) {
329
//                    throw new ExpressionRuntimeException(code, I18N.Cant_use_non_SQL_compatible_functions(function.name()));
330
//                }
331 44198 jjdelcerro
                Codes args = caller.parameters();
332 44154 jjdelcerro
                try {
333
                    switch( caller.type() ) {
334 44752 jjdelcerro
                    case Callable.UNARY_OPERATOR:
335 44154 jjdelcerro
                        if( args == null || args.size() != 1 ) {
336
                            throw new ExpressionRuntimeException(code, I18N.Number_of_argument_mistmatch_in_operator_XIdentifierX_expected_1_got_XargcX(function.name(),args==null?0:args.size()));
337
                        }
338
                        value = ((UnaryOperator) function).call(this, runCode(args.get(0)));
339
                        break;
340 43521 jjdelcerro
341 44752 jjdelcerro
                    case Callable.BINARY_OPERATOR:
342 44154 jjdelcerro
                        if( args == null || args.size() != 2 ) {
343
                            throw new ExpressionRuntimeException(code, I18N.Number_of_argument_mistmatch_in_operator_XIdentifierX_expected_2_got_XargcX(function.name(),args==null?0:args.size()));
344
                        }
345
                        value = ((BinaryOperator) function).call(this, runCode(args.get(0)), runCode(args.get(1)));
346
                        break;
347 43521 jjdelcerro
348 44752 jjdelcerro
                    case Callable.FUNCTION:
349 44154 jjdelcerro
                        int argc = (args == null) ? 0 : args.size();
350
                        if( !function.argc().contains(argc) ) {
351
                            throw new ExpressionRuntimeException(code, I18N.Number_of_argument_mistmatch_in_function_XIdentifierX_expected_XexpectedX_got_XfoundX(function.name(),function.argc(),argc));
352
                        }
353
                        if( function.useArgumentsInsteadObjects() ) {
354
                            value = function.call(this, args);
355
                        } else {
356
                            Object[] argvalues = new Object[argc];
357
                            if( args != null ) {
358
                                int i = 0;
359
                                for( Code arg : args ) {
360
                                    argvalues[i++] = runCode(arg);
361
                                }
362 43939 jjdelcerro
                            }
363 44154 jjdelcerro
                            value = function.call(this, argvalues);
364 43521 jjdelcerro
                        }
365
                    }
366 44154 jjdelcerro
                } catch (RuntimeException ex) {
367
                    throw ex;
368
                } catch (Exception ex) {
369
                    String argsstr = "???";
370
                    try {
371 44191 jjdelcerro
                        argsstr = Objects.toString(args);
372 44154 jjdelcerro
                    } catch(Exception ex2) {
373
                        // Ignore.
374
                    }
375 44379 jjdelcerro
                    throw new ExpressionRuntimeException(code, I18N.Problems_calling_function_XIdentifierX_with_args_XargsX(function.name(),argsstr), ex);
376 43512 jjdelcerro
                }
377 44154 jjdelcerro
                break;
378
379 43512 jjdelcerro
            }
380 44154 jjdelcerro
        } finally {
381
            this.currentCode = null;
382
            if( recursionControl!=null ) {
383
                recursionControl.exitCode();
384
            }
385 43512 jjdelcerro
        }
386
        return value;
387
    }
388 43521 jjdelcerro
389
    @Override
390
    public Code getCurrentCode() {
391
        return this.currentCode;
392
    }
393 43512 jjdelcerro
}