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

History | View | Annotate | Download (6.97 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.Function;
18
import org.gvsig.expressionevaluator.impl.function.operator.BinaryOperator;
19
import org.gvsig.expressionevaluator.impl.function.operator.UnaryOperator;
20

    
21
public class DefaultInterpreter implements Interpreter {
22

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

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

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

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

    
55
        private int getMaxElements() {
56
            return 100;
57
        }
58

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

    
80
    public DefaultInterpreter() {
81
        this.symbolTable = SQLSymbolTable.getInstance();
82
        this.cache = new DefaultCache();
83
    }
84

    
85
    @Override
86
    public Cache getCache() {
87
        return this.cache;
88
    }
89

    
90
    @Override
91
    public void setSymbolTable(SymbolTable symbolTable) {
92
        this.symbolTable = symbolTable;
93
    }
94

    
95
    @Override
96
    public SymbolTable getSymbolTable() {
97
        return this.symbolTable;
98
    }
99
    @Override
100
    public Double getAccuracy() {
101
        return this.accuracy;
102
    }
103
    
104
    @Override
105
    public void setAccuracy(Double accuracy) {
106
        this.accuracy = accuracy;
107
    }
108
    
109
    @Override
110
    public Object run(Code code) {
111
        try {
112
            return this.runCode(code);
113
        } catch (Exception ex) {
114
            throw new RuntimeException(ex);
115
        }
116
    }
117

    
118
    @Override
119
    public void link(Code code) {
120
        linkCode(code);
121
    }
122

    
123
    private void linkCode(Code code) {
124
        if( code instanceof Caller ) {
125
            Caller caller = (Caller) code;
126
            if( caller.function() == null ) {
127
                caller.function(this.symbolTable.function(caller.name()));
128
            }
129
            if( caller.args() != null ) {
130
                for( Code arg : caller.args() ) {
131
                    linkCode(arg);
132
                }
133
            }
134
        }
135
    }
136

    
137
    private Object runCode(Code code) throws Exception {
138
        this.currentCode = code;
139
        Object value = null;
140
        switch( code.code() ) {
141
        case Code.CONSTANT:
142
            value = ((Constant) code).value();
143
            break;
144

    
145
        case Code.IDENTIFIER:
146
            String name = ((Identifier) code).name();
147
            if( !symbolTable.exists(name) ) {
148
                throw new RuntimeException("Variable '" + name + "' not found.");
149
            }
150
            value = symbolTable.value(name);
151
            break;
152

    
153
        case Code.CALLER:
154
            Caller caller = (Caller) code;
155
            Function function = caller.function();
156
            if( function == null ) {
157
                function = this.symbolTable.function(caller.name());
158
                if( function == null ) {
159
                    throw new RuntimeException("Function '" + caller.name() + "' not found.");
160
                }
161
                caller.function(function);
162
            }
163
            Arguments args = caller.args();
164
            try {
165
                switch( caller.type() ) {
166
                case Caller.UNARY_OPERATOR:
167
                    if( args == null || args.count() != 1 ) {
168
                        throw new RuntimeException("Number of argument mistmatch, expected 1 got " + args.count() + ".");
169
                    }
170
                    value = ((UnaryOperator) function).call(this, runCode(args.get(0)));
171
                    break;
172

    
173
                case Caller.BINARY_OPERATOR:
174
                    if( args == null || args.count() != 2 ) {
175
                        throw new RuntimeException("Number of argument mistmatch, expected 2 got " + args.count() + ".");
176
                    }
177
                    value = ((BinaryOperator) function).call(this, runCode(args.get(0)), runCode(args.get(1)));
178
                    break;
179

    
180
                case Caller.FUNCTION:
181
                    int argc = (args == null) ? 0 : args.count();
182
                    if( !function.argc().contains(argc) ) {
183
                        throw new RuntimeException("Number of argument mistmatch, expected " + function.argc() + " got " + argc + ".");
184
                    }
185
                    Object[] argvalues = new Object[argc];
186
                    if( args != null ) {
187
                        int i = 0;
188
                        for( Code arg : args ) {
189
                            argvalues[i++] = runCode(arg);
190
                        }
191
                    }
192
                    value = function.call(this, argvalues);
193
                }
194
            } catch (Exception ex) {
195
                String argsstr = "???";
196
                try {
197
                    argsstr = args.toString();
198
                } catch(Exception ex2) {
199
                    // Ignore.
200
                }
201
                throw new RuntimeException("Problems calling function '"+function.name()+"' with args ("+argsstr+").", ex);
202
            }
203
        }
204
        this.currentCode = null;
205
        return value;
206
    }
207

    
208
    @Override
209
    public Code getCurrentCode() {
210
        return this.currentCode;
211
    }
212
}