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

History | View | Annotate | Download (7.39 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 Cache cache;
79

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

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

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

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

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

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

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

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

    
166
        case Code.CALLER:
167
            Caller caller = (Caller) code;
168
            Function function = caller.function();
169
            if( function == null ) {
170
                function = this.getSymbolTable().function(caller.name());
171
                if( function == null ) {
172
                    throw new RuntimeException("Function '" + caller.name() + "' not found.");
173
                }
174
                caller.function(function);
175
            }
176
            Arguments args = caller.args();
177
            try {
178
                switch( caller.type() ) {
179
                case Caller.UNARY_OPERATOR:
180
                    if( args == null || args.count() != 1 ) {
181
                        throw new RuntimeException("Number of argument mistmatch, expected 1 got " + args.count() + ".");
182
                    }
183
                    value = ((UnaryOperator) function).call(this, runCode(args.get(0)));
184
                    break;
185

    
186
                case Caller.BINARY_OPERATOR:
187
                    if( args == null || args.count() != 2 ) {
188
                        throw new RuntimeException("Number of argument mistmatch, expected 2 got " + args.count() + ".");
189
                    }
190
                    value = ((BinaryOperator) function).call(this, runCode(args.get(0)), runCode(args.get(1)));
191
                    break;
192

    
193
                case Caller.FUNCTION:
194
                    int argc = (args == null) ? 0 : args.count();
195
                    if( !function.argc().contains(argc) ) {
196
                        throw new RuntimeException("Number of argument mistmatch, expected " + function.argc() + " got " + argc + ".");
197
                    }
198
                    Object[] argvalues = new Object[argc];
199
                    if( args != null ) {
200
                        int i = 0;
201
                        for( Code arg : args ) {
202
                            argvalues[i++] = runCode(arg);
203
                        }
204
                    }
205
                    value = function.call(this, argvalues);
206
                }
207
            } catch (Exception ex) {
208
                String argsstr = "???";
209
                try {
210
                    argsstr = args.toString();
211
                } catch(Exception ex2) {
212
                    // Ignore.
213
                }
214
                throw new RuntimeException("Problems calling function '"+function.name()+"' with args ("+argsstr+").", ex);
215
            }
216
        }
217
        this.currentCode = null;
218
        return value;
219
    }
220

    
221
    @Override
222
    public Code getCurrentCode() {
223
        return this.currentCode;
224
    }
225
}