All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aya.tyck.order.AyaSccTycker Maven / Gradle / Ivy

There is a newer version: 0.33.0
Show newest version
// 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.order;

import kala.collection.immutable.ImmutableSeq;
import kala.collection.mutable.DynamicSeq;
import kala.control.Option;
import org.aya.api.error.CollectingReporter;
import org.aya.api.util.InterruptException;
import org.aya.concrete.remark.Remark;
import org.aya.concrete.stmt.Decl;
import org.aya.concrete.stmt.Sample;
import org.aya.core.def.Def;
import org.aya.tyck.StmtTycker;
import org.aya.tyck.error.CircularSignatureError;
import org.aya.tyck.trace.Trace;
import org.aya.util.MutableGraph;
import org.aya.util.tyck.SCCTycker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.function.Function;

/**
 * Tyck statements in SCC.
 *
 * @author kiva
 */
public record AyaSccTycker(
  @NotNull StmtTycker tycker,
  @NotNull CollectingReporter reporter,
  @NotNull DynamicSeq<@NotNull Def> wellTyped
) implements SCCTycker {
  public AyaSccTycker(@Nullable Trace.Builder builder, @NotNull CollectingReporter reporter) {
    this(new StmtTycker(reporter, builder), reporter, DynamicSeq.create());
  }

  public @NotNull ImmutableSeq tyckSCC(@NotNull ImmutableSeq scc) {
    try {
      if (scc.sizeEquals(1)) checkBody(scc.first());
      else {
        var headerOrder = headerOrder(scc);
        headerOrder.forEach(this::checkHeader);
        headerOrder.forEach(this::checkBody);
      }
      return ImmutableSeq.empty();
    } catch (SCCTyckingFailed failed) {
      return failed.what;
    }
  }

  private void checkHeader(@NotNull TyckUnit stmt) {
    switch (stmt) {
      case Decl decl -> tycker.tyckHeader(decl, tycker.newTycker());
      case Sample sample -> sample.tyckHeader(tycker);
      // TODO[ice]: tyck ctor/field
      default -> {}
    }
    if (reporter.anyError()) throw new SCCTyckingFailed(ImmutableSeq.of(stmt));
  }

  private void checkBody(@NotNull TyckUnit stmt) {
    switch (stmt) {
      case Decl decl -> wellTyped.append(tycker.tyck(decl, tycker.newTycker()));
      case Sample sample -> {
        var tyck = sample.tyck(tycker);
        if (tyck != null) wellTyped.append(tyck);
      }
      case Remark remark -> Option.of(remark.literate).forEach(l -> l.tyck(tycker.newTycker()));
      default -> {}
    }
    if (reporter.anyError()) throw new SCCTyckingFailed(ImmutableSeq.of(stmt));
  }

  /**
   * Generate the order of dependency of headers, fail if a cycle occurs.
   *
   * @author re-xyr, kiva
   */
  public @NotNull ImmutableSeq headerOrder(@NotNull ImmutableSeq stmts) {
    var graph = MutableGraph.create();
    stmts.forEach(stmt -> {
      var reference = DynamicSeq.create();
      SigRefFinder.HEADER_ONLY.visit(stmt, reference);
      graph.suc(stmt).appendAll(reference);
    });
    var order = graph.topologicalOrder();
    var cycle = order.view().filter(s -> s.sizeGreaterThan(1));
    if (cycle.isNotEmpty()) {
      cycle.forEach(c -> reporter.report(new CircularSignatureError(c)));
      throw new SCCTyckingFailed(stmts);
    }
    return order.flatMap(Function.identity());
  }

  public static class SCCTyckingFailed extends InterruptException {
    public @NotNull ImmutableSeq what;

    public SCCTyckingFailed(@NotNull ImmutableSeq what) {
      this.what = what;
    }

    @Override public InterruptStage stage() {
      return InterruptStage.Tycking;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy