@harmoniclabs/plu-ts-onchain
Version:
An embedded DSL for Cardano smart contracts creation coupled with a library for Cardano transactions, all in Typescript
383 lines (382 loc) • 17.9 kB
JavaScript
;
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleLettedAndReturnRoot = void 0;
var IRApp_1 = require("../../../IRNodes/IRApp.js");
var IRFunc_1 = require("../../../IRNodes/IRFunc.js");
var IRLetted_1 = require("../../../IRNodes/IRLetted.js");
var IRVar_1 = require("../../../IRNodes/IRVar.js");
var _modifyChildFromTo_1 = require("../../_internal/_modifyChildFromTo.js");
var findAll_1 = require("../../_internal/findAll.js");
var getDebruijnInTerm_1 = require("../../_internal/getDebruijnInTerm.js");
var groupByScope_1 = require("./groupByScope.js");
var IRDelayed_1 = require("../../../IRNodes/IRDelayed.js");
var IRForced_1 = require("../../../IRNodes/IRForced.js");
var lowestCommonAncestor_1 = require("../../_internal/lowestCommonAncestor.js");
var isIRTerm_1 = require("../../../utils/isIRTerm.js");
var markRecursiveHoistsAsForced_1 = require("../markRecursiveHoistsAsForced.js");
var IRConst_1 = require("../../../IRNodes/IRConst.js");
var incrementUnboundDbns_1 = require("./incrementUnboundDbns.js");
var IRHash_1 = require("../../../IRHash.js");
var sanifyTree_1 = require("../sanifyTree.js");
var mapArrayLike_1 = require("../../../IRNodes/utils/mapArrayLike.js");
var IRCase_1 = require("../../../IRNodes/IRCase.js");
var IRConstr_1 = require("../../../IRNodes/IRConstr.js");
var IRRecursive_1 = require("../../../IRNodes/IRRecursive.js");
var IRSelfCall_1 = require("../../../IRNodes/IRSelfCall.js");
var findHighestRecursiveParent_1 = require("./findHighestRecursiveParent.js");
function handleLettedAndReturnRoot(term) {
var _a, _b;
// console.log(" ------------------------------------------- handleLetted ------------------------------------------- ");
// console.log( prettyIRText( term ))
// most of the time we are just compiling small
// pre-execuded terms (hence constants)
if (term instanceof IRConst_1.IRConst)
return term;
// TODO: should probably merge `markRecursiveHoistsAsForced` inside `getLettedTerms` to iter once
(0, markRecursiveHoistsAsForced_1.markRecursiveHoistsAsForced)(term);
var _loop_1 = function () {
var e_1, _c, e_2, _d;
var allDirectLetted = (0, IRLetted_1.getLettedTerms)(term, { all: false, includeHoisted: false });
if (allDirectLetted.length === 0)
return { value: term };
var sortedLettedSet = (0, IRLetted_1.getSortedLettedSet)(allDirectLetted);
var _e = sortedLettedSet.pop(), letted = _e.letted, nReferences = _e.nReferences;
/*
const _lettedValue_ = letted.value;
const shouldLog = (
_lettedValue_ instanceof IRApp &&
_lettedValue_.fn instanceof IRFunc &&
_lettedValue_.fn.arity === 1 &&
_lettedValue_.fn.body instanceof IRLetted &&
equalIrHash( _lettedValue_.fn.body.hash, new Uint32Array( fromHex("71030a2d7560e563fe25fd782edd847f").buffer ) as IRHash ) &&
_lettedValue_.arg instanceof IRLetted &&
equalIrHash( _lettedValue_.arg.hash, new Uint32Array( fromHex("82dfb8a2f2703fe59fb25f8372e5e958").buffer ) as IRHash )
);
//*/
// shouldLog && console.log("nReferences", nReferences);
// console.log(` ------------------ working with ${lettedToStr(letted)} ------------------ `);
if (nReferences === 1) {
// console.log("inlining letted (single reference) with value", prettyIRText( letted.value ) )
(0, _modifyChildFromTo_1._modifyChildFromTo)(letted.parent, letted, letted.value);
return "continue";
}
var maxScope = (_a = findLettedMaxScope(letted)) !== null && _a !== void 0 ? _a : (function () {
if (letted.meta.isClosed || letted.isClosedAtDbn(0)) {
// value is closed (hoisted),
// so the max scope is the entire script
return term;
}
else
throw new Error("could not find a max scope for letted value with hash ".concat((0, IRHash_1.irHashToHex)(letted.hash)));
})();
var lettedTermCanBeHoisted = maxScope === term;
var minScope = (0, findHighestRecursiveParent_1.findHighestRecursiveParent)(letted, maxScope);
(0, sanifyTree_1.sanifyTree)(maxScope);
var lettedHash = letted.hash;
var sameLettedRefs = (0, findAll_1.findAllNoHoisted)(maxScope, function (node) {
return node instanceof IRLetted_1.IRLetted &&
(0, IRHash_1.equalIrHash)(node.hash, lettedHash);
});
if (sameLettedRefs.length <= 0) {
console.warn("how did you get here? 0 references found for letted term;\n\n" +
"!!! PLEASE OPEN AN ISSUE ON GITHUB (https://github.com/HarmonicLabs/plu-ts/issues) !!!\n\n");
return "continue";
}
// just in case
if (sameLettedRefs.length === 1 && !minScope) {
// console.log("inlining letted (single reference pedantic) with value", prettyIRText( letted.value ) )
(0, _modifyChildFromTo_1._modifyChildFromTo)(letted.parent, letted, letted.value);
return "continue";
}
// always inline letted vars
if (letted.value instanceof IRVar_1.IRVar ||
letted.value instanceof IRSelfCall_1.IRSelfCall) {
try {
// console.log("inlining letted (value is var) with value", prettyIRText( letted.value ) )
for (var sameLettedRefs_1 = (e_1 = void 0, __values(sameLettedRefs)), sameLettedRefs_1_1 = sameLettedRefs_1.next(); !sameLettedRefs_1_1.done; sameLettedRefs_1_1 = sameLettedRefs_1.next()) {
var elem = sameLettedRefs_1_1.value;
// inline
(0, _modifyChildFromTo_1._modifyChildFromTo)(elem.parent, elem, elem.value);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (sameLettedRefs_1_1 && !sameLettedRefs_1_1.done && (_c = sameLettedRefs_1.return)) _c.call(sameLettedRefs_1);
}
finally { if (e_1) throw e_1.error; }
}
return "continue";
}
var lca = minScope !== null && minScope !== void 0 ? minScope : sameLettedRefs[0];
// const forceHoist = false && sameLettedRefs.some( letted => letted.meta.forceHoist === true );
for (var j = 1; j < sameLettedRefs.length; j++) {
var prevLca = lca;
lca = (0, lowestCommonAncestor_1.lowestCommonAncestor)(lca, sameLettedRefs[j], maxScope);
if (!(0, isIRTerm_1.isIRTerm)(lca)) {
lca = prevLca;
}
;
}
if (!(0, isIRTerm_1.isIRTerm)(lca)) {
throw new Error("letting nodes with hash " + (0, IRHash_1.irHashToHex)(lettedHash) + " from different trees");
}
var realLca = lca;
// point to the first func or delay node above the lca
// (worst case scenario we hit the maxScope; which is an IRFunc)
// IRFuncs should always be under IRRecursives if any
while (!(lca instanceof IRFunc_1.IRFunc ||
lca instanceof IRDelayed_1.IRDelayed) && lca) {
lca = (_b = lca === null || lca === void 0 ? void 0 : lca.parent) !== null && _b !== void 0 ? _b : undefined;
}
if (!(0, isIRTerm_1.isIRTerm)(lca)) {
if (!lettedTermCanBeHoisted)
throw new Error("lowest common ancestor outside the max scope");
lca = realLca;
var tmpRoot = handleLettedAsHoistedAndReturnRoot(letted, realLca, // lca
sameLettedRefs, term);
if (lca === maxScope || !lca.parent)
term = tmpRoot;
return "continue";
}
var parentNode = lca;
var parentNodeDirectChild = (parentNode instanceof IRFunc_1.IRFunc ||
parentNode instanceof IRRecursive_1.IRRecursive) ? parentNode.body : parentNode.delayed;
// add 1 to every var's DeBruijn that accesses stuff outside the parent node
// not including the `parentNode` node
// since the new function introdcued substituting the letted term
// is added inside the `parentNode` node
(0, incrementUnboundDbns_1.incrementUnboundDbns)(parentNodeDirectChild,
// `shouldNotModifyLetted` arg (given the hash returns `true` if it should NOT modify the term)
// this callback is ONLY called on LETTED terms
function (_a) {
var hash = _a.hash;
return (0, IRHash_1.equalIrHash)(hash, lettedHash);
});
// now we replace
var lettedValue = letted.value.clone();
modifyValueToLetDbns(lettedValue, getDiffDbn(letted, parentNode));
var newNode = new IRApp_1.IRApp(new IRFunc_1.IRFunc(1, parentNodeDirectChild), lettedValue, { __src__: letted.meta.__src__ });
// replace child with new node
if (parentNode instanceof IRFunc_1.IRFunc || parentNode instanceof IRRecursive_1.IRRecursive)
parentNode.body = newNode;
else
parentNode.delayed = newNode;
try {
for (var sameLettedRefs_2 = (e_2 = void 0, __values(sameLettedRefs)), sameLettedRefs_2_1 = sameLettedRefs_2.next(); !sameLettedRefs_2_1.done; sameLettedRefs_2_1 = sameLettedRefs_2.next()) {
var ref = sameLettedRefs_2_1.value;
(0, _modifyChildFromTo_1._modifyChildFromTo)(ref.parent, ref, new IRVar_1.IRVar((0, getDebruijnInTerm_1.getDebruijnInTerm)(parentNodeDirectChild, ref)));
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (sameLettedRefs_2_1 && !sameLettedRefs_2_1.done && (_d = sameLettedRefs_2.return)) _d.call(sameLettedRefs_2);
}
finally { if (e_2) throw e_2.error; }
}
};
// in case there are no letted terms there is no work to do
while (true) {
var state_1 = _loop_1();
if (typeof state_1 === "object")
return state_1.value;
}
}
exports.handleLettedAndReturnRoot = handleLettedAndReturnRoot;
/**
*
* @param letted
* @returns {IRFunc} the lowest `IRFunc` in the tree that defines all the variables needed for the
*/
function findLettedMaxScope(letted) {
var minUnboundDbn = (0, groupByScope_1._getMinUnboundDbn)(letted.value);
if (minUnboundDbn === undefined) {
var tmp_1 = letted;
var maxScope_1 = undefined;
while (tmp_1.parent) {
tmp_1 = tmp_1.parent;
if (tmp_1 instanceof IRFunc_1.IRFunc || tmp_1 instanceof IRDelayed_1.IRDelayed)
maxScope_1 = tmp_1;
}
;
return maxScope_1;
}
var tmp = letted;
var maxScope = undefined;
while (minUnboundDbn >= 0) {
if (!tmp.parent) {
throw new Error("could not find a max scope for letted value with hash ".concat((0, IRHash_1.irHashToHex)(letted.hash), "; ") +
"the max parent found leaves the term open (reached root)");
}
tmp = tmp.parent;
if (tmp instanceof IRRecursive_1.IRRecursive) {
minUnboundDbn -= tmp.arity;
// maxScope = tmp; // recursive cannot be a max scope
}
else if (tmp instanceof IRFunc_1.IRFunc) {
minUnboundDbn -= tmp.arity;
maxScope = tmp;
}
}
// just ts sillyness here
if (!maxScope) {
throw new Error("could not find a max scope for letted value with hash ".concat((0, IRHash_1.irHashToHex)(letted.hash), "; ") +
"no IRFunc found");
}
return maxScope;
}
function modifyValueToLetDbns(lettedValue, diffDbn) {
if (diffDbn <= 0)
return;
// if there is any actual difference between the letted term
// and the position where it will be finally placed
// the value needs to be modified accoridingly
var stack = [{ term: lettedValue, dbn: 0 }];
var _loop_2 = function () {
var _a = stack.pop(), t = _a.term, dbn = _a.dbn;
if ((t instanceof IRVar_1.IRVar ||
t instanceof IRSelfCall_1.IRSelfCall) &&
t.dbn > dbn) {
t.dbn -= diffDbn;
}
if (t instanceof IRLetted_1.IRLetted) {
t.dbn -= diffDbn;
// reduce dbn in letted value too
stack.push({ term: t.value, dbn: dbn });
return "continue";
}
if (t instanceof IRApp_1.IRApp) {
stack.push({ term: t.arg, dbn: dbn }, { term: t.fn, dbn: dbn });
return "continue";
}
if (t instanceof IRCase_1.IRCase) {
stack.push.apply(stack, __spreadArray([{ term: t.constrTerm, dbn: dbn }], __read((0, mapArrayLike_1.mapArrayLike)(t.continuations, function (continuation) { return ({ term: continuation, dbn: dbn }); })), false));
return "continue";
}
if (t instanceof IRConstr_1.IRConstr) {
stack.push.apply(stack, __spreadArray([], __read((0, mapArrayLike_1.mapArrayLike)(t.fields, function (field) { return ({ term: field, dbn: dbn }); })), false));
return "continue";
}
if (t instanceof IRDelayed_1.IRDelayed) {
stack.push({ term: t.delayed, dbn: dbn });
return "continue";
}
if (t instanceof IRForced_1.IRForced) {
stack.push({ term: t.forced, dbn: dbn });
return "continue";
}
if (t instanceof IRFunc_1.IRFunc) {
stack.push({ term: t.body, dbn: dbn + t.arity });
return "continue";
}
if (t instanceof IRRecursive_1.IRRecursive) {
stack.push({ term: t.body, dbn: dbn + t.arity });
return "continue";
}
};
while (stack.length > 0) {
_loop_2();
}
}
/**
* @returns the difference in DeBruijn
* between the maxScope and the letted term
*/
function getDiffDbn(letted, parentNode) {
// get the difference in DeBruijn
// between the maxScope and the letted term
var diffDbn = 0;
//*
var tmpNode = letted;
while (tmpNode !== parentNode) {
tmpNode = tmpNode.parent;
if ( // is an intermediate `IRFunc`
(tmpNode instanceof IRFunc_1.IRFunc ||
tmpNode instanceof IRRecursive_1.IRRecursive) &&
tmpNode !== parentNode // avoid counting parent node arity if IRFunc
) {
// increment differential in DeBruijn by n vars indroduced here
diffDbn += tmpNode.arity;
}
}
return diffDbn;
}
function handleLettedAsHoistedAndReturnRoot(letted, lca, sameLettedRefs, currentRoot) {
var e_3, _a;
var lettedHash = letted.hash;
var parentNode = lca.parent;
var parentNodeDirectChild = lca;
// add 1 to every var's DeBruijn that accesses stuff outside the parent node
// not including the `parentNode` node
// since the new function introdcued substituting the letted term
// is added inside the `parentNode` node
(0, incrementUnboundDbns_1.incrementUnboundDbns)(parentNodeDirectChild,
// `shouldNotModifyLetted` arg (given the hash returns `true` if it should NOT modify the term)
function (_a) {
var hash = _a.hash;
return (0, IRHash_1.equalIrHash)(hash, lettedHash);
});
// now we replace
var lettedValue = letted.value; //.clone();
// no need to modify letted value dbns, since closed
// modifyValueToLetDbns( lettedValue, getDiffDbn( letted, parentNode ) );
var newNode = new IRApp_1.IRApp(new IRFunc_1.IRFunc(1, parentNodeDirectChild), lettedValue, { __src__: letted.meta.__src__ });
// replace child with new node
if (parentNode) {
(0, _modifyChildFromTo_1._modifyChildFromTo)(parentNode, parentNodeDirectChild, newNode);
}
else {
currentRoot = newNode;
}
try {
for (var sameLettedRefs_3 = __values(sameLettedRefs), sameLettedRefs_3_1 = sameLettedRefs_3.next(); !sameLettedRefs_3_1.done; sameLettedRefs_3_1 = sameLettedRefs_3.next()) {
var ref = sameLettedRefs_3_1.value;
(0, _modifyChildFromTo_1._modifyChildFromTo)(ref.parent, ref, new IRVar_1.IRVar((0, getDebruijnInTerm_1.getDebruijnInTerm)(parentNodeDirectChild, ref)));
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (sameLettedRefs_3_1 && !sameLettedRefs_3_1.done && (_a = sameLettedRefs_3.return)) _a.call(sameLettedRefs_3);
}
finally { if (e_3) throw e_3.error; }
}
return currentRoot;
}