@harmoniclabs/uplc
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -1,4 +0,4 @@ | ||
import { UPLCTerm } from "../UPLCTerm/index.js"; | ||
import { UPLCTerm } from "../UPLCTerm/UPLCTerm.js"; | ||
export interface ToUPLC { | ||
toUPLC: (dbn?: number | bigint) => UPLCTerm; | ||
} |
@@ -9,3 +9,3 @@ "use strict"; | ||
var UPLCVersion_1 = require("../UPLCProgram/UPLCVersion.js"); | ||
var UPLCTerm_1 = require("../UPLCTerm/index.js"); | ||
var UPLCTerm_1 = require("../UPLCTerm/UPLCTerm.js"); | ||
var Application_1 = require("../UPLCTerms/Application.js"); | ||
@@ -219,7 +219,10 @@ var Builtin_1 = require("../UPLCTerms/Builtin/Builtin.js"); | ||
partialUPLC += "(error)"; | ||
return new ErrorUPLC_1.ErrorUPLC("error got from deserialization;", { | ||
debruijnLevel: currDbn, | ||
byteIndex: currByteIndex(), | ||
bitIndex: currPtr | ||
}); | ||
return new ErrorUPLC_1.ErrorUPLC( | ||
// "error got from deserialization;", | ||
// { | ||
// debruijnLevel: currDbn, | ||
// byteIndex: currByteIndex(), | ||
// bitIndex: currPtr | ||
// } | ||
); | ||
case 7: | ||
@@ -277,3 +280,10 @@ var bn_tag = Number(readNBits(7)); | ||
if ((0, ConstType_1.constTypeEq)(t, ConstType_1.constT.data)) { | ||
return (0, plutus_data_1.dataFromCbor)(readConstValueOfType(ConstType_1.constT.byteStr).toBuffer()); | ||
var bytes = readConstValueOfType(ConstType_1.constT.byteStr).toBuffer(); | ||
// data > 64 bytes encoded as indefinite | ||
if (bytes[0] === 0x5f && | ||
bytes.length > (64 + 2)) { | ||
// Cbor.parse will parse the indefinite length bytes as a single buffer | ||
bytes = cbor_1.Cbor.parse(bytes).buffer; | ||
} | ||
return (0, plutus_data_1.dataFromCbor)(bytes); | ||
} | ||
@@ -280,0 +290,0 @@ if ((0, ConstType_1.constTypeEq)(t, ConstType_1.constT.bool)) |
import { ConstValue } from "../UPLCTerms/UPLCConst/ConstValue/index.js"; | ||
import { PureUPLCTerm } from "../UPLCTerm/index.js"; | ||
import { UPLCTerm } from "../UPLCTerm/UPLCTerm.js"; | ||
import { UPLCProgram } from "../UPLCProgram/UPLCProgram.js"; | ||
@@ -26,3 +26,3 @@ import { UPLCVersion } from "../UPLCProgram/UPLCVersion.js"; | ||
encodeVersion(version: UPLCVersion): BitStream; | ||
encodeTerm(term: PureUPLCTerm): BitStream; | ||
encodeTerm(term: UPLCTerm): BitStream; | ||
encodeUPLCVar(uplcVar: UPLCVar): BitStream; | ||
@@ -51,2 +51,57 @@ encodeDelayTerm(delayed: Delay): BitStream; | ||
* in the Plutus GitHub repository IOHK [2019] for a definitive implementation. | ||
* | ||
* from the `encodeData` source: | ||
* | ||
* {- Note [The 64-byte limit] | ||
* We impose a 64-byte *on-the-wire* limit on the leaves of a serialized 'Data'. This prevents people from inserting | ||
* Mickey Mouse entire. | ||
* | ||
* The simplest way of doing this is to check during deserialization that we never deserialize something that uses | ||
* more than 64-bytes, and this is largely what we do. Then it's the user's problem to not produce something too big. | ||
* | ||
* But this is quite inconvenient, so see Note [Evading the 64-byte limit] for how we get around this. | ||
* -} | ||
* {- Note [Evading the 64-byte limit] | ||
* Implementing Note [The 64-byte limit] naively would be quite annoying: | ||
* - Users would be responsible for not creating Data values with leaves that were too big. | ||
* - If a script *required* such a thing (e.g. a counter that somehow got above 64 bytes), then the user is totally | ||
* stuck: the script demands something they cannot represent. | ||
* | ||
* This is unpleasant and introduces limits. Probably limits that nobody will hit, but it's nicer to just not have them. | ||
* And it turns out that we can evade the problem with some clever encoding. | ||
* | ||
* The fundamental | ||
* trick is that an *indefinite-length* CBOR bytestring is just as obfuscated as a list of bytestrings, | ||
* since it consists of a list of definite-length chunks, and each definite-length chunk must be *tagged* (at least with the size). | ||
* So we get a sequence like: | ||
* | ||
* <list start> | ||
* <chunk length metadata> | ||
* <chunk> | ||
* <chunk length metadata> | ||
* ... | ||
* <list end> | ||
* | ||
* The chunk length metadata has a prescribed format, such that it's difficult to manipulate it so that it | ||
* matches your "desired" data. | ||
* So this effectively breaks up the bytestring in much the same way as a list of <64 byte bytestrings. | ||
* | ||
* So that solves the problem for bytestrings on the encoding side: | ||
* - if they are <=64 bytes, we can just encode them as a normal bytestring | ||
* - if they are >64 bytes, we encode them as indefinite-length bytestrings with 64-byte chunks | ||
* | ||
* On the decoding side, we need to check when we decode that we never decode a definite-length | ||
* bytestring of >64 bytes. That covers our two cases: | ||
* - Short definite-length bytestrings are fine | ||
* - Long indefinite-length bytestrings are just made of short definite-length bytestings. | ||
* | ||
* * Unfortunately this all means that we have to write our own encoders/decoders so we can produce | ||
* * chunks of the right size and check the sizes when we decode, but that's okay. Users need to do the same | ||
* * thing: anyone encoding `Data` with their own encoders who doesn't split up big bytestrings in this way | ||
* * will get failures when we decode them. | ||
* | ||
* For integers, we have two cases. Small integers (<=64bits) can be encoded normally. Big integers are already | ||
* encoded *with a byte string*. The spec allows this to be an indefinite-length bytestring (although cborg doesn't | ||
* like it), so we can reuse our trick. Again, we need to write some manual encoders/decoders. | ||
* -} | ||
*/ | ||
@@ -53,0 +108,0 @@ encodeConstValueData(data: Data): BitStream; |
@@ -10,3 +10,3 @@ "use strict"; | ||
var UPLCBuiltinTag_1 = require("../UPLCTerms/Builtin/UPLCBuiltinTag.js"); | ||
var UPLCTerm_1 = require("../UPLCTerm/index.js"); | ||
var UPLCTerm_1 = require("../UPLCTerm/UPLCTerm.js"); | ||
var Application_1 = require("../UPLCTerms/Application.js"); | ||
@@ -68,3 +68,3 @@ var Builtin_1 = require("../UPLCTerms/Builtin/Builtin.js"); | ||
// no idea why deBruijn indicies start form 1...s | ||
// can dev do something? | ||
// can devs do something? | ||
uplcVar.deBruijn + BigInt(1))); | ||
@@ -126,21 +126,2 @@ return result; | ||
// ------------------------------------------------------------------------------------------------------------------- // | ||
function properlyCloneUPLC(uplc) { | ||
if (uplc instanceof UPLCVar_1.UPLCVar) | ||
return new UPLCVar_1.UPLCVar(uplc.deBruijn); | ||
if (uplc instanceof Delay_1.Delay) | ||
return new Delay_1.Delay(properlyCloneUPLC(uplc.delayedTerm)); | ||
if (uplc instanceof Lambda_1.Lambda) | ||
return new Lambda_1.Lambda(properlyCloneUPLC(uplc.body)); | ||
if (uplc instanceof Application_1.Application) | ||
return new Application_1.Application(properlyCloneUPLC(uplc.funcTerm), properlyCloneUPLC(uplc.argTerm)); | ||
if (uplc instanceof UPLCConst_1.UPLCConst) | ||
return new UPLCConst_1.UPLCConst(uplc.type, uplc.value); | ||
if (uplc instanceof Force_1.Force) | ||
return new Force_1.Force(properlyCloneUPLC(uplc.termToForce)); | ||
if (uplc instanceof ErrorUPLC_1.ErrorUPLC) | ||
return new ErrorUPLC_1.ErrorUPLC(uplc.msg, uplc.addInfos); | ||
if (uplc instanceof Builtin_1.Builtin) | ||
return new Builtin_1.Builtin(uplc.tag); | ||
throw new Error("unknown UPLC in 'properlyCloneUPLC'"); | ||
} | ||
var UPLCEncoder = /** @class */ (function () { | ||
@@ -158,3 +139,3 @@ function UPLCEncoder() { | ||
if (!(0, UPLCTerm_1.isPureUPLCTerm)(uplc)) { | ||
throw new Error("'replaceHoisteTerm' did not returned a 'PureUPLCTerm'"); | ||
throw new Error("'replaceHoisteTerm' did not return an 'UPLCTerm'"); | ||
} | ||
@@ -334,7 +315,74 @@ result.append(this.encodeTerm(uplc)); | ||
* in the Plutus GitHub repository IOHK [2019] for a definitive implementation. | ||
* | ||
* from the `encodeData` source: | ||
* | ||
* {- Note [The 64-byte limit] | ||
* We impose a 64-byte *on-the-wire* limit on the leaves of a serialized 'Data'. This prevents people from inserting | ||
* Mickey Mouse entire. | ||
* | ||
* The simplest way of doing this is to check during deserialization that we never deserialize something that uses | ||
* more than 64-bytes, and this is largely what we do. Then it's the user's problem to not produce something too big. | ||
* | ||
* But this is quite inconvenient, so see Note [Evading the 64-byte limit] for how we get around this. | ||
* -} | ||
* {- Note [Evading the 64-byte limit] | ||
* Implementing Note [The 64-byte limit] naively would be quite annoying: | ||
* - Users would be responsible for not creating Data values with leaves that were too big. | ||
* - If a script *required* such a thing (e.g. a counter that somehow got above 64 bytes), then the user is totally | ||
* stuck: the script demands something they cannot represent. | ||
* | ||
* This is unpleasant and introduces limits. Probably limits that nobody will hit, but it's nicer to just not have them. | ||
* And it turns out that we can evade the problem with some clever encoding. | ||
* | ||
* The fundamental | ||
* trick is that an *indefinite-length* CBOR bytestring is just as obfuscated as a list of bytestrings, | ||
* since it consists of a list of definite-length chunks, and each definite-length chunk must be *tagged* (at least with the size). | ||
* So we get a sequence like: | ||
* | ||
* <list start> | ||
* <chunk length metadata> | ||
* <chunk> | ||
* <chunk length metadata> | ||
* ... | ||
* <list end> | ||
* | ||
* The chunk length metadata has a prescribed format, such that it's difficult to manipulate it so that it | ||
* matches your "desired" data. | ||
* So this effectively breaks up the bytestring in much the same way as a list of <64 byte bytestrings. | ||
* | ||
* So that solves the problem for bytestrings on the encoding side: | ||
* - if they are <=64 bytes, we can just encode them as a normal bytestring | ||
* - if they are >64 bytes, we encode them as indefinite-length bytestrings with 64-byte chunks | ||
* | ||
* On the decoding side, we need to check when we decode that we never decode a definite-length | ||
* bytestring of >64 bytes. That covers our two cases: | ||
* - Short definite-length bytestrings are fine | ||
* - Long indefinite-length bytestrings are just made of short definite-length bytestings. | ||
* | ||
* * Unfortunately this all means that we have to write our own encoders/decoders so we can produce | ||
* * chunks of the right size and check the sizes when we decode, but that's okay. Users need to do the same | ||
* * thing: anyone encoding `Data` with their own encoders who doesn't split up big bytestrings in this way | ||
* * will get failures when we decode them. | ||
* | ||
* For integers, we have two cases. Small integers (<=64bits) can be encoded normally. Big integers are already | ||
* encoded *with a byte string*. The spec allows this to be an indefinite-length bytestring (although cborg doesn't | ||
* like it), so we can reuse our trick. Again, we need to write some manual encoders/decoders. | ||
* -} | ||
*/ | ||
UPLCEncoder.prototype.encodeConstValueData = function (data) { | ||
var cborBytes = (0, plutus_data_1.dataToCbor)(data).asBytes; | ||
if (cborBytes.length < 64) | ||
var cborBytes = (0, plutus_data_1.dataToCbor)(data).toBuffer(); | ||
// - if they are <=64 bytes, we can just encode them as a normal bytestring | ||
if (cborBytes.length <= 64) | ||
return this.encodeConstValueByteString(new bytestring_1.ByteString(cborBytes)); | ||
/* | ||
Large (>= 4 bytes) data encoding fixed in 1.1.0^ | ||
- if they are >64 bytes, we encode them as indefinite-length bytestrings with 64-byte chunks | ||
*/ | ||
/* | ||
**NOTE** | ||
this is only an UPLC serialization problem; | ||
UPLC builtin `serialiseData` just resutlts in a normal CBOR bytestring, no matter the length | ||
*/ | ||
var head = cborBytes.at(0); | ||
@@ -353,12 +401,12 @@ if (head === undefined) | ||
nLenBytes = 1; | ||
var ptr = nLenBytes + 1 + 1; | ||
var ptr = 0; | ||
var largeCborData = "5f"; | ||
while (ptr < cborBytes.length) { | ||
var chunkSize = Math.min(62, cborBytes.length); | ||
var chunkSize = Math.min(64, cborBytes.length - ptr); | ||
var chunkEnd = ptr + chunkSize; | ||
var header = ""; | ||
if (chunkSize < 24) | ||
header = (64 & chunkSize).toString(16); | ||
header = (64 | chunkSize).toString(16).padStart(2, "0"); | ||
else | ||
header = "58" + chunkSize.toString(16); | ||
header = "58" + chunkSize.toString(16).padStart(2, "0"); | ||
largeCborData = largeCborData + | ||
@@ -380,3 +428,2 @@ header + | ||
var missingBytes = bs.toString(); | ||
var isBadOne = missingBytes === "d87982d87981582066f225ce3f1acd5e9b133a09b571af99ea4f0742741d008e482d3d33a7329da300"; | ||
var hexChunks = []; | ||
@@ -383,0 +430,0 @@ while ((missingBytes.length / 2) > 255) { |
@@ -1,2 +0,2 @@ | ||
import { UPLCTerm } from "../UPLCTerm/index.js"; | ||
import { UPLCTerm } from "../UPLCTerm/UPLCTerm.js"; | ||
import { CanBeUInteger } from "../utils/ints.js"; | ||
@@ -3,0 +3,0 @@ import { UPLCVersion } from "./UPLCVersion.js"; |
@@ -1,53 +0,2 @@ | ||
import { UPLCVar } from "../UPLCTerms/UPLCVar/index.js"; | ||
import { Delay } from "../UPLCTerms/Delay.js"; | ||
import { Lambda } from "../UPLCTerms/Lambda.js"; | ||
import { Application } from "../UPLCTerms/Application.js"; | ||
import { UPLCConst } from "../UPLCTerms/UPLCConst/UPLCConst.js"; | ||
import { Force } from "../UPLCTerms/Force.js"; | ||
import { ErrorUPLC } from "../UPLCTerms/ErrorUPLC.js"; | ||
import { Builtin } from "../UPLCTerms/Builtin/Builtin.js"; | ||
import { ConstType } from "../UPLCTerms/UPLCConst/ConstType/index.js"; | ||
import { ConstValue } from "../UPLCTerms/UPLCConst/ConstValue/index.js"; | ||
export type UPLCTerm = UPLCVar | Delay | Lambda | Application | UPLCConst | Force | ErrorUPLC | Builtin; | ||
/** | ||
* @deprecated alias for `UPLCTerm` use that instead | ||
*/ | ||
export type PureUPLCTerm = UPLCTerm; | ||
/** | ||
* **_O(1)_** | ||
* @param {UPLCTerm} t ```UPLCTerm``` to check | ||
* @returns {boolean} ```true``` if the argument is instance of any of the ```UPLCTerm``` constructors, ```false``` otherwise | ||
*/ | ||
export declare function isUPLCTerm(t: object): t is UPLCTerm; | ||
/** | ||
* **_O(n)_** | ||
* @param {UPLCTerm} t ```UPLCTerm``` to check | ||
* @returns {boolean} ```true``` if the AST contains only plutus-core terms, ```false``` otherwise | ||
*/ | ||
export declare function isPureUPLCTerm(t: UPLCTerm): t is PureUPLCTerm; | ||
export declare function isClosedTerm(term: UPLCTerm): boolean; | ||
export declare function showUPLCConstValue(v: ConstValue): string; | ||
export declare function showConstType(t: ConstType): string; | ||
export declare function showUPLC(term: UPLCTerm): string; | ||
export declare function prettyUPLC(term: UPLCTerm, _indent?: number): string; | ||
/** | ||
* | ||
* @param {number | bigint} varDeBruijn ```number | bigint```; debruijn level (at the term level) of the variable to search for | ||
* @param {UPLCTerm} t ```UPLCTerm``` to search in | ||
* @returns {boolean} ```true``` if the variable has **at least** 1 or more references; ```false``` otherwise | ||
*/ | ||
export declare function hasAnyRefsInTerm(varDeBruijn: number | bigint, t: UPLCTerm): boolean; | ||
/** | ||
* | ||
* @param {number | bigint} varDeBruijn ```number | bigint```; debruijn level (at the term level) of the variable to search for | ||
* @param {UPLCTerm} term ```UPLCTerm``` to search in | ||
* @returns {boolean} ```true``` if the variable has 2 or more references; ```false``` otherwise | ||
*/ | ||
export declare function hasMultipleRefsInTerm(varDeBruijn: number | bigint, t: Readonly<UPLCTerm>): boolean; | ||
/** | ||
* | ||
* @param {number | bigint} varDeBruijn ```number | bigint```; debruijn level (at the term level) of the variable to search for | ||
* @param {UPLCTerm} term ```UPLCTerm``` to search in | ||
* @returns {number} number of references to the variable | ||
*/ | ||
export declare function getUPLCVarRefsInTerm(term: UPLCTerm, varDeBruijn?: number | bigint): number; | ||
export * from "./UPLCTerm.js"; | ||
export * from "./parseUPLCText.js"; |
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getUPLCVarRefsInTerm = exports.hasMultipleRefsInTerm = exports.hasAnyRefsInTerm = exports.prettyUPLC = exports.showUPLC = exports.showConstType = exports.showUPLCConstValue = exports.isClosedTerm = exports.isPureUPLCTerm = exports.isUPLCTerm = void 0; | ||
var UPLCVar_1 = require("../UPLCTerms/UPLCVar/index.js"); | ||
var Delay_1 = require("../UPLCTerms/Delay.js"); | ||
var Lambda_1 = require("../UPLCTerms/Lambda.js"); | ||
var Application_1 = require("../UPLCTerms/Application.js"); | ||
var UPLCConst_1 = require("../UPLCTerms/UPLCConst/UPLCConst.js"); | ||
var Force_1 = require("../UPLCTerms/Force.js"); | ||
var ErrorUPLC_1 = require("../UPLCTerms/ErrorUPLC.js"); | ||
var Builtin_1 = require("../UPLCTerms/Builtin/Builtin.js"); | ||
var ConstType_1 = require("../UPLCTerms/UPLCConst/ConstType/index.js"); | ||
var UPLCBuiltinTag_1 = require("../UPLCTerms/Builtin/UPLCBuiltinTag.js"); | ||
var ConstValue_1 = require("../UPLCTerms/UPLCConst/ConstValue/index.js"); | ||
var bytestring_1 = require("@harmoniclabs/bytestring"); | ||
var pair_1 = require("@harmoniclabs/pair"); | ||
var plutus_data_1 = require("@harmoniclabs/plutus-data"); | ||
var assert_1 = require("../utils/assert.js"); | ||
/** | ||
* **_O(1)_** | ||
* @param {UPLCTerm} t ```UPLCTerm``` to check | ||
* @returns {boolean} ```true``` if the argument is instance of any of the ```UPLCTerm``` constructors, ```false``` otherwise | ||
*/ | ||
function isUPLCTerm(t) { | ||
var proto = Object.getPrototypeOf(t); | ||
// only strict instances | ||
return (proto === UPLCVar_1.UPLCVar.prototype || | ||
proto === Delay_1.Delay.prototype || | ||
proto === Lambda_1.Lambda.prototype || | ||
proto === Application_1.Application.prototype || | ||
proto === UPLCConst_1.UPLCConst.prototype || | ||
proto === Force_1.Force.prototype || | ||
proto === ErrorUPLC_1.ErrorUPLC.prototype || | ||
proto === Builtin_1.Builtin.prototype); | ||
} | ||
exports.isUPLCTerm = isUPLCTerm; | ||
/** | ||
* **_O(n)_** | ||
* @param {UPLCTerm} t ```UPLCTerm``` to check | ||
* @returns {boolean} ```true``` if the AST contains only plutus-core terms, ```false``` otherwise | ||
*/ | ||
function isPureUPLCTerm(t) { | ||
if (!isUPLCTerm(t)) | ||
return false; | ||
if (t instanceof UPLCVar_1.UPLCVar) | ||
return true; | ||
if (t instanceof Delay_1.Delay) | ||
return isPureUPLCTerm(t.delayedTerm); | ||
if (t instanceof Lambda_1.Lambda) | ||
return isPureUPLCTerm(t.body); | ||
if (t instanceof Application_1.Application) | ||
return (isPureUPLCTerm(t.argTerm) && isPureUPLCTerm(t.funcTerm)); | ||
if (t instanceof UPLCConst_1.UPLCConst) | ||
return true; | ||
if (t instanceof Force_1.Force) | ||
return isPureUPLCTerm(t.termToForce); | ||
if (t instanceof ErrorUPLC_1.ErrorUPLC) | ||
return true; | ||
if (t instanceof Builtin_1.Builtin) | ||
return true; | ||
return false; | ||
} | ||
exports.isPureUPLCTerm = isPureUPLCTerm; | ||
function isClosedTerm(term) { | ||
function _isClosedTerm(maxDeBruijn, t) { | ||
(0, assert_1.assert)(isUPLCTerm(t), "'isClosedTerm' functions only works on **raw** UPLCTerms"); | ||
if (t instanceof UPLCVar_1.UPLCVar) | ||
// deBruijn variables are 0 indexed (as arrays) | ||
return maxDeBruijn > t.deBruijn; | ||
else if (t instanceof Delay_1.Delay) | ||
return _isClosedTerm(maxDeBruijn, t.delayedTerm); | ||
else if (t instanceof Lambda_1.Lambda) | ||
// increment max debruijn | ||
return _isClosedTerm(maxDeBruijn + BigInt(1), t.body); | ||
else if (t instanceof Application_1.Application) | ||
return _isClosedTerm(maxDeBruijn, t.funcTerm) && _isClosedTerm(maxDeBruijn, t.argTerm); | ||
else if (t instanceof UPLCConst_1.UPLCConst) | ||
// `UPLCConst` has no variables in it, ence always closed | ||
return true; | ||
else if (t instanceof Force_1.Force) | ||
return _isClosedTerm(maxDeBruijn, t.termToForce); | ||
else if (t instanceof ErrorUPLC_1.ErrorUPLC) | ||
// `ErrorUPLC` has no variables in it, ence always closed | ||
return true; | ||
else if (t instanceof Builtin_1.Builtin) | ||
// builtin per-se is just the function (ence a valid value), | ||
// arguments are passed using the `Apply` Term | ||
// so it is the `t instanceof Apply` case job | ||
// to be sure the arguments are closed | ||
return true; | ||
else | ||
throw new Error("unexpected execution flow in 'isClodeTerm'; all possibilieties should have already been handled; input term is: " + t.toString()); | ||
} | ||
return _isClosedTerm(BigInt(0), term); | ||
} | ||
exports.isClosedTerm = isClosedTerm; | ||
function showUPLCConstValue(v) { | ||
if (v === undefined) | ||
return "()"; | ||
if ((0, ConstValue_1.isConstValueInt)(v)) | ||
return v.toString(); | ||
if (typeof v === "string") | ||
return "\"".concat(v, "\""); | ||
if (typeof v === "boolean") | ||
return v ? "True" : "False"; | ||
if (v instanceof bytestring_1.ByteString) | ||
return "#" + v.toString(); | ||
if ((0, plutus_data_1.isData)(v)) | ||
return "#" + (0, plutus_data_1.dataToCbor)(v).toString(); | ||
if (Array.isArray(v)) | ||
return "[" + v.map(showUPLCConstValue).join(',') + "]"; | ||
if (v instanceof pair_1.Pair) | ||
return "(".concat(showUPLCConstValue(v.fst), ",").concat(showUPLCConstValue(v.snd), ")"); | ||
throw new Error("'showUPLCConstValue' did not matched any possible constant value"); | ||
} | ||
exports.showUPLCConstValue = showUPLCConstValue; | ||
function showConstType(t) { | ||
if (t[0] === ConstType_1.ConstTyTag.list) { | ||
return "list( ".concat(showConstType(ConstType_1.constListTypeUtils.getTypeArgument(t)), " )"); | ||
} | ||
if (t[0] === ConstType_1.ConstTyTag.pair) { | ||
return "pair( ".concat(showConstType(ConstType_1.constPairTypeUtils.getFirstTypeArgument(t)), ", ").concat(showConstType(ConstType_1.constPairTypeUtils.getSecondTypeArgument(t)), " )"); | ||
} | ||
return (0, ConstType_1.constTypeToStirng)(t); | ||
} | ||
exports.showConstType = showConstType; | ||
var vars = "abcdefghilmopqrstuvzwxyjkABCDEFGHILJMNOPQRSTUVZWXYJK".split(''); | ||
function getVarNameForDbn(dbn) { | ||
if (dbn < 0) | ||
return "(".concat(dbn, ")"); | ||
if (dbn < vars.length) | ||
return vars[dbn]; | ||
return vars[Math.floor(dbn / vars.length)] + getVarNameForDbn(dbn - vars.length); | ||
} | ||
function showUPLC(term) { | ||
function loop(t, dbn) { | ||
if (t instanceof UPLCVar_1.UPLCVar) { | ||
return getVarNameForDbn(dbn - 1 - Number(t.deBruijn)); | ||
} | ||
if (t instanceof Delay_1.Delay) | ||
return "(delay ".concat(loop(t.delayedTerm, dbn), ")"); | ||
if (t instanceof Lambda_1.Lambda) { | ||
return "(lam ".concat(getVarNameForDbn(dbn), " ").concat(loop(t.body, dbn + 1), ")"); | ||
} | ||
if (t instanceof Application_1.Application) | ||
return "[".concat(loop(t.funcTerm, dbn), " ").concat(loop(t.argTerm, dbn), "]"); | ||
if (t instanceof UPLCConst_1.UPLCConst) | ||
return "(con ".concat(showConstType(t.type), " ").concat(showUPLCConstValue(t.value), ")"); | ||
if (t instanceof Force_1.Force) | ||
return "(force ".concat(loop(t.termToForce, dbn), ")"); | ||
if (t instanceof ErrorUPLC_1.ErrorUPLC) | ||
return "(error)"; | ||
if (t instanceof Builtin_1.Builtin) { | ||
var nForces = (0, UPLCBuiltinTag_1.getNRequiredForces)(t.tag); | ||
return "(force ".repeat(nForces) + "(builtin ".concat((0, UPLCBuiltinTag_1.builtinTagToString)(t.tag), ")") + ')'.repeat(nForces); | ||
} | ||
return ""; | ||
} | ||
return loop(term, 0); | ||
} | ||
exports.showUPLC = showUPLC; | ||
function prettyUPLC(term, _indent) { | ||
if (_indent === void 0) { _indent = 2; } | ||
if (!Number.isSafeInteger(_indent) || _indent < 1) | ||
return showUPLC(term); | ||
var indentStr = " ".repeat(_indent); | ||
function getVarNameForDbn(dbn) { | ||
if (dbn < 0) | ||
return "(".concat(dbn, ")"); | ||
if (dbn < vars.length) | ||
return vars[dbn]; | ||
return vars[Math.floor(dbn / vars.length)] + getVarNameForDbn(dbn - vars.length); | ||
} | ||
function loop(t, dbn, depth) { | ||
var indent = "\n".concat(indentStr.repeat(depth)); | ||
if (t instanceof UPLCVar_1.UPLCVar) { | ||
return indent + getVarNameForDbn(dbn - 1 - Number(t.deBruijn)); | ||
} | ||
if (t instanceof Delay_1.Delay) | ||
return "".concat(indent, "(delay ").concat(loop(t.delayedTerm, dbn, depth + 1)).concat(indent, ")"); | ||
if (t instanceof Lambda_1.Lambda) { | ||
return "".concat(indent, "(lam ").concat(getVarNameForDbn(dbn), " ").concat(loop(t.body, dbn + 1, depth + 1)).concat(indent, ")"); | ||
} | ||
if (t instanceof Application_1.Application) | ||
return "".concat(indent, "[").concat(loop(t.funcTerm, dbn, depth + 1), " ").concat(loop(t.argTerm, dbn, depth + 1)).concat(indent, "]"); | ||
if (t instanceof UPLCConst_1.UPLCConst) | ||
return "".concat(indent, "(con ").concat(showConstType(t.type), " ").concat(showUPLCConstValue(t.value), ")"); | ||
if (t instanceof Force_1.Force) | ||
return "".concat(indent, "(force ").concat(loop(t.termToForce, dbn, depth + 1)).concat(indent, ")"); | ||
if (t instanceof ErrorUPLC_1.ErrorUPLC) | ||
return "(error)"; | ||
if (t instanceof Builtin_1.Builtin) { | ||
var nForces = (0, UPLCBuiltinTag_1.getNRequiredForces)(t.tag); | ||
return indent + "(force ".repeat(nForces) + "(builtin ".concat((0, UPLCBuiltinTag_1.builtinTagToString)(t.tag), ")") + ')'.repeat(nForces); | ||
} | ||
return ""; | ||
} | ||
return loop(term, 0, 0); | ||
} | ||
exports.prettyUPLC = prettyUPLC; | ||
/** | ||
* | ||
* @param {number | bigint} varDeBruijn ```number | bigint```; debruijn level (at the term level) of the variable to search for | ||
* @param {UPLCTerm} t ```UPLCTerm``` to search in | ||
* @returns {boolean} ```true``` if the variable has **at least** 1 or more references; ```false``` otherwise | ||
*/ | ||
function hasAnyRefsInTerm(varDeBruijn, t) { | ||
(0, assert_1.assert)(isUPLCTerm(t), "'getUPLCVarRefsInTerm' expects an UPLCTerms"); | ||
var dbn = BigInt(varDeBruijn); | ||
if (t instanceof UPLCVar_1.UPLCVar) | ||
return t.deBruijn === dbn; | ||
if (t instanceof Delay_1.Delay) | ||
return hasAnyRefsInTerm(dbn, t.delayedTerm); | ||
if (t instanceof Lambda_1.Lambda) | ||
return hasAnyRefsInTerm(dbn + BigInt(1), t.body); | ||
if (t instanceof Application_1.Application) | ||
return hasAnyRefsInTerm(dbn, t.funcTerm) || hasAnyRefsInTerm(dbn, t.argTerm); | ||
if (t instanceof UPLCConst_1.UPLCConst) | ||
return false; | ||
if (t instanceof Force_1.Force) | ||
return hasAnyRefsInTerm(dbn, t.termToForce); | ||
if (t instanceof ErrorUPLC_1.ErrorUPLC) | ||
return false; | ||
if (t instanceof Builtin_1.Builtin) | ||
return false; | ||
throw new Error("'hasAnyRefsInTerm' did not matched any possible 'UPLCTerm' constructor"); | ||
} | ||
exports.hasAnyRefsInTerm = hasAnyRefsInTerm; | ||
/** | ||
* | ||
* @param {number | bigint} varDeBruijn ```number | bigint```; debruijn level (at the term level) of the variable to search for | ||
* @param {UPLCTerm} term ```UPLCTerm``` to search in | ||
* @returns {boolean} ```true``` if the variable has 2 or more references; ```false``` otherwise | ||
*/ | ||
function hasMultipleRefsInTerm(varDeBruijn, t) { | ||
(0, assert_1.assert)(isUPLCTerm(t), "'getUPLCVarRefsInTerm' expects an UPLCTerms"); | ||
var dbn = BigInt(varDeBruijn); | ||
if (t instanceof UPLCVar_1.UPLCVar) | ||
return false; // single ref; case of multple refs is handled in 'Application' using 'hasAnyRefsInTerm' | ||
if (t instanceof Delay_1.Delay) | ||
return hasMultipleRefsInTerm(dbn, t.delayedTerm); | ||
if (t instanceof Lambda_1.Lambda) | ||
return hasMultipleRefsInTerm(dbn + BigInt(1), t.body); | ||
if (t instanceof Application_1.Application) | ||
return ((hasAnyRefsInTerm(dbn, t.funcTerm) && hasAnyRefsInTerm(dbn, t.argTerm)) || // referenced at least once in both terms | ||
hasMultipleRefsInTerm(dbn, t.funcTerm) || // referenced multiple times in func | ||
hasMultipleRefsInTerm(dbn, t.argTerm) // referenced multiple times in arg | ||
); | ||
if (t instanceof UPLCConst_1.UPLCConst) | ||
return false; | ||
if (t instanceof Force_1.Force) | ||
return hasMultipleRefsInTerm(dbn, t.termToForce); | ||
if (t instanceof ErrorUPLC_1.ErrorUPLC) | ||
return false; | ||
if (t instanceof Builtin_1.Builtin) | ||
return false; | ||
throw new Error("getUPLCVarRefsInTerm did not matched any possible 'UPLCTerm' constructor"); | ||
} | ||
exports.hasMultipleRefsInTerm = hasMultipleRefsInTerm; | ||
/** | ||
* | ||
* @param {number | bigint} varDeBruijn ```number | bigint```; debruijn level (at the term level) of the variable to search for | ||
* @param {UPLCTerm} term ```UPLCTerm``` to search in | ||
* @returns {number} number of references to the variable | ||
*/ | ||
function getUPLCVarRefsInTerm(term, varDeBruijn) { | ||
if (varDeBruijn === void 0) { varDeBruijn = 0; } | ||
function _getUPLCVarRefsInTerm(dbn, t, countedUntilNow) { | ||
(0, assert_1.assert)(isUPLCTerm(t), "'getUPLCVarRefsInTerm' expects an UPLCTerms"); | ||
if (t instanceof UPLCVar_1.UPLCVar) | ||
return countedUntilNow + (t.deBruijn === dbn ? 1 : 0); | ||
if (t instanceof Delay_1.Delay) | ||
return _getUPLCVarRefsInTerm(dbn, t.delayedTerm, countedUntilNow); | ||
if (t instanceof Lambda_1.Lambda) | ||
return _getUPLCVarRefsInTerm(dbn + BigInt(1), t.body, countedUntilNow); | ||
if (t instanceof Application_1.Application) | ||
return _getUPLCVarRefsInTerm(dbn, t.funcTerm, countedUntilNow) + _getUPLCVarRefsInTerm(dbn, t.argTerm, countedUntilNow); | ||
if (t instanceof UPLCConst_1.UPLCConst) | ||
return countedUntilNow; | ||
if (t instanceof Force_1.Force) | ||
return _getUPLCVarRefsInTerm(dbn, t.termToForce, countedUntilNow); | ||
if (t instanceof ErrorUPLC_1.ErrorUPLC) | ||
return countedUntilNow; | ||
if (t instanceof Builtin_1.Builtin) | ||
return countedUntilNow; | ||
throw new Error("getUPLCVarRefsInTerm did not matched any possible 'UPLCTerm' constructor"); | ||
} | ||
return _getUPLCVarRefsInTerm(BigInt(varDeBruijn), term, 0); | ||
} | ||
exports.getUPLCVarRefsInTerm = getUPLCVarRefsInTerm; | ||
__exportStar(require("./UPLCTerm.js"), exports); | ||
__exportStar(require("./parseUPLCText.js"), exports); |
@@ -1,2 +0,2 @@ | ||
import { UPLCTerm } from "../UPLCTerm/index.js"; | ||
import { UPLCTerm } from "../UPLCTerm/UPLCTerm.js"; | ||
import { UPLCVar } from "./UPLCVar/index.js"; | ||
@@ -3,0 +3,0 @@ import { Lambda } from "./Lambda.js"; |
@@ -66,1 +66,2 @@ export type UPLCBuiltinTagNumber = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53; | ||
export declare function builtinTagToString(tag: UPLCBuiltinTag): string; | ||
export declare function builtinTagFromString(tag: string): UPLCBuiltinTag; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.builtinTagToString = exports.isV2Supported = exports.isV1Supported = exports.getNRequiredForces = exports.isUPLCBuiltinTag = exports.UPLCBuiltinTag = void 0; | ||
exports.builtinTagFromString = exports.builtinTagToString = exports.isV2Supported = exports.isV1Supported = exports.getNRequiredForces = exports.isUPLCBuiltinTag = exports.UPLCBuiltinTag = void 0; | ||
var assert_1 = require("../../utils/assert.js"); | ||
@@ -179,1 +179,63 @@ /** | ||
exports.builtinTagToString = builtinTagToString; | ||
function builtinTagFromString(tag) { | ||
switch (tag) { | ||
case "addInteger": return UPLCBuiltinTag.addInteger; | ||
case "subtractInteger": return UPLCBuiltinTag.subtractInteger; | ||
case "multiplyInteger": return UPLCBuiltinTag.multiplyInteger; | ||
case "divideInteger": return UPLCBuiltinTag.divideInteger; | ||
case "quotientInteger": return UPLCBuiltinTag.quotientInteger; | ||
case "remainderInteger": return UPLCBuiltinTag.remainderInteger; | ||
case "modInteger": return UPLCBuiltinTag.modInteger; | ||
case "equalsInteger": return UPLCBuiltinTag.equalsInteger; | ||
case "lessThanInteger": return UPLCBuiltinTag.lessThanInteger; | ||
case "lessThanEqualInteger": return UPLCBuiltinTag.lessThanEqualInteger; | ||
case "appendByteString": return UPLCBuiltinTag.appendByteString; | ||
case "consByteString": return UPLCBuiltinTag.consByteString; | ||
case "sliceByteString": return UPLCBuiltinTag.sliceByteString; | ||
case "lengthOfByteString": return UPLCBuiltinTag.lengthOfByteString; | ||
case "indexByteString": return UPLCBuiltinTag.indexByteString; | ||
case "equalsByteString": return UPLCBuiltinTag.equalsByteString; | ||
case "lessThanByteString": return UPLCBuiltinTag.lessThanByteString; | ||
case "lessThanEqualsByteString": return UPLCBuiltinTag.lessThanEqualsByteString; | ||
case "sha2_256": return UPLCBuiltinTag.sha2_256; | ||
case "sha3_256": return UPLCBuiltinTag.sha3_256; | ||
case "blake2b_256": return UPLCBuiltinTag.blake2b_256; | ||
case "verifyEd25519Signature": return UPLCBuiltinTag.verifyEd25519Signature; | ||
case "appendString": return UPLCBuiltinTag.appendString; | ||
case "equalsString": return UPLCBuiltinTag.equalsString; | ||
case "encodeUtf8": return UPLCBuiltinTag.encodeUtf8; | ||
case "decodeUtf8": return UPLCBuiltinTag.decodeUtf8; | ||
case "ifThenElse": return UPLCBuiltinTag.ifThenElse; | ||
case "chooseUnit": return UPLCBuiltinTag.chooseUnit; | ||
case "trace": return UPLCBuiltinTag.trace; | ||
case "fstPair": return UPLCBuiltinTag.fstPair; | ||
case "sndPair": return UPLCBuiltinTag.sndPair; | ||
case "chooseList": return UPLCBuiltinTag.chooseList; | ||
case "mkCons": return UPLCBuiltinTag.mkCons; | ||
case "headList": return UPLCBuiltinTag.headList; | ||
case "tailList": return UPLCBuiltinTag.tailList; | ||
case "nullList": return UPLCBuiltinTag.nullList; | ||
case "chooseData": return UPLCBuiltinTag.chooseData; | ||
case "constrData": return UPLCBuiltinTag.constrData; | ||
case "mapData": return UPLCBuiltinTag.mapData; | ||
case "listData": return UPLCBuiltinTag.listData; | ||
case "iData": return UPLCBuiltinTag.iData; | ||
case "bData": return UPLCBuiltinTag.bData; | ||
case "unConstrData": return UPLCBuiltinTag.unConstrData; | ||
case "unMapData": return UPLCBuiltinTag.unMapData; | ||
case "unListData": return UPLCBuiltinTag.unListData; | ||
case "unIData": return UPLCBuiltinTag.unIData; | ||
case "unBData": return UPLCBuiltinTag.unBData; | ||
case "equalsData": return UPLCBuiltinTag.equalsData; | ||
case "mkPairData": return UPLCBuiltinTag.mkPairData; | ||
case "mkNilData": return UPLCBuiltinTag.mkNilData; | ||
case "mkNilPairData": return UPLCBuiltinTag.mkNilPairData; | ||
case "serialiseData": return UPLCBuiltinTag.serialiseData; | ||
case "verifyEcdsaSecp256k1Signature": return UPLCBuiltinTag.verifyEcdsaSecp256k1Signature; | ||
case "verifySchnorrSecp256k1Signature": return UPLCBuiltinTag.verifySchnorrSecp256k1Signature; | ||
default: | ||
// tag; // check that is of type 'never' | ||
throw new Error("unknow builtin: " + tag); | ||
} | ||
} | ||
exports.builtinTagFromString = builtinTagFromString; |
import { BitStream } from "@harmoniclabs/bitstream"; | ||
import { UPLCTerm } from "../UPLCTerm/index.js"; | ||
import { UPLCTerm } from "../UPLCTerm/UPLCTerm.js"; | ||
export declare class Delay { | ||
@@ -4,0 +4,0 @@ static get UPLCTag(): BitStream; |
@@ -1,2 +0,2 @@ | ||
import { UPLCTerm } from "../UPLCTerm/index.js"; | ||
import { UPLCTerm } from "../UPLCTerm/UPLCTerm.js"; | ||
import { Delay } from "./Delay.js"; | ||
@@ -3,0 +3,0 @@ import { UPLCVar } from "./UPLCVar/index.js"; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isUPLCForce = exports.Force = exports.isForceableTerm = void 0; | ||
var UPLCTerm_1 = require("../UPLCTerm/index.js"); | ||
var UPLCTerm_1 = require("../UPLCTerm/UPLCTerm.js"); | ||
var Delay_1 = require("./Delay.js"); | ||
@@ -6,0 +6,0 @@ var UPLCVar_1 = require("./UPLCVar/index.js"); |
import { BitStream } from "@harmoniclabs/bitstream"; | ||
import { UPLCTerm } from "../UPLCTerm/index.js"; | ||
import { UPLCTerm } from "../UPLCTerm/UPLCTerm.js"; | ||
export declare class Lambda { | ||
@@ -4,0 +4,0 @@ static get UPLCTag(): BitStream; |
{ | ||
"name": "@harmoniclabs/uplc", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "./dist/index.js", |
@@ -13,2 +13,4 @@ # @harmoniclabs/uplc | ||
### parse serialized UPLC | ||
parse and print uplc form flat hex ([`@harmoniclabs/uint8array-utils`](https://github.com/HarmonicLabs/uint8array-utils) works in every js runtime) | ||
@@ -54,5 +56,38 @@ ```ts | ||
compile UPLC | ||
### parse textual UPLC | ||
```ts | ||
import { parseUPLCText, prettyUPLC } from "@harmoniclabs/uplc"; | ||
const uplc_source = ` | ||
[ | ||
(lam a | ||
[ | ||
[ | ||
(builtin addInteger) | ||
(con integer 2) | ||
] | ||
[ | ||
[ | ||
(builtin multiplyInteger) | ||
(con integer 10) | ||
] | ||
a | ||
] | ||
] | ||
) | ||
(con integer 4) | ||
]`; | ||
const uplc = parseUPLCText( uplc_source ); | ||
// expected output: true | ||
console.log( | ||
prettyUPLC( uplc, 4 ) === uplc_source | ||
); | ||
``` | ||
### compile UPLC to flat bytes | ||
```ts | ||
import { toHex } from "@harmoniclabs/uint8array-utils"; | ||
@@ -59,0 +94,0 @@ import { Application, Builtin, UPLCConst, compileUPLC, UPLCProgram } from "@harmoniclabs/uplc"; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
195944
65
4178
110