UNPKG

clvm_tools

Version:

Javascript implementation of clvm_tools

97 lines (89 loc) 3.23 kB
"use strict"; /* We treat an s-expression as a binary tree, where leaf nodes are atoms and pairs are nodes with two children. We then number the paths as follows: 1 / \ / \ / \ / \ / \ / \ 2 3 / \ / \ / \ / \ 4 6 5 7 / \ / \ / \ / \ 8 12 10 14 9 13 11 15 etc. You're probably thinking "the first two rows make sense, but why do the numbers do that weird thing after?" The reason has to do with making the implementation simple. We want a simple loop which starts with the root node, then processes bits starting with the least significant, moving either left or right (first or rest). So the LEAST significant bit controls the first branch, then the next-least the second, and so on. That leads to this ugly-numbered tree. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.RIGHT = exports.LEFT = exports.TOP = exports.NodePath = exports.compose_paths = void 0; const clvm_1 = require("clvm"); function compose_paths(path_0, path_1) { /* The binary representation of a path is a 1 (which means "stop"), followed by the path as binary digits, where 0 is "left" and 1 is "right". Look at the diagram at the top for these examples. Example: 9 = 0b1001, so right, left, left Example: 10 = 0b1010, so left, right, left How it works: we write both numbers as binary. We ignore the terminal in path_0, since it's not the terminating condition anymore. We shift path_1 enough places to OR in the rest of path_0. Example: path_0 = 9 = 0b1001, path_1 = 10 = 0b1010. Shift path_1 three places (so there is room for 0b001) to 0b1010000. Then OR in 0b001 to yield 0b1010001 = 81, which is right, left, left, left, right, left. */ let mask = BigInt(1); let temp_path = path_0; while (temp_path > 1) { path_1 <<= BigInt(1); mask <<= BigInt(1); temp_path >>= BigInt(1); } mask -= BigInt(1); return path_1 | (path_0 & mask); } exports.compose_paths = compose_paths; class NodePath { constructor(index = BigInt(1)) { this.as_path = this.as_short_path; if (index < 0) { const b = clvm_1.bigint_to_bytes(index, { signed: true }); index = clvm_1.bigint_from_bytes(b, { signed: false }); } this._index = index; } get index() { return this._index; } as_short_path() { const index = this._index; return clvm_1.bigint_to_bytes(index); } add(other_node) { const composedPath = compose_paths(this.index, other_node.index); return new NodePath(composedPath); } first() { return new NodePath(this.index * BigInt(2)); } rest() { return new NodePath(this.index * BigInt(2) + BigInt(1)); } toString() { return `NodePath: ${this.index}`; } __repl__() { return `NodePath: ${this.index}`; } } exports.NodePath = NodePath; exports.TOP = new NodePath(); exports.LEFT = exports.TOP.first(); exports.RIGHT = exports.TOP.rest();