@harmoniclabs/plu-ts-onchain
Version:
An embedded DSL for Cardano smart contracts creation coupled with a library for Cardano transactions, all in Typescript
190 lines (188 loc) • 8.3 kB
JavaScript
;
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.psop = void 0;
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 PType_1 = require("../../PType/index.js");
var obj_utils_1 = require("@harmoniclabs/obj-utils");
var assert_1 = require("../../../utils/assert.js");
var IRConstr_1 = require("../../../IR/IRNodes/IRConstr.js");
/**
* intermediate class useful to reconise structs form primitives
*/
var _PSop = /** @class */ (function (_super) {
__extends(_PSop, _super);
function _PSop() {
return _super.call(this) || this;
}
return _PSop;
}(PType_1.PType));
function isSopInstanceOfDefinition(structInstance, definition) {
var jsSopFieldsNames = Object.keys(structInstance);
var defKeys = Object.keys(definition);
return (jsSopFieldsNames.length === defKeys.length &&
defKeys.every(function (defFieldName) { return jsSopFieldsNames.includes(defFieldName); }) &&
jsSopFieldsNames.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, definition[fieldKey]);
}));
}
var RESERVED_STRUCT_KEYS = Object.freeze([
"eq",
"peq",
"extract",
"in",
"raw"
]);
/**
*
* @param {SopDef} def data-type definition of the sop
*
* each property of the object is a possible constructor for the sop;
*
* 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: SopT<SopDef,{}> ) => Methods} getMethods (optional) function to implement arbitrary methods on a given sop.
*
* the function takes as first argument the type of this same sop and expects an object with various methods to be implemented on a sop 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 psop(def, getMethods) {
(0, assert_1.assert)((0, type_system_1.isSopDefinition)(def), "cannot construct 'PSop' type; sop definition is not constant: " + (0, utils_1.structDefToString)(def));
getMethods = typeof getMethods === "function" ? getMethods : function (_self_t) { return {}; };
var PSopExt = /** @class */ (function (_super) {
__extends(PSopExt, _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 PSopExt() {
return _super.call(this) || this;
}
PSopExt._isPType = true;
return PSopExt;
}(_PSop));
var noMethodsType = (0, types_1.sop)(def);
var methods = getMethods(noMethodsType);
var thisSopType = (0, types_1.sop)(def, methods);
(0, obj_utils_1.defineReadOnlyProperty)(PSopExt, "type", thisSopType);
(0, obj_utils_1.defineReadOnlyProperty)(PSopExt, "termType", thisSopType);
var constructors = Object.keys(def);
(0, assert_1.assert)(constructors.length >= 1, "sop definition requires at least 1 constructor");
var _loop_1 = function (i) {
var ctorName = constructors[i];
(0, obj_utils_1.defineReadOnlyProperty)(PSopExt.prototype, ctorName, function (jsSop) {
var e_1, _a;
(0, assert_1.assert)((0, obj_utils_1.isObject)(jsSop), "cannot build a plu-ts structure if the input is not an object with named fields");
var thisCtorDef = def[ctorName];
// const jsSopFieldsNames = Object.keys( jsSop );
// order of fields in the 'jsSop' 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 sop key; it can't be used as custom sop 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)(thisSopType)(new Term_1.Term(thisSopType, function (_dbn) { return new IRConstr_1.IRConstr(0, []); }));
}
// still we must be sure that the jsSop has at least all the fields
(0, assert_1.assert)(isSopInstanceOfDefinition(jsSop, thisCtorDef), "the fields passed do not match the sop definition for constructor: " + ctorName);
return (0, addUtilityForType_1.addUtilityForType)(thisSopType)(new Term_1.Term(thisSopType, function (cfg, dbn) { return new IRConstr_1.IRConstr(i, ctorDefFieldsNames.map(function (fieldKey) { return jsSop[fieldKey].toIR(cfg, dbn); })); }));
});
(0, obj_utils_1.defineReadOnlyProperty)(PSopExt, ctorName, PSopExt.prototype[ctorName]);
};
// define constructors
for (var i = 0; i < constructors.length; i++) {
_loop_1(i);
}
/*
Type 'typeof PSopExt' is not assignable to type 'PSop<SopDef>'
Why is this?
*/
return PSopExt;
}
exports.psop = psop;