(refs #7375) Replaced collectFreeVariables method by a visitor
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EConstant.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.Set;
6
7 import org.simantics.scl.compiler.common.names.Name;
8 import org.simantics.scl.compiler.common.precedence.Precedence;
9 import org.simantics.scl.compiler.compilation.CompilationContext;
10 import org.simantics.scl.compiler.constants.Constant;
11 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
12 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
13 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
14 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
15 import org.simantics.scl.compiler.elaboration.errors.NotPatternException;
16 import org.simantics.scl.compiler.elaboration.expressions.lhstype.LhsType;
17 import org.simantics.scl.compiler.elaboration.expressions.lhstype.PatternMatchingLhs;
18 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
19 import org.simantics.scl.compiler.errors.Locations;
20 import org.simantics.scl.compiler.internal.codegen.references.IVal;
21 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
22 import org.simantics.scl.compiler.internal.interpreted.IConstant;
23 import org.simantics.scl.compiler.internal.interpreted.IExpression;
24 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
25 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
26 import org.simantics.scl.compiler.top.ValueNotFound;
27 import org.simantics.scl.compiler.types.TForAll;
28 import org.simantics.scl.compiler.types.TMetaVar;
29 import org.simantics.scl.compiler.types.Type;
30 import org.simantics.scl.compiler.types.Types;
31 import org.simantics.scl.compiler.types.exceptions.MatchException;
32 import org.simantics.scl.compiler.types.util.MultiFunction;
33 import org.simantics.scl.compiler.types.util.TypeUnparsingContext;
34
35 import gnu.trove.map.hash.TObjectIntHashMap;
36 import gnu.trove.set.hash.TIntHashSet;
37
38 public class EConstant extends Expression {
39     public SCLValue value;
40     Type[] typeParameters;
41     
42     public EConstant(SCLValue value, Type ... typeParameters) {
43         if(SCLCompilerConfiguration.DEBUG)
44             if(value == null)
45                 throw new NullPointerException();
46         this.value = value;
47         this.typeParameters = typeParameters;
48     }
49
50     public EConstant(SCLValue value) {
51         if(SCLCompilerConfiguration.DEBUG)
52             if(value == null)
53                 throw new NullPointerException();
54         this.value = value;
55         this.typeParameters = Type.EMPTY_ARRAY;
56     }
57
58     public EConstant(long loc, SCLValue value) {
59         super(loc);
60         if(SCLCompilerConfiguration.DEBUG)
61             if(value == null)
62                 throw new NullPointerException();
63         this.value = value;
64         this.typeParameters = Type.EMPTY_ARRAY;
65     }
66     
67     public EConstant(long loc, SCLValue value, Type ... typeParameters) {
68         super(loc);
69         if(SCLCompilerConfiguration.DEBUG)
70             if(value == null)
71                 throw new NullPointerException();
72         this.value = value;
73         this.typeParameters = typeParameters;
74     }
75
76     public void addTypeParameters(Type ... newTypeParameters) {
77         typeParameters = Types.concat(typeParameters, newTypeParameters);
78     }
79     
80     public Expression applyType(Type type) {
81         typeParameters = Types.concat(typeParameters, new Type[] {type});
82         if(getType() != null)
83             setType(Types.instantiate(getType(), type));
84         return this;
85     }
86
87     @Override
88     public void collectVars(TObjectIntHashMap<Variable> allVars,
89             TIntHashSet vars) {   
90     }
91     
92     @Override
93     public Set<Variable> getFreeVariables() {
94         return Collections.emptySet();
95     }
96
97     public void toString(StringBuilder b, TypeUnparsingContext tuc) {
98         Name name = value.getName();
99         if(name.module.equals("Builtin") || name.module.equals("Prelude"))
100             b.append(name.name);
101         else
102             b.append(name);
103         /*for(Type type : typeParameters) {
104             b.append(" <");
105             b.append(type.toString(tuc));
106             b.append(">");
107         }*/
108     }
109
110     @Override
111     protected void updateType() throws MatchException {
112         setType(Types.instantiate(value.getType(), typeParameters));
113     }
114     
115     @Override
116     public IVal toVal(CompilationContext context, CodeWriter w) {
117         IVal val = value.getValue();            
118         if(typeParameters.length > 0) {
119             val = val.createSpecialization(typeParameters);
120         }
121         return val;
122     }
123
124     @Override
125     public Expression simplify(SimplificationContext context) {
126         if(value.getInlineInSimplification()) {
127             if(typeParameters.length > 0) {
128                 context.getErrorLog().log(location, 
129                         "Inlining with type parameters not currently supported in simplification.");
130                 return this;
131             }
132             else
133                 return value.getExpression().copy().simplify(context);
134         }
135         return this;
136     }
137
138     @Override
139     public Expression resolve(TranslationContext context) {
140         return this;
141     }
142     
143     @Override
144     public void getParameters(TranslationContext translationContext,
145             ArrayList<Expression> parameters) {
146     }
147     
148     public SCLValue getValue() {
149         return value;
150     }
151     
152     @Override
153     public Expression resolveAsPattern(TranslationContext context) {
154         return this;
155     }
156
157     @Override
158     public Expression replace(ReplaceContext context) {
159         Type[] newTypeParameters;
160         if(typeParameters.length == 0)
161             newTypeParameters = Type.EMPTY_ARRAY;
162         else {
163             newTypeParameters = new Type[typeParameters.length];
164             for(int i=0;i<newTypeParameters.length;++i)
165                 newTypeParameters[i] = typeParameters[i].replace(context.tvarMap);
166         }
167         return new EConstant(value, newTypeParameters);
168     }
169     
170     public Type[] getTypeParameters() {
171         return typeParameters;
172     }
173
174     @Override
175     public LhsType getLhsType() throws NotPatternException {
176         return new PatternMatchingLhs();
177     }
178     
179     @Override
180     public IExpression toIExpression(ExpressionInterpretationContext target) {
181         Name name = value.getName();
182         try {
183             return new IConstant(target.runtimeEnvironment.getRuntimeModule(name.module).getValue(name.name));
184         } catch (ValueNotFound e) {
185             throw new UnsupportedOperationException();
186         }
187     }
188     
189     @Override
190     public Expression inferType(TypingContext context) {
191         if(context.recursiveValues != null &&
192                 context.recursiveValues.contains(value)) {
193             // Handles the case where the constant is one of the recursive definitions we are currently checking
194             // This kind of value is not yet generalized, i.e. it is not necessary to instantiate it.
195             EPlaceholder placeholder = new EPlaceholder(location, this);
196             placeholder.setType(value.getType());
197             
198             context.recursiveReferences.add(placeholder);
199             return placeholder;
200         }
201         else if(context.isInPattern()) {
202             /* This is little hackish code that handles the following kind of constructors:
203              *   data Thunk a = Thunk s (a -> s)
204              * in
205              *   match thunk with Thunk s f -> f s
206              * We cannot assign s with an unbound metaVar because its type depends on 
207              * how it has been constructed. Therefore we parametrize the function with
208              * existential variable.
209              */
210             Type resultType = value.getType();
211             if(resultType instanceof TForAll) {
212                 ArrayList<TMetaVar> vars = new ArrayList<TMetaVar>(); 
213                 resultType = Types.instantiate(resultType, vars);
214                 MultiFunction mfun = Types.matchFunction(resultType);
215                 resultType = mfun.returnType;
216                 
217                 for(TMetaVar var : vars) {
218                     if(resultType.contains(var))
219                         break;
220                     addTypeParameters(Types.var(var.getKind()));                    
221                 }
222             }
223             return this;
224         }
225         else
226             return applyPUnit(context);
227     }
228     
229     @Override
230     public boolean isEffectful() {
231         return false;
232     }
233     
234     @Override
235     public void setLocationDeep(long loc) {
236         if(location == Locations.NO_LOCATION)
237             location = loc;
238     }
239     
240     @Override
241     public void accept(ExpressionVisitor visitor) {
242         visitor.visit(this);
243     }
244     
245     @Override
246     public Precedence getPrecedence() {
247         return value.getPrecedence();
248     }
249     
250     @Override
251     public boolean isPattern(int arity) {
252         IVal val = value.getValue();
253         if(!(val instanceof Constant))
254             return false;
255         Constant constant = (Constant)val;
256         return constant.constructorTag() >= 0 && constant.getArity() == arity;
257     }
258     
259     @Override
260     public Expression accept(ExpressionTransformer transformer) {
261         return transformer.transform(this);
262     }
263
264     @Override
265     public boolean equalsExpression(Expression expression) {
266         if(expression.getClass() != getClass())
267             return false;
268         EConstant other = (EConstant)expression;
269         return value == other.value && Types.equals(typeParameters, other.typeParameters);
270     }
271 }