UNPKG

@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
"use strict"; 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; }