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 / DefaultOptimizer.java @ 44205

History | View | Annotate | Download (7.38 KB)

1
package org.gvsig.expressionevaluator.impl;
2

    
3
import org.gvsig.expressionevaluator.Optimizer;
4
import java.util.Collection;
5
import java.util.Collections;
6
import java.util.Iterator;
7
import org.gvsig.expressionevaluator.Code;
8
import org.gvsig.expressionevaluator.Code.Caller;
9
import org.gvsig.expressionevaluator.CodeBuilder;
10
import org.gvsig.expressionevaluator.Function;
11
import org.gvsig.expressionevaluator.Interpreter;
12
import org.gvsig.expressionevaluator.SymbolTable;
13
import org.gvsig.expressionevaluator.impl.DefaultCodeBuilder.BaseCodes;
14
import org.gvsig.tools.script.Script;
15

    
16
/**
17
 *
18
 * @author jjdelcerro
19
 */
20
public class DefaultOptimizer implements Optimizer {
21

    
22
    private static class OptimizerSymbolTable implements SymbolTable {
23

    
24
        private SymbolTable symbolTable;
25

    
26
        public OptimizerSymbolTable() {
27

    
28
        }
29

    
30
        public SymbolTable getSymbolTable() {
31
            return this.symbolTable;
32
        }
33

    
34
        public void setSymbolTable(SymbolTable symbolTable) {
35
            this.symbolTable = symbolTable;
36
        }
37

    
38
        @Override
39
        public String getName() {
40
            return "Optimizer";
41
        }
42

    
43
        @Override
44
        public void addSymbolTable(SymbolTable symbolTable) {
45
            throw new UnsupportedOperationException("Not supported yet.");
46
        }
47

    
48
        @Override
49
        public Function function(String name) {
50
            return this.symbolTable.function(name);
51
        }
52

    
53
        @Override
54
        public boolean exists(String name) {
55
            return false;
56
        }
57

    
58
        @Override
59
        public Object value(String name) {
60
            return null;
61
        }
62

    
63
        @Override
64
        public boolean isSQLCompatible(String name) {
65
            return false;
66
        }
67

    
68
        @Override
69
        public Collection<String> variables() {
70
            return Collections.EMPTY_LIST;
71
        }
72

    
73
        @Override
74
        public Collection<Function> functions() {
75
            return this.symbolTable.functions();
76
        }
77

    
78
        @Override
79
        public Collection<Script> scripts() {
80
            return this.symbolTable.scripts();
81
        }
82

    
83
        @Override
84
        @SuppressWarnings("CloneDoesntCallSuperClone")
85
        public SymbolTable clone() throws CloneNotSupportedException {
86
            throw new UnsupportedOperationException("Not supported yet.");
87
        }
88

    
89
        @Override
90
        public Iterator<Function> iterator() {
91
            return this.symbolTable.iterator();
92
        }
93

    
94
    }
95

    
96
    private final OptimizerSymbolTable symbolTable;
97
    private Interpreter interpreter;
98
    private CodeBuilder codeBuilder;
99

    
100
    public DefaultOptimizer() {
101
        this.symbolTable = new OptimizerSymbolTable();
102
    }
103

    
104
    public DefaultOptimizer(SymbolTable symbolTable) {
105
        this();
106
        this.symbolTable.setSymbolTable(symbolTable);
107
    }
108

    
109
    @Override
110
    public void setSymbolTable(SymbolTable symbolTable) {
111
        this.symbolTable.setSymbolTable(symbolTable);
112
    }
113

    
114
    @Override
115
    public SymbolTable getSymbolTable() {
116
        return this.symbolTable;
117
    }
118

    
119
    @Override
120
    public Interpreter getInterpreter() {
121
        if (this.interpreter == null) {
122
            this.interpreter = new DefaultInterpreter();
123
            this.interpreter.setSymbolTable(this.symbolTable);
124
        }
125
        return this.interpreter;
126
    }
127

    
128
    @Override
129
    public CodeBuilder getCodeBuilder() {
130
        if (this.codeBuilder == null) {
131
            this.codeBuilder = new DefaultCodeBuilder();
132
        }
133
        return this.codeBuilder;
134
    }
135

    
136
    @Override
137
    public Code optimize(SymbolTable symbolTable, Code code) {
138
        this.setSymbolTable(symbolTable);
139
        return this.optimize(code);
140
    }
141

    
142
    @Override
143
    public Code optimize(Code code) {
144
        code = this.doOptimize(code);
145
        return code;
146
    }
147

    
148
    private Code doOptimize(Code code) {
149
        switch (code.code()) {
150
            case Code.CALLER:
151
                Caller caller = (Caller) code;
152
                if (caller.function() == null) {
153
                    // resolve and link function
154
                    caller.function(this.getSymbolTable().function(caller.name()));
155
                }
156
                if (caller.function() instanceof FunctionOptimizer) {
157
                    return ((FunctionOptimizer) caller.function()).optimize(this, caller);
158
                } else {
159
                    switch (caller.type()) {
160
                        case Caller.BINARY_OPERATOR: {
161
                            Code op1 = this.doOptimize(caller.parameters().get(0));
162
                            Code op2 = this.doOptimize(caller.parameters().get(1));
163
                            if (caller.function().allowConstantFolding()) {
164
                                if (op1.code() == Code.CONSTANT && op2.code() == Code.CONSTANT) {
165
                                    Object value = this.getInterpreter().run(code);
166
                                    Code newCode = this.getCodeBuilder().constant(value);
167
                                    return newCode;
168
                                }
169
                                Code newCode = this.getCodeBuilder().operator(caller.name(), op1, op2);
170
                                return newCode;
171
                            }
172
                        }
173

    
174
                        case Code.Caller.UNARY_OPERATOR: {
175
                            Code op1 = this.doOptimize(caller.parameters().get(0));
176
                            if (caller.function().allowConstantFolding()
177
                                    && op1.code() == Code.CONSTANT) {
178
                                Object value = this.getInterpreter().run(code);
179
                                Code newCode = this.getCodeBuilder().constant(value);
180
                                return newCode;
181
                            }
182
                            return code;
183
                        }
184

    
185
                        case Code.Caller.FUNCTION:
186
                        default: {
187
                            BaseCodes newArgs = null;
188
                            boolean canOptimize = true;
189
                            if (caller.parameters() != null) {
190
                                newArgs = (BaseCodes) this.getCodeBuilder().args();
191
                                for (Code arg : caller.parameters()) {
192
                                    Code newArg = this.doOptimize(arg);
193
                                    newArgs.add(newArg);
194
                                    if (newArg.code() != Code.CONSTANT) {
195
                                        canOptimize = false;
196
                                    }
197
                                }
198
                            }
199
                            if (canOptimize && caller.function().allowConstantFolding()) {
200
                                Object value = this.getInterpreter().run(code);
201
                                Code newCode = this.getCodeBuilder().constant(value);
202
                                return newCode;
203
                            }
204
                            Code newCode = this.getCodeBuilder().function(
205
                                    caller.name(),
206
                                    caller.type(),
207
                                    newArgs
208
                            );
209
                            return newCode;
210
                        }
211
                    }
212
                }
213
//                break;//                break;
214
                
215
            case Code.CONSTANT:
216
            case Code.IDENTIFIER:
217
            case Code.METHOD:
218
            default:
219
                return code;
220
        }
221
    }
222
}