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

org.aya.resolve.visitor.StmtBinder Maven / Gradle / Ivy

The newest version!
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.resolve.visitor;

import kala.collection.SeqLike;
import org.aya.resolve.ResolveInfo;
import org.aya.resolve.ResolvingStmt;
import org.aya.resolve.context.Context;
import org.aya.resolve.error.NameProblem;
import org.aya.syntax.concrete.stmt.BindBlock;
import org.aya.syntax.concrete.stmt.QualifiedID;
import org.aya.syntax.concrete.stmt.decl.ClassDecl;
import org.aya.syntax.concrete.stmt.decl.DataDecl;
import org.aya.syntax.concrete.stmt.decl.FnDecl;
import org.aya.syntax.concrete.stmt.decl.PrimDecl;
import org.aya.syntax.ref.AnyDefVar;
import org.aya.syntax.ref.DefVar;
import org.aya.util.binop.OpDecl;
import org.aya.util.error.Panic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import static org.aya.resolve.ResolvingStmt.*;

public record StmtBinder(@NotNull ResolveInfo info) {
  private void visitBind(@NotNull Context ctx, @NotNull DefVar selfDef, @NotNull BindBlock bind) {
    bind(ctx, bind, selfDef.concrete);
  }

  /**
   * Bind {@param bindBlock} to {@param opSet} in {@param ctx}
   */
  public void bind(@NotNull Context ctx, @NotNull BindBlock bindBlock, OpDecl self) {
    if (bindBlock == BindBlock.EMPTY) return;
    bindBlock.resolvedLoosers().set(bindBlock.loosers().mapNotNull(looser ->
      bind(self, ctx, OpDecl.BindPred.Looser, looser)));
    bindBlock.resolvedTighters().set(bindBlock.tighters().mapNotNull(tighter ->
      bind(self, ctx, OpDecl.BindPred.Tighter, tighter)));
  }

  private @Nullable AnyDefVar bind(
    @NotNull OpDecl self, @NotNull Context ctx,
    @NotNull OpDecl.BindPred pred, @NotNull QualifiedID id
  ) throws Context.ResolvingInterruptedException {
    var var = ctx.get(id);
    var opDecl = info.resolveOpDecl(var);
    if (opDecl != null) {
      info.opSet().bind(self, pred, opDecl, id.sourcePos());
      return var instanceof AnyDefVar defVar ? defVar : null;
    }

    // make compiler happy 😥
    info.opSet().fail(
      new NameProblem.OperatorNameNotFound(id.sourcePos(), id.join()));
    throw new Context.ResolvingInterruptedException();
  }

  public void resolveBind(@NotNull SeqLike contents) {
    contents.forEach(s -> resolveBind(info.thisModule(), s));
    info.opRename().forEach((_, v) -> {
      if (v.bind() == BindBlock.EMPTY) return;
      bind(info.thisModule(), v.bind(), v.renamed());
    });
  }

  /**
   * @param ctx the context that {@param stmt} binds to
   */
  private void resolveBind(@NotNull Context ctx, @NotNull ResolvingStmt stmt) {
    switch (stmt) {
      case TopDecl(DataDecl decl, var innerCtx) -> {
        decl.body.forEach(con -> resolveBind(innerCtx, new MiscDecl(con)));
        visitBind(ctx, decl.ref, decl.bindBlock());
      }
      case TopDecl(ClassDecl decl, var innerCtx) -> {
        decl.members.forEach(field -> resolveBind(innerCtx, new MiscDecl(field)));
        visitBind(ctx, decl.ref, decl.bindBlock());
      }
      case TopDecl(FnDecl fn, var innerCtx) -> visitBind(innerCtx, fn.ref, fn.bindBlock());
      case MiscDecl(var decl) -> visitBind(ctx, decl.ref(), decl.bindBlock());
      case TopDecl(PrimDecl _, _), GenStmt _ -> { }
      case TopDecl _ -> Panic.unreachable();
      case ModStmt(var stmts) -> resolveBind(stmts);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy