org.aya.tyck.tycker.AppTycker 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.tyck.tycker;
import kala.collection.Seq;
import kala.collection.SeqView;
import kala.collection.immutable.ImmutableArray;
import kala.function.CheckedBiFunction;
import org.aya.generic.stmt.Shaped;
import org.aya.syntax.compile.JitCon;
import org.aya.syntax.compile.JitData;
import org.aya.syntax.compile.JitFn;
import org.aya.syntax.compile.JitPrim;
import org.aya.syntax.concrete.stmt.decl.*;
import org.aya.syntax.core.def.*;
import org.aya.syntax.core.repr.AyaShape;
import org.aya.syntax.core.term.Term;
import org.aya.syntax.core.term.call.*;
import org.aya.syntax.ref.DefVar;
import org.aya.syntax.ref.LocalVar;
import org.aya.syntax.telescope.AbstractTele;
import org.aya.tyck.Jdg;
import org.aya.tyck.TyckState;
import org.aya.util.error.Panic;
import org.aya.util.error.SourcePos;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.BiFunction;
public record AppTycker(
@Override @NotNull TyckState state,
@NotNull AbstractTycker tycker,
@NotNull SourcePos pos,
int argsCount, int lift,
@NotNull Factory makeArgs
) implements Stateful {
/**
*
* Signature (0th param) --------> Argument Parser (this interface)
* |
* [ arguments ]
* |
* v
* Well-typed Call (result) <---- Factory (1st param)
*
*/
@FunctionalInterface
public interface Factory extends
CheckedBiFunction, Jdg, Ex> {
}
public AppTycker(
@NotNull AbstractTycker tycker, @NotNull SourcePos pos,
int argsCount, int lift, @NotNull Factory makeArgs
) {
this(tycker.state, tycker, pos, argsCount, lift, makeArgs);
}
public @NotNull Jdg checkCompiledApplication(@NotNull AbstractTele def) throws Ex {
return switch (def) {
case JitFn fn -> {
int shape = fn.metadata().shape();
var operator = shape != -1 ? AyaShape.ofFn(fn, AyaShape.values()[shape]) : null;
yield checkFnCall(fn, operator);
}
case JitData data -> checkDataCall(data);
case JitPrim prim -> checkPrimCall(prim);
case JitCon con -> checkConCall(con);
default -> throw new Panic(def.getClass().getCanonicalName());
};
}
@SuppressWarnings("unchecked")
public @NotNull Jdg checkDefApplication(
@NotNull DefVar, ?> defVar
) throws Ex {
return switch (defVar.concrete) {
case FnDecl _ -> {
var fnDef = new FnDef.Delegate((DefVar) defVar);
var op = state.shapeFactory.find(fnDef).map(recog -> AyaShape.ofFn(fnDef, recog.shape())).getOrNull();
yield checkFnCall(fnDef, op);
}
// Extracted to prevent pervasive influence of suppression of unchecked warning.
case DataDecl _ -> checkDataCall(
new DataDef.Delegate((DefVar) defVar));
case PrimDecl _ -> checkPrimCall(
new PrimDef.Delegate((DefVar) defVar));
case DataCon _ -> checkConCall(
new ConDef.Delegate((DefVar) defVar));
case ClassDecl _ -> checkClassCall(
new ClassDef.Delegate((DefVar) defVar));
case ClassMember _ -> checkProjCall(
new MemberDef.Delegate((DefVar) defVar));
case Decl any -> throw new Panic(any.getClass().getCanonicalName());
};
}
private @NotNull Jdg checkConCall(@NotNull ConDefLike conVar) throws Ex {
var dataVar = conVar.dataRef();
// ownerTele + selfTele
var fullSignature = conVar.signature().lift(lift);
return makeArgs.applyChecked(fullSignature, (args, _) -> {
var realArgs = ImmutableArray.from(args);
var ownerArgs = realArgs.take(conVar.ownerTeleSize());
var conArgs = realArgs.drop(conVar.ownerTeleSize());
var type = (DataCall) fullSignature.result(realArgs);
var shape = state.shapeFactory.find(dataVar)
.mapNotNull(recog -> AyaShape.ofCon(conVar, recog, type))
.getOrNull();
if (shape != null) return new Jdg.Default(new RuleReducer.Con(shape, 0, ownerArgs, conArgs), type);
var wellTyped = new ConCall(conVar, ownerArgs, 0, conArgs);
return new Jdg.Default(wellTyped, type);
});
}
private @NotNull Jdg checkPrimCall(@NotNull PrimDefLike primVar) throws Ex {
var signature = primVar.signature().lift(lift);
return makeArgs.applyChecked(signature, (args, _) -> new Jdg.Default(
state.primFactory.unfold(new PrimCall(primVar, 0, ImmutableArray.from(args)), state),
signature.result(args)
));
}
private @NotNull Jdg checkDataCall(@NotNull DataDefLike data) throws Ex {
var signature = data.signature().lift(lift);
return makeArgs.applyChecked(signature, (args, _) -> new Jdg.Default(
new DataCall(data, 0, ImmutableArray.from(args)),
signature.result(args)
));
}
private @NotNull Jdg checkFnCall(
@NotNull FnDefLike fnDef, @Nullable Shaped.Applicable operator
) throws Ex {
var signature = fnDef.signature().lift(lift);
return makeArgs.applyChecked(signature, (args, _) -> {
var argsSeq = ImmutableArray.from(args);
var result = signature.result(args);
if (operator != null) {
return new Jdg.Default(new RuleReducer.Fn(operator, 0, argsSeq), result);
}
var fnCall = new FnCall(fnDef, 0, argsSeq);
return new Jdg.Default(fnCall, result);
});
}
private @NotNull Jdg checkClassCall(@NotNull ClassDefLike clazz) throws Ex {
var self = LocalVar.generate("self");
var appliedParams = ofClassMembers(clazz, argsCount).lift(lift);
state.classThis.push(self);
var result = makeArgs.applyChecked(appliedParams, (args, _) -> new Jdg.Default(
new ClassCall(clazz, 0, ImmutableArray.from(args).map(x -> x.bind(self))),
appliedParams.result(args)
));
state.classThis.pop();
return result;
}
private @NotNull Jdg checkProjCall(@NotNull MemberDefLike member) throws Ex {
var signature = member.signature().lift(lift);
return makeArgs.applyChecked(signature, (args, fstTy) -> {
assert args.length >= 1;
var ofTy = whnf(fstTy);
if (!(ofTy instanceof ClassCall classTy)) throw new UnsupportedOperationException("report"); // TODO
var fieldArgs = ImmutableArray.fill(args.length - 1, i -> args[i + 1]);
return new Jdg.Default(
MemberCall.make(classTy, args[0], member, 0, fieldArgs),
signature.result(args)
);
});
}
private @NotNull AbstractTele ofClassMembers(@NotNull ClassDefLike def, int memberCount) {
return new TakeMembers(def, memberCount);
}
record TakeMembers(@NotNull ClassDefLike clazz, @Override int telescopeSize) implements AbstractTele {
@Override public boolean telescopeLicit(int i) { return true; }
@Override public @NotNull String telescopeName(int i) {
assert i < telescopeSize;
return clazz.members().get(i).name();
}
// class Foo
// | foo : A
// | infix + : A -> A -> A
// | bar : Fn (x : Foo A) -> (x.foo) self.+ (self.foo)
// instantiate these! ^ ^
@Override public @NotNull Term telescope(int i, Seq teleArgs) {
// teleArgs are former members
assert i < telescopeSize;
return clazz.telescope(i, teleArgs);
}
@Override public @NotNull Term result(Seq teleArgs) {
return clazz.result(telescopeSize);
}
@Override public @NotNull SeqView namesView() {
return clazz.members().sliceView(0, telescopeSize).map(AnyDef::name);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy