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