@taquito/michel-codec
Version:
Michelson parser/validator/formatter
1,347 lines (1,339 loc) • 223 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@taquito/core')) :
typeof define === 'function' && define.amd ? define(['exports', '@taquito/core'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.taquitoMichelCodec = {}, global.core));
})(this, (function (exports, core) { 'use strict';
// Michelson abstract syntax tree types https://tezos.gitlab.io/whitedoc/michelson.html#concrete-syntax
const sourceReference = Symbol('source_reference');
/**
* @category Error
* @description Error that indicates a failure when performing the scan step when parsing Michelson
*/
class ScanError extends core.TaquitoError {
constructor(src, idx, message) {
super();
this.src = src;
this.idx = idx;
this.message = message;
this.name = 'ScanError';
}
}
var Literal;
(function (Literal) {
Literal[Literal["Comment"] = 0] = "Comment";
Literal[Literal["Number"] = 1] = "Number";
Literal[Literal["String"] = 2] = "String";
Literal[Literal["Bytes"] = 3] = "Bytes";
Literal[Literal["Ident"] = 4] = "Ident";
})(Literal || (Literal = {}));
const isSpace = new RegExp('\\s');
const isIdentStart = new RegExp('[:@%_A-Za-z]');
const isIdent = new RegExp('[@%_\\.A-Za-z0-9]');
const isDigit = new RegExp('[0-9]');
const isHex = new RegExp('[0-9a-fA-F]');
function* scan(src, scanComments = false) {
let i = 0;
while (i < src.length) {
// Skip space
while (i < src.length && isSpace.test(src[i])) {
i++;
}
if (i === src.length) {
return;
}
const s = src[i];
const start = i;
if (isIdentStart.test(s)) {
// Identifier
i++;
while (i < src.length && isIdent.test(src[i])) {
i++;
}
yield { t: Literal.Ident, v: src.slice(start, i), first: start, last: i };
}
else if (src.length - i > 1 && src.substring(i, i + 2) === '0x') {
// Bytes
i += 2;
while (i < src.length && isHex.test(src[i])) {
i++;
}
if (((i - start) & 1) !== 0) {
throw new ScanError(src, i, 'Bytes literal length is expected to be power of two');
}
yield { t: Literal.Bytes, v: src.slice(start, i), first: start, last: i };
}
else if (isDigit.test(s) || s === '-') {
// Number
if (s === '-') {
i++;
}
const ii = i;
while (i < src.length && isDigit.test(src[i])) {
i++;
}
if (ii === i) {
throw new ScanError(src, i, 'Number literal is too short');
}
yield { t: Literal.Number, v: src.slice(start, i), first: start, last: i };
}
else if (s === '"') {
// String
i++;
let esc = false;
for (; i < src.length && (esc || src[i] !== '"'); i++) {
if (!esc && src[i] === '\\') {
esc = true;
}
else {
esc = false;
}
}
if (i === src.length) {
throw new ScanError(src, i, 'Unterminated string literal');
}
i++;
yield { t: Literal.String, v: src.slice(start, i), first: start, last: i };
}
else if (s === '#') {
// Comment
i++;
while (i < src.length && src[i] !== '\n') {
i++;
}
if (scanComments) {
yield { t: Literal.Comment, v: src.slice(start, i), first: start, last: i };
}
}
else if (src.length - i > 1 && src.substring(i, i + 2) === '/*') {
// C style comment
i += 2;
while (i < src.length && !(src.length - i > 1 && src.substring(i, i + 2) === '*/')) {
i++;
}
if (i === src.length) {
throw new ScanError(src, i, 'Unterminated C style comment');
}
i += 2;
if (scanComments) {
yield { t: Literal.Comment, v: src.slice(start, i), first: start, last: i };
}
}
else if (s === '(' || s === ')' || s === '{' || s === '}' || s === ';') {
i++;
yield { t: s, v: s, first: start, last: i };
}
else {
throw new ScanError(src, i, `Invalid character at offset ${i}: \`${s}'`);
}
}
}
// Michelson types
const refContract = Symbol('ref_contract');
exports.Protocol = void 0;
(function (Protocol) {
Protocol["Ps9mPmXa"] = "Ps9mPmXaRzmzk35gbAYNCAw6UXdE2qoABTHbN2oEEc1qM7CwT9P";
Protocol["PtCJ7pwo"] = "PtCJ7pwoxe8JasnHY8YonnLYjcVHmhiARPJvqcC6VfHT5s8k8sY";
Protocol["PsYLVpVv"] = "PsYLVpVvgbLhAhoqAkMFUo6gudkJ9weNXhUYCiLDzcUpFpkk8Wt";
Protocol["PsddFKi3"] = "PsddFKi32cMJ2qPjf43Qv5GDWLDPZb3T3bF6fLKiF5HtvHNU7aP";
Protocol["Pt24m4xi"] = "Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd";
Protocol["PsBABY5H"] = "PsBABY5HQTSkA4297zNHfsZNKtxULfL18y95qb3m53QJiXGmrbU";
Protocol["PsBabyM1"] = "PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS";
Protocol["PsCARTHA"] = "PsCARTHAGazKbHtnKfLzQg3kms52kSRpgnDY982a9oYsSXRLQEb";
Protocol["PsDELPH1"] = "PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo";
Protocol["PtEdoTez"] = "PtEdoTezd3RHSC31mpxxo1npxFjoWWcFgQtxapi51Z8TLu6v6Uq";
Protocol["PtEdo2Zk"] = "PtEdo2ZkT9oKpimTah6x2embF25oss54njMuPzkJTEi5RqfdZFA";
Protocol["PsFLorena"] = "PsFLorenaUUuikDWvMDr6fGBRG8kt3e3D3fHoXK1j1BFRxeSH4i";
Protocol["PtGRANADs"] = "PtGRANADsDU8R9daYKAgWnQYAJ64omN1o3KMGVCykShA97vQbvV";
Protocol["PtHangzH"] = "PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r";
Protocol["PtHangz2"] = "PtHangz2aRngywmSRGGvrcTyMbbdpWdpFKuS4uMWxg2RaH9i1qx";
Protocol["PsiThaCa"] = "PsiThaCaT47Zboaw71QWScM8sXeMM7bbQFncK9FLqYc6EKdpjVP";
Protocol["Psithaca2"] = "Psithaca2MLRFYargivpo7YvUr7wUDqyxrdhC5CQq78mRvimz6A";
Protocol["PtJakarta"] = "PtJakartaiDz69SfDDLXJSiuZqTSeSKRDbKVZC8MNzJnvRjvnGw";
Protocol["PtJakart2"] = "PtJakart2xVj7pYXJBXrqHgd82rdkLey5ZeeGwDgPp9rhQUbSqY";
Protocol["PtKathman"] = "PtKathmankSpLLDALzWw7CGD2j2MtyveTwboEYokqUCP4a1LxMg";
Protocol["PtLimaPtL"] = "PtLimaPtLMwfNinJi9rCfDPWea8dFgTZ1MeJ9f1m2SRic6ayiwW";
Protocol["PtMumbaii"] = "PtMumbaiiFFEGbew1rRjzSPyzRbA51Tm3RVZL5suHPxSZYDhCEc";
Protocol["PtMumbai2"] = "PtMumbai2TmsJHNGRkD8v8YDbtao7BLUC3wjASn1inAKLFCjaH1";
Protocol["PtNairobi"] = "PtNairobiyssHuh87hEhfVBGCVrK3WnS8Z2FT4ymB5tAa4r1nQf";
Protocol["ProxfordY"] = "ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH";
Protocol["PtParisBx"] = "PtParisBxoLz5gzMmn3d9WBQNoPSZakgnkMC2VNuQ3KXfUtUQeZ";
Protocol["PsParisCZ"] = "PsParisCZo7KAh1Z1smVd9ZMZ1HHn5gkzbM94V3PLCpknFWhUAi";
Protocol["PsQuebecn"] = "PsQuebecnLByd3JwTiGadoG4nGWi3HYiLXUjkibeFV8dCFeVMUg";
Protocol["PsRiotuma"] = "PsRiotumaAMotcRoDWW1bysEhQy2n1M5fy8JgRp8jjRfHGmfeA7";
Protocol["ProtoALpha"] = "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK";
})(exports.Protocol || (exports.Protocol = {}));
const DefaultProtocol = exports.Protocol.PsRiotuma;
const protoLevel = {
Ps9mPmXaRzmzk35gbAYNCAw6UXdE2qoABTHbN2oEEc1qM7CwT9P: 0,
PtCJ7pwoxe8JasnHY8YonnLYjcVHmhiARPJvqcC6VfHT5s8k8sY: 1,
PsYLVpVvgbLhAhoqAkMFUo6gudkJ9weNXhUYCiLDzcUpFpkk8Wt: 2,
PsddFKi32cMJ2qPjf43Qv5GDWLDPZb3T3bF6fLKiF5HtvHNU7aP: 3,
Pt24m4xiPbLDhVgVfABUjirbmda3yohdN82Sp9FeuAXJ4eV9otd: 4,
PsBABY5HQTSkA4297zNHfsZNKtxULfL18y95qb3m53QJiXGmrbU: 5,
PsBabyM1eUXZseaJdmXFApDSBqj8YBfwELoxZHHW77EMcAbbwAS: 5,
PsCARTHAGazKbHtnKfLzQg3kms52kSRpgnDY982a9oYsSXRLQEb: 6,
PsDELPH1Kxsxt8f9eWbxQeRxkjfbxoqM52jvs5Y5fBxWWh4ifpo: 7,
PtEdoTezd3RHSC31mpxxo1npxFjoWWcFgQtxapi51Z8TLu6v6Uq: 8,
PtEdo2ZkT9oKpimTah6x2embF25oss54njMuPzkJTEi5RqfdZFA: 8,
PsFLorenaUUuikDWvMDr6fGBRG8kt3e3D3fHoXK1j1BFRxeSH4i: 9,
PtGRANADsDU8R9daYKAgWnQYAJ64omN1o3KMGVCykShA97vQbvV: 10,
PtHangzHogokSuiMHemCuowEavgYTP8J5qQ9fQS793MHYFpCY3r: 11,
PtHangz2aRngywmSRGGvrcTyMbbdpWdpFKuS4uMWxg2RaH9i1qx: 11,
PsiThaCaT47Zboaw71QWScM8sXeMM7bbQFncK9FLqYc6EKdpjVP: 12,
Psithaca2MLRFYargivpo7YvUr7wUDqyxrdhC5CQq78mRvimz6A: 12,
PtJakartaiDz69SfDDLXJSiuZqTSeSKRDbKVZC8MNzJnvRjvnGw: 13,
PtJakart2xVj7pYXJBXrqHgd82rdkLey5ZeeGwDgPp9rhQUbSqY: 13,
PtKathmankSpLLDALzWw7CGD2j2MtyveTwboEYokqUCP4a1LxMg: 14,
PtLimaPtLMwfNinJi9rCfDPWea8dFgTZ1MeJ9f1m2SRic6ayiwW: 15,
PtMumbaiiFFEGbew1rRjzSPyzRbA51Tm3RVZL5suHPxSZYDhCEc: 16,
PtMumbai2TmsJHNGRkD8v8YDbtao7BLUC3wjASn1inAKLFCjaH1: 16,
PtNairobiyssHuh87hEhfVBGCVrK3WnS8Z2FT4ymB5tAa4r1nQf: 17,
ProxfordYmVfjWnRcgjWH36fW6PArwqykTFzotUxRs6gmTcZDuH: 19,
PtParisBxoLz5gzMmn3d9WBQNoPSZakgnkMC2VNuQ3KXfUtUQeZ: 20,
PsParisCZo7KAh1Z1smVd9ZMZ1HHn5gkzbM94V3PLCpknFWhUAi: 20,
PsQuebecnLByd3JwTiGadoG4nGWi3HYiLXUjkibeFV8dCFeVMUg: 21,
PsRiotumaAMotcRoDWW1bysEhQy2n1M5fy8JgRp8jjRfHGmfeA7: 22,
ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK: 23,
};
function ProtoGreaterOrEqual(a, b) {
return protoLevel[a] >= protoLevel[b];
}
function ProtoInferiorTo(a, b) {
return protoLevel[a] < protoLevel[b];
}
/**
* @category Error
* @description Error that indicates macros failed to be expanded
*/
class MacroError extends core.TaquitoError {
constructor(prim, message) {
super();
this.prim = prim;
this.message = message;
this.name = 'MacroError';
}
}
function assertArgs$1(ex, n) {
var _a, _b;
if ((n === 0 && ex.args === undefined) || ((_a = ex.args) === null || _a === void 0 ? void 0 : _a.length) === n) {
return true;
}
throw new MacroError(ex, `macro ${ex.prim} expects ${n} arguments, was given ${(_b = ex.args) === null || _b === void 0 ? void 0 : _b.length}`);
}
function assertNoAnnots(ex) {
if (ex.annots === undefined) {
return true;
}
throw new MacroError(ex, `unexpected annotation on macro ${ex.prim}: ${ex.annots}`);
}
function assertIntArg(ex, arg) {
if ('int' in arg) {
return true;
}
throw new MacroError(ex, `macro ${ex.prim} expects int argument`);
}
function parsePairUnpairExpr(p, expr, annotations, agg) {
let i = 0;
let ai = 0;
const ann = [null, null];
// Left expression
let lexpr;
if (i === expr.length) {
throw new MacroError(p, `unexpected end: ${p.prim}`);
}
let c = expr[i++];
switch (c) {
case 'P': {
const { r, n, an } = parsePairUnpairExpr(p, expr.slice(i), annotations.slice(ai), agg);
lexpr = r;
i += n;
ai += an;
break;
}
case 'A':
if (ai !== annotations.length) {
ann[0] = annotations[ai++];
}
break;
default:
throw new MacroError(p, `${p.prim}: unexpected character: ${c}`);
}
// Right expression
let rexpr;
if (i === expr.length) {
throw new MacroError(p, `unexpected end: ${p.prim}`);
}
c = expr[i++];
switch (c) {
case 'P': {
const { r, n, an } = parsePairUnpairExpr(p, expr.slice(i), annotations.slice(ai), agg);
rexpr = r.map(([v, a]) => [v + 1, a]);
i += n;
ai += an;
break;
}
case 'I':
if (ai !== annotations.length) {
ann[1] = annotations[ai++];
}
break;
default:
throw new MacroError(p, `${p.prim}: unexpected character: ${c}`);
}
return { r: agg(lexpr, rexpr, [0, ann]), n: i, an: ai };
}
function parseSetMapCadr(p, expr, vann, term) {
const c = expr[0];
switch (c) {
case 'A':
return expr.length > 1
? [
{ prim: 'DUP' },
{
prim: 'DIP',
args: [
[{ prim: 'CAR', annots: ['@%%'] }, parseSetMapCadr(p, expr.slice(1), [], term)],
],
},
{ prim: 'CDR', annots: ['@%%'] },
{ prim: 'SWAP' },
{ prim: 'PAIR', annots: ['%@', '%@', ...vann] },
]
: term.a;
case 'D':
return expr.length > 1
? [
{ prim: 'DUP' },
{
prim: 'DIP',
args: [
[{ prim: 'CDR', annots: ['@%%'] }, parseSetMapCadr(p, expr.slice(1), [], term)],
],
},
{ prim: 'CAR', annots: ['@%%'] },
{ prim: 'PAIR', annots: ['%@', '%@', ...vann] },
]
: term.d;
default:
throw new MacroError(p, `${p.prim}: unexpected character: ${c}`);
}
}
function trimLast(a, v) {
let l = a.length;
while (l > 0 && a[l - 1] === v) {
l--;
}
return a.slice(0, l);
}
function filterAnnotations(a) {
const fields = [];
const rest = [];
if (a !== undefined) {
for (const v of a) {
(v.length !== 0 && v[0] === '%' ? fields : rest).push(v);
}
}
return { fields, rest };
}
function mkPrim({ prim, annots, args }) {
return Object.assign(Object.assign({ prim }, (annots && { annots })), (args && { args }));
}
const pairRe = /^P[PAI]{3,}R$/;
const unpairRe = /^UNP[PAI]{2,}R$/;
const cadrRe = /^C[AD]{2,}R$/;
const setCadrRe = /^SET_C[AD]+R$/;
const mapCadrRe = /^MAP_C[AD]+R$/;
const diipRe = /^DI{2,}P$/;
const duupRe = /^DU+P$/;
function expandMacros(ex, opt) {
const proto = (opt === null || opt === void 0 ? void 0 : opt.protocol) || DefaultProtocol;
function mayRename(annots) {
return annots !== undefined ? [{ prim: 'RENAME', annots }] : [];
}
switch (ex.prim) {
// Compare
case 'CMPEQ':
case 'CMPNEQ':
case 'CMPLT':
case 'CMPGT':
case 'CMPLE':
case 'CMPGE':
if (assertArgs$1(ex, 0)) {
return [{ prim: 'COMPARE' }, mkPrim({ prim: ex.prim.slice(3), annots: ex.annots })];
}
break;
case 'IFEQ':
case 'IFNEQ':
case 'IFLT':
case 'IFGT':
case 'IFLE':
case 'IFGE':
if (assertArgs$1(ex, 2)) {
return [
{ prim: ex.prim.slice(2) },
mkPrim({ prim: 'IF', annots: ex.annots, args: ex.args }),
];
}
break;
case 'IFCMPEQ':
case 'IFCMPNEQ':
case 'IFCMPLT':
case 'IFCMPGT':
case 'IFCMPLE':
case 'IFCMPGE':
if (assertArgs$1(ex, 2)) {
return [
{ prim: 'COMPARE' },
{ prim: ex.prim.slice(5) },
mkPrim({ prim: 'IF', annots: ex.annots, args: ex.args }),
];
}
break;
// Fail
case 'FAIL':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [{ prim: 'UNIT' }, { prim: 'FAILWITH' }];
}
break;
// Assertion macros
case 'ASSERT':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [
{
prim: 'IF',
args: [[], [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_EQ':
case 'ASSERT_NEQ':
case 'ASSERT_LT':
case 'ASSERT_GT':
case 'ASSERT_LE':
case 'ASSERT_GE':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [
{ prim: ex.prim.slice(7) },
{
prim: 'IF',
args: [[], [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_CMPEQ':
case 'ASSERT_CMPNEQ':
case 'ASSERT_CMPLT':
case 'ASSERT_CMPGT':
case 'ASSERT_CMPLE':
case 'ASSERT_CMPGE':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [
[{ prim: 'COMPARE' }, { prim: ex.prim.slice(10) }],
{
prim: 'IF',
args: [[], [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_NONE':
if (assertArgs$1(ex, 0) && assertNoAnnots(ex)) {
return [
{
prim: 'IF_NONE',
args: [[], [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_SOME':
if (assertArgs$1(ex, 0)) {
return [
{
prim: 'IF_NONE',
args: [[[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]], mayRename(ex.annots)],
},
];
}
break;
case 'ASSERT_LEFT':
if (assertArgs$1(ex, 0)) {
return [
{
prim: 'IF_LEFT',
args: [mayRename(ex.annots), [[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]]],
},
];
}
break;
case 'ASSERT_RIGHT':
if (assertArgs$1(ex, 0)) {
return [
{
prim: 'IF_LEFT',
args: [[[{ prim: 'UNIT' }, { prim: 'FAILWITH' }]], mayRename(ex.annots)],
},
];
}
break;
// Syntactic conveniences
case 'IF_SOME':
if (assertArgs$1(ex, 2)) {
return [mkPrim({ prim: 'IF_NONE', annots: ex.annots, args: [ex.args[1], ex.args[0]] })];
}
break;
case 'IF_RIGHT':
if (assertArgs$1(ex, 2)) {
return [mkPrim({ prim: 'IF_LEFT', annots: ex.annots, args: [ex.args[1], ex.args[0]] })];
}
break;
// CAR/CDR n
case 'CAR':
case 'CDR':
if (ex.args !== undefined) {
if (assertArgs$1(ex, 1) && assertIntArg(ex, ex.args[0])) {
const n = parseInt(ex.args[0].int, 10);
return mkPrim({
prim: 'GET',
args: [{ int: ex.prim === 'CAR' ? String(n * 2 + 1) : String(n * 2) }],
annots: ex.annots,
});
}
}
else {
return ex;
}
}
// More syntactic conveniences
// PAPPAIIR macro
if (pairRe.test(ex.prim)) {
if (assertArgs$1(ex, 0)) {
const { fields, rest } = filterAnnotations(ex.annots);
const { r } = parsePairUnpairExpr(ex, ex.prim.slice(1), fields, (l, r, top) => [
...(l || []),
...(r || []),
top,
]);
return r.map(([v, a], i) => {
const ann = [
...trimLast(a, null).map((v) => (v === null ? '%' : v)),
...(v === 0 && i === r.length - 1 ? rest : []),
];
const leaf = mkPrim({ prim: 'PAIR', annots: ann.length !== 0 ? ann : undefined });
return v === 0
? leaf
: {
prim: 'DIP',
args: v === 1 ? [[leaf]] : [{ int: String(v) }, [leaf]],
};
});
}
}
// UNPAPPAIIR macro
if (unpairRe.test(ex.prim)) {
if (ProtoInferiorTo(proto, exports.Protocol.PtEdo2Zk) && assertArgs$1(ex, 0)) {
const { r } = parsePairUnpairExpr(ex, ex.prim.slice(3), ex.annots || [], (l, r, top) => [
top,
...(r || []),
...(l || []),
]);
return r.map(([v, a]) => {
const leaf = [
{ prim: 'DUP' },
mkPrim({ prim: 'CAR', annots: a[0] !== null ? [a[0]] : undefined }),
{
prim: 'DIP',
args: [[mkPrim({ prim: 'CDR', annots: a[1] !== null ? [a[1]] : undefined })]],
},
];
return v === 0
? leaf
: {
prim: 'DIP',
args: v === 1 ? [[leaf]] : [{ int: String(v) }, [leaf]],
};
});
}
else {
if (ex.prim === 'UNPAIR') {
return ex;
}
if (assertArgs$1(ex, 0)) {
// 008_edo: annotations are deprecated
const { r } = parsePairUnpairExpr(ex, ex.prim.slice(3), [], (l, r, top) => [
top,
...(r || []),
...(l || []),
]);
return r.map(([v]) => {
const leaf = mkPrim({
prim: 'UNPAIR',
});
return v === 0
? leaf
: {
prim: 'DIP',
args: v === 1 ? [[leaf]] : [{ int: String(v) }, [leaf]],
};
});
}
}
}
// C[AD]+R macro
if (cadrRe.test(ex.prim)) {
if (assertArgs$1(ex, 0)) {
const ch = [...ex.prim.slice(1, ex.prim.length - 1)];
return ch.map((c, i) => {
const ann = i === ch.length - 1 ? ex.annots : undefined;
switch (c) {
case 'A':
return mkPrim({ prim: 'CAR', annots: ann });
case 'D':
return mkPrim({ prim: 'CDR', annots: ann });
default:
throw new MacroError(ex, `unexpected character: ${c}`);
}
});
}
}
// SET_C[AD]+R macro
if (setCadrRe.test(ex.prim)) {
if (assertArgs$1(ex, 0)) {
const { fields, rest } = filterAnnotations(ex.annots);
if (fields.length > 1) {
throw new MacroError(ex, `unexpected annotation on macro ${ex.prim}: ${fields}`);
}
const term = fields.length !== 0
? {
a: [
{ prim: 'DUP' },
{ prim: 'CAR', annots: fields },
{ prim: 'DROP' },
{ prim: 'CDR', annots: ['@%%'] },
{ prim: 'SWAP' },
{ prim: 'PAIR', annots: [fields[0], '%@'] },
],
d: [
{ prim: 'DUP' },
{ prim: 'CDR', annots: fields },
{ prim: 'DROP' },
{ prim: 'CAR', annots: ['@%%'] },
{ prim: 'PAIR', annots: ['%@', fields[0]] },
],
}
: {
a: [
{ prim: 'CDR', annots: ['@%%'] },
{ prim: 'SWAP' },
{ prim: 'PAIR', annots: ['%', '%@'] },
],
d: [
{ prim: 'CAR', annots: ['@%%'] },
{ prim: 'PAIR', annots: ['%@', '%'] },
],
};
return parseSetMapCadr(ex, ex.prim.slice(5, ex.prim.length - 1), rest, term);
}
}
// MAP_C[AD]+R macro
if (mapCadrRe.test(ex.prim)) {
if (assertArgs$1(ex, 1)) {
const { fields } = filterAnnotations(ex.annots);
if (fields.length > 1) {
throw new MacroError(ex, `unexpected annotation on macro ${ex.prim}: ${fields}`);
}
const term = {
a: [
{ prim: 'DUP' },
{ prim: 'CDR', annots: ['@%%'] },
{
prim: 'DIP',
args: [
[
mkPrim({
prim: 'CAR',
annots: fields.length !== 0 ? ['@' + fields[0].slice(1)] : undefined,
}),
ex.args[0],
],
],
},
{ prim: 'SWAP' },
{ prim: 'PAIR', annots: [fields.length !== 0 ? fields[0] : '%', '%@'] },
],
d: [
{ prim: 'DUP' },
mkPrim({
prim: 'CDR',
annots: fields.length !== 0 ? ['@' + fields[0].slice(1)] : undefined,
}),
ex.args[0],
{ prim: 'SWAP' },
{ prim: 'CAR', annots: ['@%%'] },
{ prim: 'PAIR', annots: ['%@', fields.length !== 0 ? fields[0] : '%'] },
],
};
return parseSetMapCadr(ex, ex.prim.slice(5, ex.prim.length - 1), [], term);
}
}
// Expand deprecated DI...IP to [DIP n]
if (diipRe.test(ex.prim)) {
if (assertArgs$1(ex, 1)) {
let n = 0;
while (ex.prim[1 + n] === 'I') {
n++;
}
return mkPrim({ prim: 'DIP', args: [{ int: String(n) }, ex.args[0]] });
}
}
// Expand DU...UP and DUP n
if (duupRe.test(ex.prim)) {
let n = 0;
while (ex.prim[1 + n] === 'U') {
n++;
}
if (ProtoInferiorTo(proto, exports.Protocol.PtEdo2Zk)) {
if (n === 1) {
if (ex.args === undefined) {
return ex; // skip
}
if (assertArgs$1(ex, 1) && assertIntArg(ex, ex.args[0])) {
n = parseInt(ex.args[0].int, 10);
}
}
else {
assertArgs$1(ex, 0);
}
if (n === 1) {
return [mkPrim({ prim: 'DUP', annots: ex.annots })];
}
else if (n === 2) {
return [
{
prim: 'DIP',
args: [[mkPrim({ prim: 'DUP', annots: ex.annots })]],
},
{ prim: 'SWAP' },
];
}
else {
return [
{
prim: 'DIP',
args: [{ int: String(n - 1) }, [mkPrim({ prim: 'DUP', annots: ex.annots })]],
},
{
prim: 'DIG',
args: [{ int: String(n) }],
},
];
}
}
else {
if (n === 1) {
return ex;
}
if (assertArgs$1(ex, 0)) {
return mkPrim({ prim: 'DUP', args: [{ int: String(n) }], annots: ex.annots });
}
}
}
return ex;
}
function expandGlobalConstants(ex, hashAndValue) {
if (ex.args !== undefined &&
ex.args.length === 1 &&
'string' in ex.args[0] &&
ex.args[0].string in hashAndValue) {
return hashAndValue[ex.args[0].string];
}
return ex;
}
/**
* @category Error
* @description Error that indicates a failure when parsing Micheline expressions
*/
class MichelineParseError extends core.TaquitoError {
/**
* @param token A token caused the error
* @param message An error message
*/
constructor(token, message) {
super();
this.token = token;
this.message = message;
this.name = 'MichelineParseError';
}
}
/**
* @category Error
* @description Error indicates a failure when parsing Micheline JSON
*/
class JSONParseError extends core.TaquitoError {
/**
* @param node A node caused the error
* @param message An error message
*/
constructor(node, message) {
super();
this.node = node;
this.message = message;
this.name = 'JSONParseError';
}
}
const errEOF = new MichelineParseError(null, 'Unexpected EOF');
function isAnnotation(tok) {
return tok.t === Literal.Ident && (tok.v[0] === '@' || tok.v[0] === '%' || tok.v[0] === ':');
}
const intRe = new RegExp('^-?[0-9]+$');
const bytesRe = new RegExp('^([0-9a-fA-F]{2})*$');
/**
* Converts and validates Michelson expressions between JSON-based Michelson and Micheline
*
* Pretty Print a Michelson Smart Contract:
* ```
* const contract = await Tezos.contract.at("KT1Vsw3kh9638gqWoHTjvHCoHLPKvCbMVbCg");
* const p = new Parser();
*
* const michelsonCode = p.parseJSON(contract.script.code);
* const storage = p.parseJSON(contract.script.storage);
*
* console.log("Pretty print Michelson smart contract:");
* console.log(emitMicheline(michelsonCode, {indent:" ", newline: "\n",}));
*
* console.log("Pretty print Storage:");
* console.log(emitMicheline(storage, {indent:" ", newline: "\n",}));
* ```
*
* Encode a Michelson expression for initial storage of a smart contract
* ```
* const src = `(Pair (Pair { Elt 1
* (Pair (Pair "tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx")
* 0x0501000000026869) }
* 10000000)
* (Pair 2 333))`;
*
* const p = new Parser();
*
* const exp = p.parseMichelineExpression(src);
* console.log(JSON.stringify(exp));
* ```
*/
class Parser {
constructor(opt) {
this.opt = opt;
}
expand(ex) {
var _a, _b, _c;
if (((_a = this.opt) === null || _a === void 0 ? void 0 : _a.expandGlobalConstant) !== undefined && ex.prim === 'constant') {
const ret = expandGlobalConstants(ex, this.opt.expandGlobalConstant);
if (ret !== ex) {
ret[sourceReference] = Object.assign(Object.assign({}, (ex[sourceReference] || { first: 0, last: 0 })), { globalConstant: ex });
}
return ret;
}
if (((_b = this.opt) === null || _b === void 0 ? void 0 : _b.expandMacros) !== undefined ? (_c = this.opt) === null || _c === void 0 ? void 0 : _c.expandMacros : true) {
const ret = expandMacros(ex, this.opt);
if (ret !== ex) {
ret[sourceReference] = Object.assign(Object.assign({}, (ex[sourceReference] || { first: 0, last: 0 })), { macro: ex });
}
return ret;
}
else {
return ex;
}
}
parseListExpr(scanner, start) {
var _a;
const ref = {
first: start.first,
last: start.last,
};
const expectBracket = start.t === '(';
let tok;
if (expectBracket) {
tok = scanner.next();
if (tok.done) {
throw errEOF;
}
ref.last = tok.value.last;
}
else {
tok = { value: start };
}
if (tok.value.t !== Literal.Ident) {
throw new MichelineParseError(tok.value, `not an identifier: ${tok.value.v}`);
}
const ret = {
prim: tok.value.v,
[sourceReference]: ref,
};
for (;;) {
const tok = scanner.next();
if (tok.done) {
if (expectBracket) {
throw errEOF;
}
break;
}
else if (tok.value.t === ')') {
if (!expectBracket) {
throw new MichelineParseError(tok.value, 'unexpected closing bracket');
}
ref.last = tok.value.last;
break;
}
else if (isAnnotation(tok.value)) {
ret.annots = ret.annots || [];
ret.annots.push(tok.value.v);
ref.last = tok.value.last;
}
else {
ret.args = ret.args || [];
const arg = this.parseExpr(scanner, tok.value);
ref.last = ((_a = arg[sourceReference]) === null || _a === void 0 ? void 0 : _a.last) || ref.last;
ret.args.push(arg);
}
}
return this.expand(ret);
}
parseArgs(scanner, start) {
var _a;
// Identifier with arguments
const ref = {
first: start.first,
last: start.last,
};
const p = {
prim: start.v,
[sourceReference]: ref,
};
for (;;) {
const t = scanner.next();
if (t.done || t.value.t === '}' || t.value.t === ';') {
return [p, t];
}
if (isAnnotation(t.value)) {
ref.last = t.value.last;
p.annots = p.annots || [];
p.annots.push(t.value.v);
}
else {
const arg = this.parseExpr(scanner, t.value);
ref.last = ((_a = arg[sourceReference]) === null || _a === void 0 ? void 0 : _a.last) || ref.last;
p.args = p.args || [];
p.args.push(arg);
}
}
}
parseSequenceExpr(scanner, start) {
var _a, _b;
const ref = {
first: start.first,
last: start.last,
};
const seq = [];
seq[sourceReference] = ref;
const expectBracket = start.t === '{';
let tok = start.t === '{' ? null : { value: start };
for (;;) {
if (tok === null) {
tok = scanner.next();
if (!tok.done) {
ref.last = tok.value.last;
}
}
if (tok.done) {
if (expectBracket) {
throw errEOF;
}
else {
return seq;
}
}
if (tok.value.t === '}') {
if (!expectBracket) {
throw new MichelineParseError(tok.value, 'unexpected closing bracket');
}
else {
return seq;
}
}
else if (tok.value.t === Literal.Ident) {
// Identifier with arguments
const [itm, n] = this.parseArgs(scanner, tok.value);
ref.last = ((_a = itm[sourceReference]) === null || _a === void 0 ? void 0 : _a.last) || ref.last;
seq.push(this.expand(itm));
tok = n;
}
else {
// Other
const ex = this.parseExpr(scanner, tok.value);
ref.last = ((_b = ex[sourceReference]) === null || _b === void 0 ? void 0 : _b.last) || ref.last;
seq.push(ex);
tok = null;
}
if (tok === null) {
tok = scanner.next();
if (!tok.done) {
ref.last = tok.value.last;
}
}
if (!tok.done && tok.value.t === ';') {
tok = null;
}
}
}
parseExpr(scanner, tok) {
switch (tok.t) {
case Literal.Ident:
return this.expand({
prim: tok.v,
[sourceReference]: { first: tok.first, last: tok.last },
});
case Literal.Number:
return { int: tok.v, [sourceReference]: { first: tok.first, last: tok.last } };
case Literal.String:
return {
string: JSON.parse(tok.v),
[sourceReference]: { first: tok.first, last: tok.last },
};
case Literal.Bytes:
return { bytes: tok.v.slice(2), [sourceReference]: { first: tok.first, last: tok.last } };
case '{':
return this.parseSequenceExpr(scanner, tok);
default:
return this.parseListExpr(scanner, tok);
}
}
/**
* Parses a Micheline sequence expression, such as smart contract source. Enclosing curly brackets may be omitted.
* @param src A Micheline sequence `{parameter ...; storage int; code { DUP ; ...};}` or `parameter ...; storage int; code { DUP ; ...};`
*/
parseSequence(src) {
if (typeof src !== 'string') {
throw new TypeError(`string type was expected, got ${typeof src} instead`);
}
const scanner = scan(src);
const tok = scanner.next();
if (tok.done) {
return null;
}
return this.parseSequenceExpr(scanner, tok.value);
}
/**
* Parse a Micheline sequence expression. Enclosing curly brackets may be omitted.
* @param src A Michelson list expression such as `(Pair {Elt "0" 0} 0)` or `Pair {Elt "0" 0} 0`
* @returns An AST node or null for empty document.
*/
parseList(src) {
if (typeof src !== 'string') {
throw new TypeError(`string type was expected, got ${typeof src} instead`);
}
const scanner = scan(src);
const tok = scanner.next();
if (tok.done) {
return null;
}
return this.parseListExpr(scanner, tok.value);
}
/**
* Parse any Michelson expression
* @param src A Michelson expression such as `(Pair {Elt "0" 0} 0)` or `{parameter ...; storage int; code { DUP ; ...};}`
* @returns An AST node or null for empty document.
*/
parseMichelineExpression(src) {
if (typeof src !== 'string') {
throw new TypeError(`string type was expected, got ${typeof src} instead`);
}
const scanner = scan(src);
const tok = scanner.next();
if (tok.done) {
return null;
}
return this.parseExpr(scanner, tok.value);
}
/**
* Parse a Micheline sequence expression, such as smart contract source. Enclosing curly brackets may be omitted.
* An alias for `parseSequence`
* @param src A Micheline sequence `{parameter ...; storage int; code { DUP ; ...};}` or `parameter ...; storage int; code { DUP ; ...};`
*/
parseScript(src) {
return this.parseSequence(src);
}
/**
* Parse a Micheline sequence expression. Enclosing curly brackets may be omitted.
* An alias for `parseList`
* @param src A Michelson list expression such as `(Pair {Elt "0" 0} 0)` or `Pair {Elt "0" 0} 0`
* @returns An AST node or null for empty document.
*/
parseData(src) {
return this.parseList(src);
}
/**
* Takes a JSON-encoded Michelson, validates it, strips away unneeded properties and optionally expands macros (See {@link ParserOptions}).
* @param src An object containing JSON-encoded Michelson, usually returned by `JSON.parse()`
*/
parseJSON(src) {
if (typeof src !== 'object') {
throw new TypeError(`object type was expected, got ${typeof src} instead`);
}
if (Array.isArray(src)) {
const ret = [];
for (const n of src) {
if (n === null || typeof n !== 'object') {
throw new JSONParseError(n, `unexpected sequence element: ${n}`);
}
ret.push(this.parseJSON(n));
}
return ret;
}
else if ('prim' in src) {
const p = src;
if (typeof p.prim === 'string' &&
(p.annots === undefined || Array.isArray(p.annots)) &&
(p.args === undefined || Array.isArray(p.args))) {
const ret = {
prim: p.prim,
};
if (p.annots !== undefined) {
for (const a of p.annots) {
if (typeof a !== 'string') {
throw new JSONParseError(a, `string expected: ${a}`);
}
}
ret.annots = p.annots;
}
if (p.args !== undefined) {
ret.args = [];
for (const a of p.args) {
if (a === null || typeof a !== 'object') {
throw new JSONParseError(a, `unexpected argument: ${a}`);
}
ret.args.push(this.parseJSON(a));
}
}
return this.expand(ret);
}
throw new JSONParseError(src, `malformed prim expression: ${src}`);
}
else if ('string' in src) {
if (typeof src.string === 'string') {
return { string: src.string };
}
throw new JSONParseError(src, `malformed string literal: ${src}`);
}
else if ('int' in src) {
if (typeof src.int === 'string' && intRe.test(src.int)) {
return { int: src.int };
}
throw new JSONParseError(src, `malformed int literal: ${src}`);
}
else if ('bytes' in src) {
if (typeof src.bytes === 'string' &&
bytesRe.test(src.bytes)) {
return { bytes: src.bytes };
}
throw new JSONParseError(src, `malformed bytes literal: ${src}`);
}
else {
throw new JSONParseError(src, `unexpected object: ${src}`);
}
}
}
class Formatter {
constructor(opt, lev = 0) {
this.opt = opt;
this.lev = lev;
}
indent(n = 0) {
var _a;
let ret = '';
if (((_a = this.opt) === null || _a === void 0 ? void 0 : _a.indent) !== undefined) {
for (let i = this.lev + n; i > 0; i--) {
ret += this.opt.indent;
}
}
return ret;
}
get lf() {
var _a;
return ((_a = this.opt) === null || _a === void 0 ? void 0 : _a.newline) || '';
}
get lfsp() {
var _a;
return ((_a = this.opt) === null || _a === void 0 ? void 0 : _a.newline) || ' ';
}
down(n) {
return new Formatter(this.opt, this.lev + n);
}
}
function hasArgs(node) {
return ('prim' in node &&
((node.annots !== undefined && node.annots.length !== 0) ||
(node.args !== undefined && node.args.length !== 0)));
}
function isMultiline(node) {
if (node.args !== undefined) {
for (const a of node.args) {
if (Array.isArray(a) || hasArgs(a)) {
return true;
}
}
}
return false;
}
function emitExpr(node, f, foldMacros) {
var _a;
const macro = (_a = node[sourceReference]) === null || _a === void 0 ? void 0 : _a.macro;
if (foldMacros && macro) {
return emitExpr(macro, f, foldMacros);
}
if (Array.isArray(node)) {
return emitSeq(node, f, foldMacros);
}
else if ('string' in node) {
return JSON.stringify(node.string);
}
else if ('int' in node) {
return node.int;
}
else if ('bytes' in node) {
return '0x' + node.bytes;
}
else {
if ((node.annots === undefined || node.annots.length === 0) &&
(node.args === undefined || node.args.length === 0)) {
return node.prim;
}
let ret = '(' + node.prim;
if (node.annots !== undefined) {
for (const a of node.annots) {
ret += ' ' + a;
}
}
if (node.args !== undefined) {
const multiline = isMultiline(node);
for (const a of node.args) {
if (multiline) {
ret += f.lfsp + f.indent(1) + emitExpr(a, f.down(1), foldMacros);
}
else {
ret += ' ' + emitExpr(a, f, foldMacros);
}
}
}
return ret + ')';
}
}
function emitSeq(node, f, foldMacros) {
let ret = '{' + f.lf;
let i = node.length;
for (const el of node) {
ret += f.indent(1);
if ('prim' in el) {
ret += el.prim;
if (el.annots !== undefined) {
for (const a of el.annots) {
ret += ' ' + a;
}
}
if (el.args !== undefined) {
const multiline = isMultiline(el);
for (const a of el.args) {
if (multiline) {
ret += f.lfsp + f.indent(2) + emitExpr(a, f.down(2), foldMacros);
}
else {
ret += ' ' + emitExpr(a, f, foldMacros);
}
}
}
}
else {
ret += emitExpr(el, f.down(1), foldMacros);
}
ret += i > 1 ? ';' + f.lfsp : f.lf;
i--;
}
return ret + f.indent() + '}';
}
/**
* Formats Micheline expression
* @param expr An AST node
* @param opt Options
*/
function emitMicheline(expr, opt, foldMacros = false) {
if (typeof expr !== 'object') {
throw new TypeError(`object type was expected, got ${typeof expr} instead`);
}
return emitExpr(expr, new Formatter(opt), foldMacros);
}
const H = [
0x6a09e667 | 0,
0xbb67ae85 | 0,
0x3c6ef372 | 0,
0xa54ff53a | 0,
0x510e527f | 0,
0x9b05688c | 0,
0x1f83d9ab | 0,
0x5be0cd19 | 0,
];
const K = [
0x428a2f98 | 0,
0x71374491 | 0,
0xb5c0fbcf | 0,
0xe9b5dba5 | 0,
0x3956c25b | 0,
0x59f111f1 | 0,
0x923f82a4 | 0,
0xab1c5ed5 | 0,
0xd807aa98 | 0,
0x12835b01 | 0,
0x243185be | 0,
0x550c7dc3 | 0,
0x72be5d74 | 0,
0x80deb1fe | 0,
0x9bdc06a7 | 0,
0xc19bf174 | 0,
0xe49b69c1 | 0,
0xefbe4786 | 0,
0x0fc19dc6 | 0,
0x240ca1cc | 0,
0x2de92c6f | 0,
0x4a7484aa | 0,
0x5cb0a9dc | 0,
0x76f988da | 0,
0x983e5152 | 0,
0xa831c66d | 0,
0xb00327c8 | 0,
0xbf597fc7 | 0,
0xc6e00bf3 | 0,
0xd5a79147 | 0,
0x06ca6351 | 0,
0x14292967 | 0,
0x27b70a85 | 0,
0x2e1b2138 | 0,
0x4d2c6dfc | 0,
0x53380d13 | 0,
0x650a7354 | 0,
0x766a0abb | 0,
0x81c2c92e | 0,
0x92722c85 | 0,
0xa2bfe8a1 | 0,
0xa81a664b | 0,
0xc24b8b70 | 0,
0xc76c51a3 | 0,
0xd192e819 | 0,
0xd6990624 | 0,
0xf40e3585 | 0,
0x106aa070 | 0,
0x19a4c116 | 0,
0x1e376c08 | 0,
0x2748774c | 0,
0x34b0bcb5 | 0,
0x391c0cb3 | 0,
0x4ed8aa4a | 0,
0x5b9cca4