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

org.aya.generic.Renamer Maven / Gradle / Ivy

// 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.generic;

import kala.collection.mutable.MutableMap;
import org.aya.syntax.core.term.*;
import org.aya.syntax.core.term.call.Callable;
import org.aya.syntax.core.term.xtt.CoeTerm;
import org.aya.syntax.core.term.xtt.DimTyTerm;
import org.aya.syntax.core.term.xtt.EqTerm;
import org.aya.syntax.core.term.xtt.PAppTerm;
import org.aya.syntax.ref.LocalCtx;
import org.aya.syntax.ref.LocalVar;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public record Renamer(MutableMap scope) {
  public Renamer() {
    this(MutableMap.create());
  }

  public void store(@NotNull LocalCtx ctx) {
    ctx.extract().forEach(lv -> scope.put(lv.name(), lv));
  }

  public static @NotNull String nameOf(@Nullable Term ty) {
    return switch (ty) {
      case FreeTerm(var name) -> name.name();
      case MetaPatTerm _ -> "p";
      case Callable.Tele c -> Character.toString(Character.toLowerCase(
        c.ref().name().codePointAt(0)));
      case DepTypeTerm _ -> "f";
      case DimTyTerm _ -> "i";
      case ProjTerm p -> nameOf(p.of());
      case AppTerm a -> nameOf(a.fun());
      case PAppTerm a -> nameOf(a.fun());
      case EqTerm _, CoeTerm _ -> "p";
      case null, default -> "x";
    };
  }

  public @NotNull LocalVar bindName(@Nullable Term name) {
    return bindName(nameOf(name));
  }
  public @NotNull LocalVar bindName(@NotNull String name) {
    if (scope.containsKey(name)) {
      var newGame = sanitizeName(name);
      var uid = LocalVar.generate(newGame);
      scope.put(newGame, uid);
      return uid;
    } else {
      var uid = LocalVar.generate(name);
      scope.put(name, uid);
      return uid;
    }
  }

  private String sanitizeName(String name) {
    if (name.length() == 1) {
      var c = name.codePointAt(0);
      if (c >= 'a' && c <= 'z') {
        var ideal = conflictAlphabetic(c, 'a');
        if (ideal != null) return ideal;
      }
      if (c >= 'A' && c <= 'Z') {
        var ideal = conflictAlphabetic(c, 'A');
        if (ideal != null) return ideal;
      }
    }
    return conflictSuffix(name);
  }

  private String conflictAlphabetic(int c, int base) {
    int initial = c - base;
    int i = initial + 1;
    while (scope.containsKey(Character.toString(i + base))) {
      if (i == initial) return null;
      i = (i + 1) % 26;
    }
    return Character.toString(i + base);
  }

  private String conflictSuffix(String name) {
    int i = 0;
    while (scope.containsKey(name + i)) i++;
    return name + i;
  }

  public void unbindName(@NotNull LocalVar uid) {
    scope.remove(uid.name());
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy