@harmoniclabs/plu-ts-onchain
Version:
An embedded DSL for Cardano smart contracts creation coupled with a library for Cardano transactions, all in Typescript
73 lines (72 loc) • 3.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports._precursive = void 0;
var IRFunc_1 = require("../../../IR/IRNodes/IRFunc.js");
var IRRecursive_1 = require("../../../IR/IRNodes/IRRecursive.js");
var IRSelfCall_1 = require("../../../IR/IRNodes/IRSelfCall.js");
var IRVar_1 = require("../../../IR/IRNodes/IRVar.js");
var _modifyChildFromTo_1 = require("../../../IR/toUPLC/_internal/_modifyChildFromTo.js");
var getChildren_1 = require("../../../IR/tree_utils/getChildren.js");
var assert_1 = require("../../../utils/assert.js");
var Term_1 = require("../../Term/index.js");
var type_system_1 = require("../../type_system/index.js");
/**
* for reference the "Z combinator in js": https://medium.com/swlh/y-and-z-combinators-in-javascript-lambda-calculus-with-real-code-31f25be934ec
*
* ```js
* const Zcombinator = (
* Z => (
* toMakeRecursive => Z( value => toMakeRecursive(toMakeRecursive)(value) )
* )( toMakeRecursive => Z( value => toMakeRecursive(toMakeRecursive)(value)) )
* );
* ```
* of type
* ```js
* Z => toMakeRecursive => value => result
* ```
* and ```toMakeRecursive``` has to be of type
* ```js
* self => value => result
* ```
*/
function _precursive(fnBody) {
var a = (0, type_system_1.tyVar)("recursive_fn_a");
var b = (0, type_system_1.tyVar)("recursive_fn_b");
(0, assert_1.assert)((0, type_system_1.typeExtends)(fnBody.type, (0, type_system_1.lam)((0, type_system_1.lam)(a, b), (0, type_system_1.lam)(a, b))), "passed function body cannot be recursive; " +
"the first argument is not a lambda or it doesn't take any input");
var recursiveFn = new Term_1.Term(fnBody.type[2], function (cfg, dbn) {
var fnBodyIr = assertArity2AndRemoveFirst(fnBody.toIR(cfg, dbn));
replaceSelfVars(fnBodyIr);
return new IRRecursive_1.IRRecursive(fnBodyIr);
// return new IRApp(
// IRNative.z_comb,
// fnBodyIr
// )
});
return (recursiveFn);
}
exports._precursive = _precursive;
function assertArity2AndRemoveFirst(term) {
if (!(term instanceof IRFunc_1.IRFunc))
throw new Error("argument of precursive must be a function");
if (term.arity >= 2) {
return new IRFunc_1.IRFunc(term.arity - 1, term.body);
}
// else term.arity === 1
if (!(term.body instanceof IRFunc_1.IRFunc))
throw new Error("argument of precursive must be a function with arity >= 2");
return term.body;
}
function replaceSelfVars(term, dbn) {
if (dbn === void 0) { dbn = 0; }
if (term instanceof IRVar_1.IRVar) {
if (term.dbn === dbn) {
(0, _modifyChildFromTo_1._modifyChildFromTo)(term.parent, term, new IRSelfCall_1.IRSelfCall(dbn));
}
return;
}
if (term instanceof IRFunc_1.IRFunc ||
term instanceof IRRecursive_1.IRRecursive)
return replaceSelfVars(term.body, dbn + term.arity);
(0, getChildren_1.getChildren)(term).forEach(function (child) { return replaceSelfVars(child, dbn); });
}