Repository: bitcoin/bitcoin
File: src/script/miniscript.h (C/C++)

Code before:
    /** ANDOR will construct an andor node from the last three constructed nodes. */
    ANDOR,
    /** OR_B will construct an or_b node from the last two constructed nodes. */
    OR_B,
    /** OR_C will construct an or_c node from the last two constructed nodes. */
    OR_C,
    /** OR_D will construct an or_d node from the last two constructed nodes. */
    OR_D,
    /** OR_I will construct an or_i node from the last two constructed nodes. */
    OR_I,

    /** THRESH will read a wrapped expression, and then look for a COMMA. If
     * no comma follows, it will construct a thresh node from the appropriate
     * number of constructed children. Otherwise, it will recurse with another
     * THRESH. */
    THRESH,

    /** COMMA expects the next element to be ',' and fails if not. */
    COMMA,
    /** CLOSE_BRACKET expects the next element to be ')' and fails if not. */
    CLOSE_BRACKET,
};

int FindNextChar(std::span<const char> in, const char m);

/** Parse a key string ending at the end of the fragment's text representation. */
template<typename Key, typename Ctx>
std::optional<Key> ParseKey(const std::string& func, std::span<const char>& in, const Ctx& ctx)
{
    std::span<const char> expr = script::Expr(in);
    if (!script::Func(func, expr)) return {};
    return ctx.FromString(expr);
}

/** Parse a hex string ending at the end of the fragment's text representation. */
template<typename Ctx>
std::optional<std::vector<unsigned char>> ParseHexStr(const std::string& func, std::span<const char>& in, const size_t expected_size,
                                                                         const Ctx& ctx)
{
    std::span<const char> expr = script::Expr(in);
    if (!script::Func(func, expr)) return {};
    std::string val = std::string(expr.begin(), expr.end());
    if (!IsHex(val)) return {};
    auto hash = ParseHex(val);
    if (hash.size() != expected_size) return {};
    return hash;
}

/** BuildBack pops the last two elements off `constructed` and wraps them in the specified Fragment */
template<typename Key>
void BuildBack(const MiniscriptContext script_ctx, Fragment nt, std::vector<NodeRef<Key>>& constructed, const bool reverse = false)

Review comment (suggestion):
In commit "miniscript: Using Func and Expr when parsing keys, hashes, and locktimes"

This comment seems outdated now, as it will also stop at commas (plus the comment should probably explain the new `func` argument).

Code after:
        : fragment(nt), k(val), subs(std::move(sub)), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}
    Node(internal::NoDupCheck, MiniscriptContext script_ctx, enum Fragment nt, uint32_t val = 0)
        : fragment(nt), k(val), m_script_ctx{script_ctx}, ops(CalcOps()), ss(CalcStackSize()), ws(CalcWitnessSize()), typ(CalcType()), scriptlen(CalcScriptLen()) {}

    // Constructors with various argument combinations, which do perform the duplicate key check.
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, std::vector<unsigned char> arg, uint32_t val = 0)
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(arg), val) { DuplicateKeyCheck(ctx); }
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<unsigned char> arg, uint32_t val = 0)
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(arg), val) { DuplicateKeyCheck(ctx);}
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, std::vector<Key> key, uint32_t val = 0)
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), std::move(key), val) { DuplicateKeyCheck(ctx); }
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Key> key, uint32_t val = 0)
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(key), val) { DuplicateKeyCheck(ctx); }
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, std::vector<Node> sub, uint32_t val = 0)
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, std::move(sub), val) { DuplicateKeyCheck(ctx); }
    template <typename Ctx> Node(const Ctx& ctx, enum Fragment nt, uint32_t val = 0)
        : Node(internal::NoDupCheck{}, ctx.MsContext(), nt, val) { DuplicateKeyCheck(ctx); }

    // Delete copy constructor and assignment operator, use Clone() instead
    Node(const Node&) = delete;
    Node& operator=(const Node&) = delete;

    // subs is movable, circumventing recursion, so these are permitted.
    Node(Node&&) noexcept = default;
    Node& operator=(Node&&) noexcept = default;
};

namespace internal {

enum class ParseContext {
    /** An expression which may be begin with wrappers followed by a colon. */
    WRAPPED_EXPR,
    /** A miniscript expression which does not begin with wrappers. */
    EXPR,

    /** SWAP wraps the top constructed node with s: */
    SWAP,
    /** ALT wraps the top constructed node with a: */
    ALT,
    /** CHECK wraps the top constructed node with c: */
    CHECK,
    /** DUP_IF wraps the top constructed node with d: */
    DUP_IF,
    /** VERIFY wraps the top constructed node with v: */
    VERIFY,
    /** NON_ZERO wraps the top constructed node with j: */
    NON_ZERO,
    /** ZERO_NOTEQUAL wraps the top constructed node with n: */
    ZERO_NOTEQUAL,
    /** WRAP_U will construct an or_i(X,0) node from the top constructed node. */
    WRAP_U,