7b56d22fa2991bba35ef28d73240015326917c8e
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / EIf.java
1 package org.simantics.scl.compiler.elaboration.expressions;
2
3 import org.simantics.scl.compiler.compilation.CompilationContext;
4 import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext;
5 import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext;
6 import org.simantics.scl.compiler.elaboration.contexts.TranslationContext;
7 import org.simantics.scl.compiler.elaboration.contexts.TypingContext;
8 import org.simantics.scl.compiler.errors.Locations;
9 import org.simantics.scl.compiler.internal.codegen.references.IVal;
10 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
11 import org.simantics.scl.compiler.internal.interpreted.IConstant;
12 import org.simantics.scl.compiler.internal.interpreted.IExpression;
13 import org.simantics.scl.compiler.internal.interpreted.IIf;
14 import org.simantics.scl.compiler.top.ExpressionInterpretationContext;
15 import org.simantics.scl.compiler.types.Type;
16 import org.simantics.scl.compiler.types.Types;
17 import org.simantics.scl.compiler.types.exceptions.MatchException;
18 import org.simantics.scl.runtime.tuple.Tuple0;
19
20 import gnu.trove.map.hash.TObjectIntHashMap;
21 import gnu.trove.set.hash.THashSet;
22 import gnu.trove.set.hash.TIntHashSet;
23
24 public class EIf extends Expression {
25     public Expression condition;
26     public Expression then_;
27     public Expression else_; // may be null
28     
29     public EIf(Expression condition, Expression then_, Expression else_) {
30         this.condition = condition;
31         this.then_ = then_;
32         this.else_ = else_;
33     }
34
35     public EIf(long loc, Expression condition, Expression then_, Expression else_) {
36         super(loc);
37         this.condition = condition;
38         this.then_ = then_;
39         this.else_ = else_;
40     }
41
42     @Override
43     public void collectVars(TObjectIntHashMap<Variable> allVars,
44             TIntHashSet vars) {
45         condition.collectVars(allVars, vars);
46         then_.collectVars(allVars, vars);
47         if(else_ != null)
48             else_.collectVars(allVars, vars);
49     }
50
51     @Override
52     protected void updateType() throws MatchException {
53         setType(then_.getType());
54     }
55
56     @Override
57     public IVal toVal(CompilationContext context, CodeWriter w) {
58         IVal conditionVal = condition.toVal(context, w); 
59         CodeWriter joinPoint = w.createBlock(getType());
60         CodeWriter thenBlock = w.createBlock();
61         if(else_ != null) {
62             CodeWriter elseBlock = w.createBlock();        
63             w.if_(conditionVal, thenBlock.getContinuation(), elseBlock.getContinuation());
64                 
65             IVal elseVal = else_.toVal(context, elseBlock);
66             elseBlock.jump(joinPoint.getContinuation(), elseVal);
67         }
68         else {
69             w.if_(conditionVal, thenBlock.getContinuation(), joinPoint.getContinuation());
70         }
71         IVal thenVal = then_.toVal(context, thenBlock);
72         thenBlock.jump(joinPoint.getContinuation(), thenVal);
73         w.continueAs(joinPoint);
74         
75         return w.getParameters()[0];
76     }
77
78     @Override
79     public void collectFreeVariables(THashSet<Variable> vars) {
80         condition.collectFreeVariables(vars);
81         then_.collectFreeVariables(vars);
82         if(else_ != null)
83             else_.collectFreeVariables(vars);
84     }
85
86     @Override
87     public Expression simplify(SimplificationContext context) {
88         condition = condition.simplify(context);
89         then_ = then_.simplify(context);
90         if(else_ != null)
91             else_ = else_.simplify(context);
92         return this;
93     }
94
95     @Override
96     public Expression resolve(TranslationContext context) {
97         condition = condition.resolve(context);
98         then_ = then_.resolve(context);
99         if(else_ != null)
100             else_ = else_.resolve(context);
101         return this;
102     }
103
104     @Override
105     public Expression replace(ReplaceContext context) {
106         return new EIf(condition.replace(context), 
107                 then_.replace(context), 
108                 else_ == null ? null : else_.replace(context));
109     }
110     
111     @Override
112     public Expression checkBasicType(TypingContext context, Type requiredType) {
113         condition = condition.checkType(context, Types.BOOLEAN);
114         then_ = then_.checkType(context, requiredType);
115         if(else_ != null)
116             else_ = else_.checkType(context, requiredType);
117         else
118             context.getErrorLog().log(location, "Else branch is required because the return value of the if expression is used.");
119         return this;
120     }
121     
122     @Override
123     public Expression checkIgnoredType(TypingContext context) {
124         condition = condition.checkType(context, Types.BOOLEAN);
125         then_ = then_.checkIgnoredType(context);
126         if(else_ != null)
127             else_ = else_.checkIgnoredType(context);
128         return this;
129     }
130     
131     @Override
132     public boolean isEffectful() {
133         return condition.isEffectful() || then_.isEffectful() || (else_ != null && else_.isEffectful());
134     }
135     
136     @Override
137     public void setLocationDeep(long loc) {
138         if(location == Locations.NO_LOCATION) {
139             location = loc;
140             condition.setLocationDeep(loc);
141             then_.setLocationDeep(loc);
142             if(else_ != null)
143                 else_.setLocationDeep(loc);
144         }
145     }
146     
147     @Override
148     public void accept(ExpressionVisitor visitor) {
149         visitor.visit(this);
150     }
151     
152     @Override
153     public IExpression toIExpression(ExpressionInterpretationContext target) {
154         return new IIf(condition.toIExpression(target), then_.toIExpression(target), 
155                 else_ != null ? else_.toIExpression(target) : new IConstant(Tuple0.INSTANCE));
156     }
157
158     @Override
159     public Expression accept(ExpressionTransformer transformer) {
160         return transformer.transform(this);
161     }
162
163     @Override
164     public int getSyntacticFunctionArity() {
165         return Math.max(then_.getSyntacticFunctionArity(), else_.getSyntacticFunctionArity());
166     }
167 }