This version of the module is deprecated: Superseded by moonbitlang/core/debug, which is part of the standard library: use its Debug trait, derive(Debug), debug_inspect and render instead. This module gets no further updates.

    #moonbit-community/debug/repr

    This package defines Repr : a small, structural, tree-shaped representation used by moonbit-community/debug for:

    • pretty-printing (moonbit-community/debug/pretty_print)
    • diffing (moonbit-community/debug/diff)
    • the Debug trait (moonbit-community/debug)

    Repr is exported as a readonly enum ( pub enum Repr ), so it can be pattern-matched outside the package but not directly constructed. Use the smart constructors ( Repr::... ) or the convenience functions ( int , record , ...).

    #Records

    A record node is represented structurally as:

    • Record([RecordField(name, value), ...])

    #Why Record(Array[Repr]) + RecordField ?

    You might wonder why we don’t model records more “directly” as something like Record(Array[(String, Repr)]) . The choice here is deliberate:

    • Uniform traversal/rewrite: every tree edge is a Repr. Generic utilities like Repr::children , Repr::with_children , pruning, and the diff algorithm can treat records exactly like arrays/ctors/opaque nodes without special-cases for (String, Repr) pairs.
    • Field names live in the tree: a field is a real node (RecordField(name, ...)), so pretty-printing and diffing can use the same “label + children” pipeline everywhere.
    • Keeps the public API small: an alternative representation would either complicate the children/with_children contract (because record “children” aren’t Repr values) or require additional parallel APIs just for records.

    If you want “map-like” semantics (key/value pairs as first-class children), use Map([MapEntry(key, value), ...]) , which is what the Debug instance for Map uses.

    So for a value conceptually shaped like:

    record { x : Int; y : String }

    the corresponding Repr is:

    Record([ RecordField("x", Fixnum(...)), RecordField("y", StringLit(...)), ])

    #Example (runnable)

    ///|
    test {
    let r : Repr = @repr.Repr::record({
    "x": Repr::int(1),
    "y": Repr::string("hi"),
    })
    match r {
    Record([RecordField("x", Fixnum("1")), RecordField("y", StringLit("hi"))]) =>
    ()
    _ => fail("unexpected Repr shape for record {x: Int; y: String}")
    }
    }

    #Tuples (and unit)

    Tuples are represented as:

    • Tuple([a, b, ...])

    Unit is the empty tuple:

    • Tuple([]) (also constructible with unit())

    #Example (runnable)

    ///|
    test {
    let t : Repr = Repr::tuple([Repr::int(1), Repr::string("x")])
    match t {
    Tuple([Fixnum("1"), StringLit("x")]) => ()
    _ => fail("unexpected Repr shape for tuple (Int, String)")
    }
    }

    #Labeled constructor arguments

    MoonBit enum variants (and tuple-struct constructors) can have labeled arguments. To preserve those labels in a Repr , use Repr::ctor with optional labels:

    • Repr::ctor("A", [(Some("x"), ...), (Some("y"), ...)]) prints as A(x=..., y=...)

    • you can freely mix positional and labeled args: Repr::ctor("B", [(Some("x"), ...), (None, ...)])

    prints as B(x=..., ...)

    #Example (runnable)

    ///|
    test {
    let r : Repr = Repr::ctor("A", [
    (Some("x"), Repr::int(1)),
    (Some("y"), Repr::string("hi")),
    ])
    match r {
    Enum(
    "A",
    [EnumLabeledArg("x", Fixnum("1")), EnumLabeledArg("y", StringLit("hi"))]
    ) => ()
    _ => fail("unexpected Repr shape for labeled ctor A(x=Int, y=String)")
    }
    }

    Repr

    pub enum Repr {
    UnitLit
    Fixnum(String)
    DoubleLit(Double)
    FloatLit(Float)
    BoolLit(Bool)
    CharLit(Char)
    StringLit(String)
    Tuple(Array[Repr])
    Array(Array[Repr])
    Record(Array[Repr])
    Enum(String, Array[Repr])
    Map(Array[Repr])
    RecordField(String, Repr)
    EnumLabeledArg(String, Repr)
    Opaque(String, Array[Repr])
    Literal(String)
    MapEntry(Repr, Repr)
    Omitted
    }

    Direct structural representation for debugging/diffing/pretty-printing.

    pub makes it readonly outside this package: it can be pattern-matched but not directly constructed. Use the smart constructors below.

    Design notes:
    • Record is encoded as Record([RecordField(name, value), ...]) (not as an array of (String, Repr) pairs) to keep generic traversal/rewrite code simple: every tree edge is a Repr, so children/with_children, pruning, and diff can work uniformly across node kinds.
    • Labeled enum arguments are encoded as Enum(name, [EnumLabeledArg(label, value), ...]), which supports mixing positional and labeled args.
    • Map is encoded as Map([MapEntry(key, value), ...]), which is intended for "map-like" collections (MoonBit map literals like { k: v }).
    • Opaque is intended for "container-like" wrappers that keep a type/tag but otherwise behave structurally through their children.

    Repr::array

    fn Repr::array(children : Array[Repr]) -> Repr

    Construct an Array node from pre-built child Reprs.

    Repr::bool

    fn Repr::bool(x : Bool) -> Repr

    Construct a BoolLit leaf.

    Repr::char

    fn Repr::char(x : Char) -> Repr

    Construct a CharLit leaf.

    Repr::children

    fn Repr::children(self : Repr) -> Array[Repr]

    Child nodes of a Repr node.

    Design notes:
    • Leaves return []; container nodes return their stored children.
    • RecordField/EnumLabeledArg have one child; MapEntry has two.
    • children and with_children form a partial lens for tree rewrites: self.with_children(self.children()) == self.

    Repr::ctor

    fn Repr::ctor(name : String, args : Array[(String?, Repr)]) -> Repr

    Construct an Enum(name, args) node for enum/constructor applications.

    Use None for positional arguments and Some(label) for labeled ones.

    Repr::dict

    fn Repr::dict(contents : Array[(Repr, Repr)]) -> Repr

    Construct a Map node from key/value Repr pairs (for map literals).

    Repr::double

    fn Repr::double(x : Double) -> Repr

    Construct a DoubleLit leaf.

    Repr::float

    fn Repr::float(x : Float) -> Repr

    Construct a FloatLit leaf.

    Repr::int

    fn Repr::int(x : Int) -> Repr

    Construct a Fixnum leaf from an Int.

    Repr::int16

    fn Repr::int16(x : Int16) -> Repr

    Construct a Fixnum leaf from an Int16.

    Repr::int64

    fn Repr::int64(x : Int64) -> Repr

    Construct a Fixnum leaf from an Int64.

    Repr::literal

    fn Repr::literal(value : String) -> Repr

    Construct a Literal(value) leaf (already formatted).

    Repr::omitted

    fn Repr::omitted() -> Repr

    Construct an Omitted marker node.

    Repr::opaque_

    fn Repr::opaque_(name : String, children : Array[Repr]) -> Repr

    Construct an Opaque(name, children) node.

    This is useful for values where you want to keep a tag/type name but still show a structural summary through children (e.g. <Map: {...}>).

    Repr::record

    fn Repr::record(fields : Map[String, Repr]) -> Repr

    Construct a Record node from pre-built child Reprs.

    Repr::shallow

    fn Repr::shallow(self : Repr) -> Repr

    A shallow copy of self containing only its "label" (children replaced).

    This is used by diff/pretty-print when the structure is preserved but children are rendered separately.

    Repr::string

    fn Repr::string(x : String) -> Repr

    Construct a StringLit leaf.

    Repr::traverse

    fn Repr::traverse(self : Repr, f : (Repr) -> Repr) -> Repr

    Traverse a Repr tree and rewrite each node with f.

    f runs after children are traversed (post-order), so it sees rewritten children and can hide fields by rewriting RecordField/EnumLabeledArg nodes.

    Repr::tuple

    fn Repr::tuple(children : Array[Repr]) -> Repr

    Construct a Tuple node from pre-built child Reprs.

    Repr::uint

    fn Repr::uint(x : UInt) -> Repr

    Construct a Fixnum leaf from a UInt.

    Repr::uint16

    fn Repr::uint16(x : UInt16) -> Repr

    Construct a Fixnum leaf from a UInt16.

    Repr::uint64

    fn Repr::uint64(x : UInt64) -> Repr

    Construct a Fixnum leaf from a UInt64.

    Repr::unit

    fn Repr::unit() -> Repr

    Repr::with_children

    fn Repr::with_children(self : Repr, children : Array[Repr]) -> Repr

    Rebuild a Repr node with a new child list (payload is preserved).

    Notes:
    • Leaf nodes ignore children and return themselves.
    • RecordField/EnumLabeledArg expect exactly one child and fall back to RecordField(name, Omitted)/EnumLabeledArg(label, Omitted).
    • MapEntry expects exactly two children and falls back to MapEntry(Omitted, Omitted).
    • This is intentionally not a total inverse of children: invalid arity is clamped to keep the tree well-formed for generic traversal.