package org.simantics.scl.compiler.internal.elaboration.constraints; import java.util.ArrayList; import org.simantics.scl.compiler.elaboration.expressions.ELiteral; import org.simantics.scl.compiler.elaboration.expressions.EVariable; import org.simantics.scl.compiler.elaboration.expressions.Variable; import org.simantics.scl.compiler.errors.Locations; import org.simantics.scl.compiler.types.TCon; import org.simantics.scl.compiler.types.TPred; import org.simantics.scl.compiler.types.Types; import gnu.trove.map.hash.THashMap; import gnu.trove.set.hash.THashSet; class ConstraintSet { private static int id = 0; final ConstraintEnvironment environment; /** * Collection of all active (solved or unsolved) constraints. */ final THashMap> constraints = new THashMap>(); /** * Set of currently unsolved constraints. */ THashSet unsolved = new THashSet(); /** * These are constraints that are explicitly required in the code */ final ArrayList needed = new ArrayList(); public ConstraintSet(ConstraintEnvironment environment) { this.environment = environment; } private ArrayList getConstraintList(TCon typeClass) { ArrayList cl = constraints.get(typeClass); if(cl == null) { cl = new ArrayList(2); constraints.put(typeClass, cl); } return cl; } public void addDemand(EVariable demand) { Constraint constraint = addConstraint(demand.getLocation(), (TPred)demand.getType()); demand.setVariable(constraint.evidence); needed.add(constraint); } private Constraint addConstraint(long demandLocation, TPred constraint) { ArrayList cl = getConstraintList(constraint.typeClass); for(Constraint c : cl) { if(Types.equals(constraint, c.constraint)) { return c; } } Constraint newConstraint = newConstraint(demandLocation, constraint); cl.add(newConstraint); unsolved.add(newConstraint); return newConstraint; } private void addSuperconstraints(Constraint constraint) { scloop: for(Superconstraint superconstraint : environment.getSuperconstraints(constraint.constraint)) { TPred sc = superconstraint.superconstraint; ArrayList cl = getConstraintList(sc.typeClass); for(Constraint c : cl) { if(c.state < Constraint.STATE_HAS_SUBCLASS && Types.equals(sc, c.constraint)) { unsolved.remove(c); c.setGenerator(Constraint.STATE_HAS_SUBCLASS, new ELiteral(constraint.demandLocation, superconstraint.generator), constraint.constraint.parameters, constraint); continue scloop; } } Constraint newConstraint = newConstraint(constraint.demandLocation, sc); newConstraint.setGenerator(Constraint.STATE_HAS_SUBCLASS, new ELiteral(constraint.demandLocation, superconstraint.generator), constraint.constraint.parameters, constraint); cl.add(newConstraint); } } private Constraint newConstraint(long demandLocation, TPred constraint) { Variable evidence = new Variable("ev" + (++id)); evidence.setType(constraint); Constraint newConstraint = new Constraint(constraint, evidence, demandLocation); addSuperconstraints(newConstraint); return newConstraint; } public void reduce() { while(!unsolved.isEmpty()) { THashSet temp = unsolved; unsolved = new THashSet(); for(Constraint c : temp) { if(c.state == Constraint.STATE_UNSOLVED) { Reduction reduction = environment.reduce(c.constraint); if(reduction != null) { TPred[] demands = reduction.demands; if(demands.length == 0) c.setGenerator(Constraint.STATE_HAS_INSTANCE, reduction.generator, reduction.parameters, Constraint.EMPTY_ARRAY); else { Constraint[] dependsOn = new Constraint[demands.length]; for(int i=0;i unsolvedConstraints, ArrayList solvedConstraints) { for(Constraint n : needed) n.collect(environment, unsolvedConstraints, solvedConstraints); } public Constraint addGiven(TPred c) { Constraint result = addConstraint(Locations.NO_LOCATION, c); result.state = Constraint.STATE_GIVEN; result.generator = Constraint.GIVEN_GENERATOR; return result; } }