UNPKG

hardhat-scilla-plugin

Version:
311 lines 10.7 kB
"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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.parseScilla = exports.parseScillaLibrary = exports.isNumeric = void 0; exports.generateTypeConstructors = generateTypeConstructors; const child_process_1 = require("child_process"); const fs_1 = __importDefault(require("fs")); const plugins_1 = require("hardhat/plugins"); const path_1 = __importDefault(require("path")); const readline_1 = __importDefault(require("readline")); const ZilliqaUtils = __importStar(require("../ZilliqaUtils")); // eslint-disable-next-line @typescript-eslint/no-var-requires const parse = require("s-expression"); const isNumeric = (type) => { if (typeof type === "string") { switch (type) { case "Int64": case "Int128": case "Int256": case "Uint32": case "Uint64": case "Uint128": case "Uint256": return true; default: return false; } } else { return false; } }; exports.isNumeric = isNumeric; const parseScillaLibrary = async (filename) => { if (!fs_1.default.existsSync(filename)) { throw new Error(`${filename} doesn't exist.`); } const fileStream = fs_1.default.createReadStream(filename); const rl = readline_1.default.createInterface({ input: fileStream, crlfDelay: Infinity, }); let libraryName; for await (const line of rl) { if (line.trim().startsWith("library")) { libraryName = line.trim().split(" ")[1]; break; } } return { name: libraryName || "", transitions: [], fields: [], constructorParams: [], ctors: [], }; }; exports.parseScillaLibrary = parseScillaLibrary; const parseScilla = (filename) => { const resolvedFilename = path_1.default.resolve(filename); if (!fs_1.default.existsSync(resolvedFilename)) { throw new Error(`${resolvedFilename} doesn't exist.`); } let sexp; if (ZilliqaUtils.useNativeScilla()) { sexp = (0, child_process_1.execSync)(`scilla-fmt --sexp --human-readable ${filename}`); } else { sexp = (0, child_process_1.execSync)(`docker run --rm -v ${resolvedFilename}:/tmp/input.scilla -i zilliqa/scilla:v0.13.3 /scilla/0/bin/scilla-fmt --sexp --human-readable /tmp/input.scilla`); } const result = parse(sexp.toString()); const libr = result.filter((row) => row[0] === "libs")[0][1]; const contr = result.filter((row) => row[0] === "contr")[0][1]; const ctors = extractTypes(libr); const contractName = extractContractName(contr); const contractParams = extractContractParams(contr); const cfields = contr.filter((row) => row[0] === "cfields")[0][1]; const fields = extractContractFields(cfields); const ccomps = contr.filter((row) => row[0] === "ccomps")[0][1]; const transitions = extractTransitions(ccomps); return { name: contractName, transitions, fields, constructorParams: contractParams, ctors, }; }; exports.parseScilla = parseScilla; const extractTypes = (lib) => { const ctors = []; if (lib.length > 0) { const lentries = lib[0][1][1]; for (const lentry of lentries) { switch (lentry[0]) { case "LibVar": break; case "LibTyp": for (const typector of lentry[2]) { const typename = lentry[1][1][1]; const typectorname = typector[0][1][1][1]; const typectorargtypes = typector[1][1].map(parseField); const userADT = { typename, ctorname: typectorname, argtypes: typectorargtypes, }; ctors.push(userADT); } break; } } } return ctors; }; const extractContractName = (contrElem) => { return contrElem .filter((row) => row[0] === "cname")[0][1] .filter((row) => row[0] === "SimpleLocal")[0][1]; }; const extractContractParams = (contrElem) => { if (contrElem[1][0] !== "cparams") { throw new Error(`Index 0 is not cparams: ${contrElem}`); } if (contrElem[1][1].length === 0) { return null; } return extractContractFields(contrElem[1][1]); }; const extractContractFields = (cfieldsElem) => { return cfieldsElem.map((row) => { const identData = row[0]; if (identData[0] !== "Ident") { throw new Error(`Index 0 is not Ident: ${identData}`); } const fieldNameData = identData[1]; if (fieldNameData[0] !== "SimpleLocal") { throw new Error(`Index 0 is not SimpleLocal: ${fieldNameData}`); } const fieldTypeData = row[1]; // Currently we just parse PrimType, for the rest we don't parse it completely. if (fieldTypeData[0] === "PrimType") { return { type: fieldTypeData[1], name: fieldNameData[1], }; } else if (fieldTypeData[0] === "ADT") { const adt = parseAdt(fieldTypeData); return { typeJSON: adt, type: adt.ctor + adt.argtypes.map((arg) => " " + arg.type).join(" "), name: fieldNameData[1], }; } else if (fieldTypeData[0] === "MapType") { return { type: "Map", name: fieldNameData[1], }; } else if (fieldTypeData[0] === "Address") { return { type: "ByStr20", name: fieldNameData[1], }; } else { throw new Error(`Data type is unknown: ${fieldTypeData}`); } }); }; const extractTransitions = (ccompsElem) => { return ccompsElem.map((row) => { const compTypeData = row[0]; if (compTypeData[0] !== "comp_type") { throw new Error(`Index 0 is not comp_type ${compTypeData}`); } const compType = compTypeData[1]; const compNameData = row[1]; if (compNameData[0] !== "comp_name") { throw new Error(`Index 0 is not comp_name ${compNameData}`); } const compName = compNameData[1][1]; if (compName[0] !== "SimpleLocal") { throw new Error(`Index 0 is not SimpleLocal: ${compName}`); } const compParamsData = row[2]; if (compParamsData[0] !== "comp_params") { throw new Error(`Index 0 is not comp_params: ${compParamsData}`); } const compParams = compParamsData[1].map((r) => { const param = parseField(r[1]); param.name = r[0][1][1]; return param; }); return { type: compType, name: compName[1], params: compParams, }; }); }; function parseAdt(row) { const ctor = row[1][1][1]; const argtypes = row[2].map(parseField); return { ctor, argtypes, }; } function generateAdtType(field) { if (field.argtypes.length === 0) { return field.ctor; } const type = `${field.ctor} ${field.argtypes .map((arg) => { // Here we're sure that type is ADTField const typeJson = arg.typeJSON; if (["Pair", "List"].includes(typeJson.ctor)) return `(${arg.type})`; else return arg.type; }) .reduce((prev, current) => `${prev} ${current}`)}`; return type; } function parseField(row) { const field_type = row[0]; if (field_type === "PrimType") { const type = row[1]; return { name: "", typeJSON: type, type, }; } else if (field_type === "ADT") { const adt = parseAdt(row); const name = row[0][1][1]; return { typeJSON: adt, type: generateAdtType(adt), name, }; } else if (field_type === "Address") { const type = "ByStr20"; return { name: "", typeJSON: type, type, }; } else { throw new plugins_1.HardhatPluginError("hardhat-scilla-plugin", `Encountered unexpected field type ${row}`); } } function generateTypeConstructors(parsedCtors) { const functions = {}; for (const parsedCtor of parsedCtors) { // We need to copy parsedCtor as it is placed in the closure of the function we are declaring so we do // not want it to be modified by the floor loop. const ctorForClosure = Object.create(parsedCtor); functions[ctorForClosure.ctorname] = (args) => { // TODO: Add dynamic type checking. return { constructor: ctorForClosure.ctorname, argtypes: ctorForClosure.argtypes, args, }; }; } return functions; } //# sourceMappingURL=ScillaParser.js.map