package org.simantics.scl.compiler.elaboration.expressions; import java.util.ArrayList; import org.simantics.scl.compiler.common.exceptions.InternalCompilerError; import org.simantics.scl.compiler.elaboration.contexts.ReplaceContext; import org.simantics.scl.compiler.elaboration.contexts.SimplificationContext; import org.simantics.scl.compiler.elaboration.contexts.TranslationContext; import org.simantics.scl.compiler.elaboration.contexts.TypingContext; import org.simantics.scl.compiler.environment.Environment; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.internal.codegen.references.IVal; import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter; import org.simantics.scl.compiler.internal.elaboration.utils.ExpressionDecorator; import org.simantics.scl.compiler.internal.interpreted.IExpression; import org.simantics.scl.compiler.internal.interpreted.IVariable; import org.simantics.scl.compiler.top.ExpressionInterpretationContext; import org.simantics.scl.compiler.types.Type; import org.simantics.scl.compiler.types.Types; import org.simantics.scl.compiler.types.exceptions.MatchException; import org.simantics.scl.compiler.types.kinds.Kinds; import org.simantics.scl.compiler.types.util.TypeUnparsingContext; import gnu.trove.map.hash.TObjectIntHashMap; import gnu.trove.set.hash.THashSet; import gnu.trove.set.hash.TIntHashSet; public class EVariable extends Expression { public static final EVariable[] EMPTY_ARRAY = new EVariable[0]; Variable variable; public EVariable(Variable variable) { this.variable = variable; } public EVariable(long loc, Variable variable) { super(loc); this.variable = variable; } public Variable getVariable() { return variable; } public void setVariable(Variable variable) { this.variable = variable; } public void collectRefs(TObjectIntHashMap allRefs, TIntHashSet refs) { } @Override public void collectVars(TObjectIntHashMap allVars, TIntHashSet vars) { int id = allVars.get(variable); if(id >= 0) vars.add(id); } public void toString(StringBuilder b, TypeUnparsingContext tuc) { b.append(variable == null ? "???" : variable.toString()); } @Override protected void updateType() throws MatchException { setType(variable.getType()); } @Override public IVal toVal(Environment env, CodeWriter w) { return variable.getVal(); } @Override public void collectFreeVariables(THashSet vars) { vars.add(variable); } @Override public Expression simplify(SimplificationContext context) { Expression expression = context.getInlinedValue(variable); if(expression != null) return expression.copy(); else return this; } @Override public Expression resolve(TranslationContext context) { return this; } @Override public void getParameters(TranslationContext translationContext, ArrayList parameters) { } @Override public void removeFreeVariables(THashSet vars) { vars.remove(variable); } @Override public Expression resolveAsPattern(TranslationContext context) { return this; } @Override public Expression replace(ReplaceContext context) { if(context.inPattern) { Type type = variable.getType().replace(context.tvarMap); Variable newVariable = new Variable(variable.name); newVariable.setType(type); EVariable result = new EVariable(newVariable); context.varMap.put(variable, result); return result; } else { if(variable == null) { EVariable newVariable = new EVariable(location, null); newVariable.setType(getType().replace(context.tvarMap)); if(context.typingContext == null) throw new InternalCompilerError(location, "Encountered unresolved variable but not in type checking phase."); context.typingContext.addConstraintDemand(newVariable); return newVariable; } else { Expression expression = context.varMap.get(variable); if(expression != null) return expression.copy(context.typingContext); else { return new EVariable(variable); } } } } @Override public IExpression toIExpression(ExpressionInterpretationContext target) { return new IVariable(target.getVariableId(variable)); } @Override public Expression inferType(TypingContext context) { if(context.isInPattern()) { variable.setType(Types.metaVar(Kinds.STAR)); return this; } else return applyPUnit(context); } @Override public Expression checkBasicType(TypingContext context, Type requiredType) { if(context.isInPattern()) { variable.setType(requiredType); return this; } else return context.subsume(this, requiredType); } @Override public Expression decorate(ExpressionDecorator decorator) { return decorator.decorate(this); } @Override public boolean isEffectful() { return false; } @Override public void collectEffects(THashSet effects) { } @Override public void setLocationDeep(long loc) { if(location == Locations.NO_LOCATION) location = loc; } @Override public void accept(ExpressionVisitor visitor) { visitor.visit(this); } @Override public void forVariables(VariableProcedure procedure) { if(variable != null) procedure.execute(location, variable); } @Override public boolean isPattern(int arity) { return arity == 0; } @Override public Expression accept(ExpressionTransformer transformer) { return transformer.transform(this); } }