All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.aya.tyck.unify.level.LevelEqnSet Maven / Gradle / Ivy
// Copyright (c) 2020-2021 Yinsen (Tesla) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.tyck.unify.level;
import kala.collection.mutable.DynamicSeq;
import kala.collection.mutable.MutableMap;
import org.aya.core.sort.LevelSubst;
import org.aya.core.sort.Sort;
import org.aya.generic.Level;
import org.aya.pretty.doc.Doc;
import org.aya.pretty.doc.Docile;
import org.aya.util.Ordering;
import org.aya.util.error.SourcePos;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
/**
* A set of level equations.
*
* @author ice1000
*/
public record LevelEqnSet(
@NotNull DynamicSeq vars,
@NotNull DynamicSeq<@NotNull Eqn> eqns,
@NotNull MutableMap solution
) implements LevelSubst.Default {
public LevelEqnSet() {
this(DynamicSeq.create(), DynamicSeq.create(), MutableMap.create());
}
public void add(@NotNull Sort lhs, @NotNull Sort rhs, @NotNull Ordering cmp, @NotNull SourcePos loc) {
insertEqn(new Eqn(lhs, rhs, cmp, loc));
}
private void insertEqn(Eqn h) {
eqns.append(h);
}
public void solve() {
var solver = new LevelSolver();
try {
solver.solve(this);
for (var lvlVar : vars)
if (!solution.containsKey(lvlVar)) {
solution.put(lvlVar, new Sort(new Level.Constant<>(0)));
}
eqns.clear();
} catch (LevelSolver.UnsatException ignored) {
// Level unsolved, leave the 'useful' equations
var buf = DynamicSeq.create();
eqns.filterNotTo(buf, solver.avoidableEqns::contains);
eqns.clear();
eqns.appendAll(buf);
}
}
/**
* For {@link org.aya.tyck.ExprTycker#universe}
*/
public boolean used(@NotNull Sort.LvlVar var) {
return eqns.anyMatch(eqn -> eqn.used(var)) ||
solution.valuesView().anyMatch(level -> Eqn.used(var, level));
}
public Sort markUsed(@NotNull Sort.LvlVar universe) {
return solution.getOrPut(universe, () -> new Sort(new Level.Reference<>(universe)));
}
@TestOnly public @NotNull String forZZS() {
var builder = new StringBuilder("List.of(");
boolean started = false;
for (var eqn : eqns) {
if (started) builder.append(", ");
started = true;
eqn.forZZS(builder);
}
return builder.append(")").toString();
}
/**
* @author ice1000
*/
public record Eqn(
@NotNull Sort lhs, @NotNull Sort rhs,
@NotNull Ordering cmp, @NotNull SourcePos sourcePos
) implements Docile {
public boolean used(@NotNull Sort.LvlVar var) {
return used(var, lhs) || used(var, rhs);
}
public static boolean used(Sort.@NotNull LvlVar var, @NotNull Level lvl) {
return lvl instanceof Level.Reference l && l.ref() == var;
}
public static boolean used(Sort.@NotNull LvlVar var, @NotNull Sort lvl) {
return lvl.levels().anyMatch(level -> used(var, level));
}
@TestOnly public @NotNull String forZZS(@NotNull Level level) {
return switch (level) {
case Level.Reference ref -> {
var r = ref.ref();
yield "new Reference(new Var(\"" + r.name() + "\", " + r.free() + "), " + ref.lift() + ")";
}
case Level.Constant constant -> "new Const(" + constant.value() + ")";
default -> throw new IllegalArgumentException(level.toString());
};
}
@TestOnly public void forZZS(@NotNull StringBuilder builder) {
builder.append("new Equation(Ord.")
.append(cmp.name())
.append(", new Max(List.of(");
lhs.levels().joinTo(builder, ", ", this::forZZS);
builder.append(")), new Max(List.of(");
rhs.levels().joinTo(builder, ", ", this::forZZS);
builder.append(")))");
}
@Override public @NotNull Doc toDoc() {
return Doc.stickySep(lhs.toDoc(), Doc.symbol(cmp.symbol), rhs.toDoc());
}
}
}