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.distill.BaseDistiller 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.distill;
import kala.collection.SeqLike;
import kala.collection.SeqView;
import kala.collection.mutable.DynamicSeq;
import org.aya.api.distill.AyaDocile;
import org.aya.api.distill.DistillerOptions;
import org.aya.api.ref.DefVar;
import org.aya.api.ref.LocalVar;
import org.aya.api.ref.Var;
import org.aya.api.util.Arg;
import org.aya.concrete.stmt.Decl;
import org.aya.concrete.stmt.Sample;
import org.aya.generic.ParamLike;
import org.aya.pretty.doc.Doc;
import org.aya.pretty.doc.Style;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.function.BiFunction;
/**
* @author ice1000
*/
public abstract class BaseDistiller {
@FunctionalInterface
protected interface Fmt extends BiFunction {
}
public static final @NotNull Style KEYWORD = Style.preset("aya:Keyword");
public static final @NotNull Style FN_CALL = Style.preset("aya:FnCall");
public static final @NotNull Style DATA_CALL = Style.preset("aya:DataCall");
public static final @NotNull Style STRUCT_CALL = Style.preset("aya:StructCall");
public static final @NotNull Style CON_CALL = Style.preset("aya:ConCall");
public static final @NotNull Style FIELD_CALL = Style.preset("aya:FieldCall");
public static final @NotNull Style GENERALIZED = Style.preset("aya:Generalized");
public final @NotNull DistillerOptions options;
protected BaseDistiller(@NotNull DistillerOptions options) {
this.options = options;
}
@NotNull Doc visitCalls(
boolean infix, @NotNull Doc fn, @NotNull Fmt fmt, Outer outer,
@NotNull SeqView<@NotNull Arg<@NotNull T>> args, boolean showImplicits
) {
var visibleArgs = (showImplicits ? args : args.filter(Arg::explicit)).toImmutableSeq();
if (visibleArgs.isEmpty()) return infix ? Doc.parened(fn) : fn;
// Print as a binary operator
if (infix) {
var firstArg = visibleArgs.first();
if (!firstArg.explicit()) return prefix(Doc.parened(fn), fmt, outer, visibleArgs.view());
var first = fmt.apply(Outer.BinOp, firstArg.term());
// If we're in a binApp/head/spine/etc., add parentheses
if (visibleArgs.sizeEquals(1)) return checkParen(outer, Doc.sep(first, fn), Outer.BinOp);
var triple = Doc.sep(first, fn, visitArg(fmt, visibleArgs.get(1), Outer.BinOp));
if (visibleArgs.sizeEquals(2)) return checkParen(outer, triple, Outer.BinOp);
return prefix(Doc.parened(triple), fmt, outer, visibleArgs.view().drop(2));
}
return prefix(fn, fmt, outer, visibleArgs.view());
}
private @NotNull Doc
prefix(@NotNull Doc fn, @NotNull Fmt fmt, Outer outer, SeqView> args) {
var call = Doc.sep(fn, Doc.sep(args.map(arg ->
visitArg(fmt, arg, Outer.AppSpine))));
// If we're in a spine, add parentheses
return checkParen(outer, call, Outer.AppSpine);
}
private Doc visitArg(@NotNull Fmt fmt, @NotNull Arg arg, @NotNull Outer outer) {
if (arg.explicit()) return fmt.apply(outer, arg.term());
return Doc.braced(fmt.apply(Outer.Free, arg.term()));
}
public static @NotNull Doc checkParen(@NotNull Outer outer, @NotNull Doc binApp, @NotNull Outer binOp) {
return outer.ordinal() >= binOp.ordinal() ? Doc.parened(binApp) : binApp;
}
@NotNull Doc ctorDoc(@NotNull Outer outer, boolean ex, Doc ctorDoc, LocalVar ctorAs, boolean noParams) {
boolean as = ctorAs != null;
var withEx = Doc.bracedUnless(ctorDoc, ex);
var withAs = !as ? withEx :
Doc.sep(Doc.parened(withEx), Doc.plain("as"), linkDef(ctorAs));
return !ex && !as ? withAs : outer != Outer.Free && !noParams ? Doc.parened(withAs) : withAs;
}
@NotNull Doc visitTele(@NotNull SeqLike extends ParamLike>> telescope) {
if (telescope.isEmpty()) return Doc.empty();
var last = telescope.first();
var buf = DynamicSeq.create();
var names = DynamicSeq.of(last.nameDoc());
for (var param : telescope.view().drop(1)) {
if (!Objects.equals(param.type(), last.type())) {
buf.append(last.toDoc(Doc.sep(names), options));
names.clear();
last = param;
}
names.append(param.nameDoc());
}
buf.append(last.toDoc(Doc.sep(names), options));
return Doc.sep(buf);
}
@NotNull Doc lambdaParam(@NotNull ParamLike> param) {
return options.map.get(DistillerOptions.Key.ShowLambdaTypes) ? param.toDoc(options)
: Doc.bracedUnless(param.nameDoc(), param.explicit());
}
public static @NotNull Doc varDoc(@NotNull Var ref) {
return Doc.linkRef(Doc.plain(ref.name()), ref.hashCode());
}
static @NotNull Doc coe(boolean coerce) {
return coerce ? Doc.styled(KEYWORD, "coerce") : Doc.empty();
}
static @NotNull Doc primDoc(Var ref) {
return Doc.sep(Doc.styled(KEYWORD, "prim"), linkDef(ref, FN_CALL));
}
public static @NotNull Doc linkDef(@NotNull Var ref, @NotNull Style color) {
return Doc.linkDef(Doc.styled(color, ref.name()), ref.hashCode());
}
public static @NotNull Doc linkRef(@NotNull Var ref, @NotNull Style color) {
return Doc.linkRef(Doc.styled(color, ref.name()), ref.hashCode());
}
public static @NotNull Doc linkDef(@NotNull Var ref) {
return Doc.linkDef(Doc.plain(ref.name()), ref.hashCode());
}
static @NotNull Doc visitDefVar(DefVar, ?> ref) {
var style = chooseStyle(ref.concrete);
return style != null ? linkDef(ref, style) : varDoc(ref);
}
protected static @Nullable Style chooseStyle(Object concrete) {
return switch (concrete) {
case Decl.FnDecl d -> FN_CALL;
case Decl.DataDecl d -> DATA_CALL;
case Decl.DataCtor d -> CON_CALL;
case Decl.StructDecl d -> STRUCT_CALL;
case Decl.StructField d -> FIELD_CALL;
case Decl.PrimDecl d -> FN_CALL;
case Sample sample -> chooseStyle(sample.delegate());
case null, default -> null;
};
}
/**
* Expression: where am I?
*
*
* Top-level expression may not need parentheses, stone free!
* An argument of an application! Stay in parentheses!
* An operand of a binary application! Applications within are safe,
* but other binary applications are in danger!
* Codomain of a telescope
*
*/
public enum Outer {
Free,
Codomain,
BinOp,
AppHead,
AppSpine,
ProjHead,
}
}