(refs #7375) Replaced collectFreeVariables method by a visitor
[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.TIntHashSet;
22
23 public class EIf extends Expression {
24     public Expression condition;
25     public Expression then_;
26     public Expression else_; // may be null
27     
28     public EIf(Expression condition, Expression then_, Expression else_) {
29         this.condition = condition;
30         this.then_ = then_;
31         this.else_ = else_;
32     }
33
34     public EIf(long loc, Expression condition, Expression then_, Expression else_) {
35         super(loc);
36         this.condition = condition;
37         this.then_ = then_;
38         this.else_ = else_;
39     }
40
41     @Override
42     public void collectVars(TObjectIntHashMap<Variable> allVars,
43             TIntHashSet vars) {
44         condition.collectVars(allVars, vars);
45         then_.collectVars(allVars, vars);
46         if(else_ != null)
47             else_.collectVars(allVars, vars);
48     }
49
50     @Override
51     protected void updateType() throws MatchException {
52         setType(then_.getType());
53     }
54
55     @Override
56     public IVal toVal(CompilationContext context, CodeWriter w) {
57         IVal conditionVal = condition.toVal(context, w); 
58         CodeWriter joinPoint = w.createBlock(getType());
59         CodeWriter thenBlock = w.createBlock();
60         if(else_ != null) {
61             CodeWriter elseBlock = w.createBlock();        
62             w.if_(conditionVal, thenBlock.getContinuation(), elseBlock.getContinuation());
63                 
64             IVal elseVal = else_.toVal(context, elseBlock);
65             elseBlock.jump(joinPoint.getContinuation(), elseVal);
66         }
67         else {
68             w.if_(conditionVal, thenBlock.getContinuation(), joinPoint.getContinuation());
69         }
70         IVal thenVal = then_.toVal(context, thenBlock);
71         thenBlock.jump(joinPoint.getContinuation(), thenVal);
72         w.continueAs(joinPoint);
73         
74         return w.getParameters()[0];
75     }
76
77     @Override
78     public Expression simplify(SimplificationContext context) {
79         condition = condition.simplify(context);
80         then_ = then_.simplify(context);
81         if(else_ != null)
82             else_ = else_.simplify(context);
83         return this;
84     }
85
86     @Override
87     public Expression resolve(TranslationContext context) {
88         condition = condition.resolve(context);
89         then_ = then_.resolve(context);
90         if(else_ != null)
91             else_ = else_.resolve(context);
92         return this;
93     }
94
95     @Override
96     public Expression replace(ReplaceContext context) {
97         return new EIf(condition.replace(context), 
98                 then_.replace(context), 
99                 else_ == null ? null : else_.replace(context));
100     }
101     
102     @Override
103     public Expression checkBasicType(TypingContext context, Type requiredType) {
104         condition = condition.checkType(context, Types.BOOLEAN);
105         then_ = then_.checkType(context, requiredType);
106         if(else_ != null)
107             else_ = else_.checkType(context, requiredType);
108         else
109             context.getErrorLog().log(location, "Else branch is required because the return value of the if expression is used.");
110         return this;
111     }
112     
113     @Override
114     public Expression checkIgnoredType(TypingContext context) {
115         condition = condition.checkType(context, Types.BOOLEAN);
116         then_ = then_.checkIgnoredType(context);
117         if(else_ != null)
118             else_ = else_.checkIgnoredType(context);
119         return this;
120     }
121     
122     @Override
123     public boolean isEffectful() {
124         return condition.isEffectful() || then_.isEffectful() || (else_ != null && else_.isEffectful());
125     }
126     
127     @Override
128     public void setLocationDeep(long loc) {
129         if(location == Locations.NO_LOCATION) {
130             location = loc;
131             condition.setLocationDeep(loc);
132             then_.setLocationDeep(loc);
133             if(else_ != null)
134                 else_.setLocationDeep(loc);
135         }
136     }
137     
138     @Override
139     public void accept(ExpressionVisitor visitor) {
140         visitor.visit(this);
141     }
142     
143     @Override
144     public IExpression toIExpression(ExpressionInterpretationContext target) {
145         return new IIf(condition.toIExpression(target), then_.toIExpression(target), 
146                 else_ != null ? else_.toIExpression(target) : new IConstant(Tuple0.INSTANCE));
147     }
148
149     @Override
150     public Expression accept(ExpressionTransformer transformer) {
151         return transformer.transform(this);
152     }
153
154     @Override
155     public int getSyntacticFunctionArity() {
156         return Math.max(then_.getSyntacticFunctionArity(), else_.getSyntacticFunctionArity());
157     }
158 }