UNPKG

clvm

Version:

Javascript implementation of chia lisp

172 lines (171 loc) 6.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.run_program = exports.msb_mask = exports.to_pre_eval_op = void 0; const __python_types__1 = require("./__python_types__"); const SExp_1 = require("./SExp"); const CLVMObject_1 = require("./CLVMObject"); const __type_compatibility__1 = require("./__type_compatibility__"); const costs_1 = require("./costs"); const EvalError_1 = require("./EvalError"); function to_pre_eval_op(pre_eval_f, to_sexp_f) { return function my_pre_eval_op(op_stack, value_stack) { const v = to_sexp_f(value_stack[value_stack.length - 1]); const context = pre_eval_f(v.first(), v.rest()); if (typeof context === "function") { const invoke_context_op = (op_stack, value_stack) => { context(to_sexp_f(value_stack[value_stack.length - 1])); return 0; }; op_stack.push(invoke_context_op); } }; } exports.to_pre_eval_op = to_pre_eval_op; function msb_mask(byte) { byte |= byte >> 1; byte |= byte >> 2; byte |= byte >> 4; return (byte + 1) >> 1; } exports.msb_mask = msb_mask; /** * @deprecated Use `run_chia_program` instead. */ function run_program(program, args, operator_lookup, max_cost = __python_types__1.None, pre_eval_f = __python_types__1.None) { console.warn("`run_program is deprecated. Use `run_chia_program` instead.`"); program = SExp_1.SExp.to(program); const pre_eval_op = pre_eval_f ? to_pre_eval_op(pre_eval_f, SExp_1.SExp.to) : __python_types__1.None; function traverse_path(sexp, env) { let cost = costs_1.PATH_LOOKUP_BASE_COST; cost += costs_1.PATH_LOOKUP_COST_PER_LEG; if (sexp.nullp()) { return (0, __type_compatibility__1.t)(cost, SExp_1.SExp.null()); } const b = sexp.atom; let end_byte_cursor = 0; while (end_byte_cursor < b.length && b.at(end_byte_cursor) === 0) { end_byte_cursor += 1; } cost += end_byte_cursor * costs_1.PATH_LOOKUP_COST_PER_ZERO_BYTE; if (end_byte_cursor === b.length) { return (0, __type_compatibility__1.t)(cost, SExp_1.SExp.null()); } // create a bitmask for the most significant *set* bit // in the last non-zero byte const end_bitmask = msb_mask(b.at(end_byte_cursor)); let byte_cursor = b.length - 1; let bitmask = 0x01; while (byte_cursor > end_byte_cursor || bitmask < end_bitmask) { if (!(0, CLVMObject_1.isCons)(env)) { throw new EvalError_1.EvalError("path into atom", env); } if (b.at(byte_cursor) & bitmask) { env = env.rest(); } else { env = env.first(); } cost += costs_1.PATH_LOOKUP_COST_PER_LEG; bitmask <<= 1; if (bitmask === 0x0100) { byte_cursor -= 1; bitmask = 0x01; } } return (0, __type_compatibility__1.t)(cost, env); } function swap_op(op_stack, value_stack) { const v2 = value_stack.pop(); const v1 = value_stack.pop(); value_stack.push(v2); value_stack.push(v1); return 0; } function cons_op(op_stack, value_stack) { const v1 = value_stack.pop(); const v2 = value_stack.pop(); value_stack.push(v1.cons(v2)); return 0; } function eval_op(op_stack, value_stack) { if (pre_eval_op) { pre_eval_op(op_stack, value_stack); } const pair = value_stack.pop(); const sexp = pair.first(); const args = pair.rest(); // put a bunch of ops on op_stack if (!(0, CLVMObject_1.isCons)(sexp)) { // sexp is an atom const [cost, r] = traverse_path(sexp, args); value_stack.push(r); return cost; } const operator = sexp.first(); if ((0, CLVMObject_1.isCons)(operator)) { const pair = operator.as_pair(); const [new_operator, must_be_nil] = pair; if (new_operator.pair || !__type_compatibility__1.Bytes.NULL.equal_to(must_be_nil.atom)) { throw new EvalError_1.EvalError("in ((X)...) syntax X must be lone atom", sexp); } const new_operand_list = sexp.rest(); value_stack.push(new_operator); value_stack.push(new_operand_list); op_stack.push(apply_op); return costs_1.APPLY_COST; } const op = operator.atom; let operand_list = sexp.rest(); // op === operator_lookup.quote_atom if (op.equal_to(operator_lookup.quote_atom)) { value_stack.push(operand_list); return costs_1.QUOTE_COST; } op_stack.push(apply_op); value_stack.push(operator); while (!operand_list.nullp()) { const _ = operand_list.first(); value_stack.push(_.cons(args)); op_stack.push(cons_op); op_stack.push(eval_op); op_stack.push(swap_op); operand_list = operand_list.rest(); } value_stack.push(SExp_1.SExp.null()); return 1; } function apply_op(op_stack, value_stack) { const operand_list = value_stack.pop(); const operator = value_stack.pop(); if (!(0, CLVMObject_1.isAtom)(operator)) { throw new EvalError_1.EvalError("internal error", operator); } const op = operator.atom; // op === operator_lookup.apply_atom if (op.equal_to(operator_lookup.apply_atom)) { if (operand_list.list_len() !== 2) { throw new EvalError_1.EvalError("apply requires exactly 2 parameters", operand_list); } const new_program = operand_list.first(); const new_args = operand_list.rest().first(); value_stack.push(new_program.cons(new_args)); op_stack.push(eval_op); return costs_1.APPLY_COST; } const [additional_cost, r] = operator_lookup(op, operand_list); value_stack.push(r); return additional_cost; } const op_stack = [eval_op]; const value_stack = [program.cons(args)]; let cost = 0; while (op_stack.length) { const f = op_stack.pop(); cost += f(op_stack, value_stack); if (max_cost && cost > max_cost) { throw new EvalError_1.EvalError("cost exceeded", SExp_1.SExp.to(max_cost)); } } return (0, __type_compatibility__1.t)(cost, value_stack[value_stack.length - 1]); } exports.run_program = run_program;