@harmoniclabs/plu-ts-onchain
Version:
An embedded DSL for Cardano smart contracts creation coupled with a library for Cardano transactions, all in Typescript
152 lines (151 loc) • 5.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.typeExtends = exports.sopDefExtends = void 0;
var isTaggedAsAlias_1 = require("./kinds/isTaggedAsAlias.js");
var isWellFormedType_1 = require("./kinds/isWellFormedType.js");
var tyArgs_1 = require("./tyArgs/index.js");
var unwrapAlias_1 = require("./tyArgs/unwrapAlias.js");
var types_1 = require("./types.js");
function isSymbol(stuff) {
return typeof stuff === "symbol";
}
/**
*
* @param a extending ctor
* @param b extended ctor
* @returns
*/
function ctorDefExtends(a, b, subs) {
if (subs === void 0) { subs = []; }
var aFields = Object.keys(a);
var bFields = Object.keys(b);
if (aFields.length !== bFields.length)
return false;
function findSym(tVar) {
return subs.find(function (pair) { return pair.tyVar === tVar; });
}
for (var i = 0; i < aFields.length; i++) {
// fields have to have the same order;
// oterwhise it would imply a different order in the `Data` onchain
if (aFields[i] !== bFields[i])
return false;
var field = aFields[i];
if (isSymbol(b[field][0])) {
var tyVar = b[field][0];
var tyArg = a[field];
var thisTyParam = findSym(tyVar);
if (thisTyParam === undefined) {
subs.push({
tyVar: tyVar,
tyArg: tyArg
});
continue;
}
if (isSymbol(tyArg[0])) {
if (tyArg[0] === thisTyParam.tyArg[0])
continue;
else
return false;
}
// type argument corresponding to type var doesn't match some of the argument previously found
// covers case of generic 'tyArg'
if (!typeExtends(tyArg, thisTyParam.tyArg /*, subs */))
return false;
if (!typeExtends(thisTyParam.tyArg, tyArg /*, subs */)) {
// this type arument is more general than the previous registered
thisTyParam.tyArg = tyArg;
continue;
}
continue;
}
if (!typeExtends(a[field], b[field] /*, subs */))
return false;
}
return true;
}
function sopDefExtends(extendingDef, sDef, subs) {
if (subs === void 0) { subs = []; }
var ctorNames = Object.keys(sDef);
var extendingCtors = Object.keys(extendingDef);
if (ctorNames.length !== extendingCtors.length)
return false;
// first check the names only in order
// not to do useless (potentially expensive)
// ctor definiton extension checks
for (var i = 0; i < ctorNames.length; i++) {
if (
// ctors have to be in the same position; otherwhise is a different struct;
ctorNames[i] !== extendingCtors[i])
return false;
}
for (var i = 0; i < ctorNames.length; i++) {
if (
// check for the same fields and the extending types to extend the given struct ones
!ctorDefExtends(extendingDef[extendingCtors[i]], sDef[ctorNames[i]], subs))
return false;
}
return true;
}
exports.sopDefExtends = sopDefExtends;
/*
* equivalent to ```A extends B``` but at plu-ts level
*/
function typeExtends(extending, extended) {
if (!((0, isWellFormedType_1.isWellFormedType)(extending) &&
(0, isWellFormedType_1.isWellFormedGenericType)(extended)))
return false;
return uncheckedTypeExtends(extending, extended);
}
exports.typeExtends = typeExtends;
function uncheckedTypeExtends(a, b) {
if ((0, isTaggedAsAlias_1.isTaggedAsAlias)(b))
return uncheckedTypeExtends(a, (0, unwrapAlias_1.unwrapAlias)(b));
if ((0, isTaggedAsAlias_1.isTaggedAsAlias)(a))
return uncheckedTypeExtends((0, unwrapAlias_1.unwrapAlias)(a), b);
if (typeof b[0] === "symbol")
return true;
if (b[0] === types_1.PrimType.Data) {
return (a[0] === types_1.PrimType.Data ||
a[0] === types_1.PrimType.Struct ||
a[0] === types_1.PrimType.AsData);
}
if (b[0] === types_1.PrimType.AsData) {
return ((a[0] === types_1.PrimType.AsData &&
uncheckedTypeExtends(a[1], b[1])) ||
a[0] === types_1.PrimType.Struct ||
a[0] === types_1.PrimType.Data);
}
if (b[0] === types_1.PrimType.Pair) {
// `getFstT` and `getSndT` unwraps `alias`es and `asData`s
return (a[0] === types_1.PrimType.Pair &&
(uncheckedTypeExtends((0, tyArgs_1.getFstT)(a), (0, tyArgs_1.getFstT)(b))) &&
(uncheckedTypeExtends((0, tyArgs_1.getSndT)(a), (0, tyArgs_1.getSndT)(b))));
}
if (a[0] === types_1.PrimType.AsData) {
// checked above
// if( b[0] === PrimType.Data ) return true;
// if( b[0] === PrimType.AsData ) return uncheckedTypeExtends( a[1], b[1] );
return b[0] === types_1.PrimType.Struct;
}
if (b[0] === types_1.PrimType.Sop)
return (0, isWellFormedType_1.isSopType)(a) && sopDefExtends(a[1], b[1]);
if (a[0] === types_1.PrimType.Sop)
return false; // b must have been a SoP too
if (b[0] === types_1.PrimType.Struct)
return (0, isWellFormedType_1.isStructType)(a) && sopDefExtends(a[1], b[1]);
// if a is a sturct but b is not
// make sure b extends `data` at least
if ((0, isWellFormedType_1.isStructType)(a))
return uncheckedTypeExtends(b, types_1.data);
var bTyArgs = b.slice(1);
var aTyArgs = a.slice(1);
return (
// any other prim type that requires parameters
a[0] === b[0] &&
// same n parameters
aTyArgs.length === bTyArgs.length &&
// must have correct parameters following
aTyArgs.every(function (aTyArg, idx) {
return uncheckedTypeExtends(aTyArg, bTyArgs[idx]);
}));
}