UNPKG

@harmoniclabs/plu-ts-onchain

Version:

An embedded DSL for Cardano smart contracts creation coupled with a library for Cardano transactions, all in Typescript

240 lines (238 loc) 11.7 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); 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."); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.pstruct = void 0; var PData_1 = require("../PData/PData.js"); var addUtilityForType_1 = require("../../lib/std/UtilityTerms/addUtilityForType.js"); var utils_1 = require("../../type_system/utils.js"); var types_1 = require("../../type_system/types.js"); var type_system_1 = require("../../type_system/index.js"); var Term_1 = require("../../Term/index.js"); var punsafeConvertType_1 = require("../../lib/punsafeConvertType/index.js"); var obj_utils_1 = require("@harmoniclabs/obj-utils"); var assert_1 = require("../../../utils/assert.js"); var plutus_data_1 = require("@harmoniclabs/plutus-data"); var plutus_machine_1 = require("@harmoniclabs/plutus-machine"); var IRHoisted_1 = require("../../../IR/IRNodes/IRHoisted.js"); var IRConst_1 = require("../../../IR/IRNodes/IRConst.js"); var const_1 = require("../../lib/std/list/const/index.js"); var IRNative_1 = require("../../../IR/IRNodes/IRNative/index.js"); var IRApp_1 = require("../../../IR/IRNodes/IRApp.js"); /** * intermediate class useful to reconise structs form primitives */ var _PStruct = /** @class */ (function (_super) { __extends(_PStruct, _super); function _PStruct() { return _super.call(this) || this; } return _PStruct; }(PData_1.PData)); function isStructInstanceOfDefinition(structInstance, definition) { var jsStructFieldsNames = Object.keys(structInstance); var defKeys = Object.keys(definition); return (jsStructFieldsNames.length === defKeys.length && defKeys.every(function (defFieldName) { return jsStructFieldsNames.includes(defFieldName); }) && jsStructFieldsNames.every(function (fieldKey) { return definition[fieldKey] !== undefined && // every field's value is a Term structInstance[fieldKey] instanceof Term_1.Term /*thisCtorDef[fieldKey]*/ && (0, type_system_1.typeExtends)(structInstance[fieldKey].type, (0, types_1.asData)(definition[fieldKey])); })); } var RESERVED_STRUCT_KEYS = Object.freeze([ "eq", "peq", "extract", "in", "raw" ]); /** * * @param {StructDef} def data-type definition of the struct * * each property of the object is a possible constructor for the struct; * * each constructor is defined by specifiying the fields that constructor expects and relative types * * @example * ```ts * const Shape = pstruct({ * Circle: { * radius: int * }, * Rectangle: { * fstSide: int, * sndSide: int * } * }); * ``` * * @param {( self_t: StructT<StructDef,{}> ) => Methods} getMethods (optional) function to implement arbitrary methods on a given struct. * * the function takes as first argument the type of this same struct and expects an object with various methods to be implemented on a struct instance * * @example * ```ts * const Shape = pstruct({ * Circle: { * radius: int * }, * Rectangle: { * fstSide: int, * sndSide: int * } * }, ( self_t ) => { * * return { * largestSide: pfn([ self_t ], int ) * ( self => * pmatch( self ) * .onCircle(({ radius }) => radius ) * .onRectangle({ fstSide, sndSide } => * pif( int ).$( fstSide.gt( sndSide ) ) * .then( fstSide ) * .else( sndSide ) * ) * ) * }; * }); * * const isLargeShape = pfn([ Shape.type ], int ) * ( shape => shape.largestSide.gtEq( 100 ) ) * ``` */ function pstruct(def, getMethods) { (0, assert_1.assert)((0, type_system_1.isStructDefinition)(def), "cannot construct 'PStruct' type; struct definition is not constant: " + (0, utils_1.structDefToString)(def)); getMethods = typeof getMethods === "function" ? getMethods : function (_self_t) { return {}; }; var PStructExt = /** @class */ (function (_super) { __extends(PStructExt, _super); // private constructors are not a thing at js runtime // in any case constructing an instance is useless // private allows the typescript LSP to rise errors (not runtime) whet trying to extend the class function PStructExt() { return _super.call(this) || this; } PStructExt._isPType = true; return PStructExt; }(_PStruct)); var noMethodsType = (0, types_1.struct)(def); var methods = getMethods(noMethodsType); var thisStructType = (0, types_1.struct)(def, methods); (0, obj_utils_1.defineReadOnlyProperty)(PStructExt, "type", thisStructType); (0, obj_utils_1.defineReadOnlyProperty)(PStructExt, "termType", thisStructType); (0, obj_utils_1.defineReadOnlyProperty)(PStructExt, "fromData", function (dataTerm /* | PappArg<PData> */) { // dataTerm = dataTerm instanceof Term ? dataTerm : pappArgToTerm( dataTerm, data ) as Term<PData>; (0, assert_1.assert)((0, type_system_1.typeExtends)(dataTerm.type, types_1.data), "trying to construct a Struct using static method 'fromData'; but the `Data` argument is not a `Data.Constr`"); // basically only mocking typescript here; still data return new Term_1.Term(thisStructType, dataTerm.toIR, dataTerm.isConstant); }); (0, obj_utils_1.defineReadOnlyProperty)(PStructExt, "toData", function (struct) { (0, assert_1.assert)((0, type_system_1.typeExtends)(struct.type, thisStructType), "trying to conver a struct using the wrong 'toData', perhaps you ment to call the 'toData' method of an other struct?"); return (0, punsafeConvertType_1.punsafeConvertType)(struct, (0, types_1.asData)(struct.type)); }); var constructors = Object.keys(def); (0, assert_1.assert)(constructors.length >= 1, "struct definition requires at least 1 constructor"); var _loop_1 = function (i) { var ctorName = constructors[i]; (0, obj_utils_1.defineReadOnlyProperty)(PStructExt.prototype, ctorName, function (jsStruct) { var e_1, _a; (0, assert_1.assert)((0, obj_utils_1.isObject)(jsStruct), "cannot build a plu-ts structure if the input is not an object with named fields"); var thisCtorDef = def[ctorName]; // const jsStructFieldsNames = Object.keys( jsStruct ); // order of fields in the 'jsStruct' migth be different than the order of the definiton // to preserve the order we need to use the keys got form the ctor definition var ctorDefFieldsNames = Object.keys(thisCtorDef); try { for (var ctorDefFieldsNames_1 = (e_1 = void 0, __values(ctorDefFieldsNames)), ctorDefFieldsNames_1_1 = ctorDefFieldsNames_1.next(); !ctorDefFieldsNames_1_1.done; ctorDefFieldsNames_1_1 = ctorDefFieldsNames_1.next()) { var fieldName = ctorDefFieldsNames_1_1.value; if (RESERVED_STRUCT_KEYS.includes(fieldName)) { throw new Error("\"".concat(fieldName, "\" is a reserved struct key; it can't be used as custom struct property.")); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (ctorDefFieldsNames_1_1 && !ctorDefFieldsNames_1_1.done && (_a = ctorDefFieldsNames_1.return)) _a.call(ctorDefFieldsNames_1); } finally { if (e_1) throw e_1.error; } } if (ctorDefFieldsNames.length === 0) { return (0, addUtilityForType_1.addUtilityForType)(thisStructType)(new Term_1.Term(thisStructType, function (_dbn) { return new IRHoisted_1.IRHoisted(IRConst_1.IRConst.data(new plutus_data_1.DataConstr(i, []))); }, true)); } // still we must be sure that the jsStruct has at least all the fields (0, assert_1.assert)(isStructInstanceOfDefinition(jsStruct, thisCtorDef), "the fields passed do not match the struct definition for constructor: " + ctorName); var dataReprTerm; if (ctorDefFieldsNames.every(function (fieldKey) { return jsStruct[fieldKey].isConstant; })) { dataReprTerm = new Term_1.Term(thisStructType, function (cfg, _dbn) { return IRConst_1.IRConst.data(new plutus_data_1.DataConstr(i, ctorDefFieldsNames.map(function (fieldKey) { var _term = jsStruct[fieldKey]; // toData_minimal( thisCtorDef[ fieldKey ] ) // ( jsStruct[ fieldKey ] ); var res = (plutus_machine_1.Machine.evalSimple(_term)); if (!(res instanceof plutus_machine_1.CEKConst && (0, plutus_data_1.isData)(res.value))) { console.log("--------------------------------"); console.log(ctorDefFieldsNames); console.log(fieldKey, (0, utils_1.termTypeToString)(thisCtorDef[fieldKey])); console.log(res); // console.log( showUPLC( _term.toIR( cfg, _dbn ) ) ) throw res; } return res.value; }))); }, true // isConstant ); } else { dataReprTerm = new Term_1.Term(thisStructType, function (cfg, dbn) { return new IRApp_1.IRApp(new IRApp_1.IRApp(IRNative_1.IRNative.constrData, IRConst_1.IRConst.int(i)), (0, const_1.pList)(types_1.data)(ctorDefFieldsNames.map(function (fieldKey) { var res = jsStruct[fieldKey]; // toData_minimal( thisCtorDef[ fieldKey ] )( jsStruct[ fieldKey ] ); return res; })).toIR(cfg, dbn)); }); } return (0, addUtilityForType_1.addUtilityForType)(thisStructType)(dataReprTerm); }); (0, obj_utils_1.defineReadOnlyProperty)(PStructExt, ctorName, PStructExt.prototype[ctorName]); }; // define constructors for (var i = 0; i < constructors.length; i++) { _loop_1(i); } /* Type 'typeof PStructExt' is not assignable to type 'PStruct<StructDef>' Why is this? */ return PStructExt; } exports.pstruct = pstruct;