debug

experimental
debug
diff
pretty-print
moon add moonbit-community/debug@0.1.3
Download zip
Version
0.1.3
License
Apache-2.0
Last updated
7 months ago
Downloads
1K
README

#moonbit-community/debug

An experimental Debug + diff + pretty-printer library for MoonBit. We plan to add this to the standard library when it is more mature.

It provides:

  • A Debug trait that turns values into a structural Repr
  • A tree-based diff (ReprDelta) with configurable float tolerance
  • A pretty printer for both Repr and ReprDelta (optionally with ANSI marks)
  • A binary to auto-generate Debug implementations for your types

Goals:

  • A way to debug values and show the diff, with pretty-printing

  • Replacing Some Roles of Show and ToJson

    The current Show trait produces output that is not suitable for debugging, as it lacks indentation and line breaks. The ToJson trait produces JSON, which is more readable with @json.inspect but not ideal for MoonBit-specific types (e.g., enums). It can also confuse users who expect ToJson to produce structured data rather than a debug representation.

    With the introduction of Debug , the Show trait can focus on producing specialized output (such as Json::stringify , String::to_string , etc.), and derive(Show) will be deprecated.

Non-goals:

  • Deserializing from Repr back to original values
  • Output a valid moonbit code representation

#Project structure

The current pre-build command design forces us to separate the build script (written in MoonBit) into its own module and use a local binary dependency to invoke it. Therefore, the project is structured as follows:

  • debug/: the main library module
  • auto_derive/: the build script module that generates Debug implementations
  • auto_derive_example/: an example module that uses the debug library and build script to generate code

#Quickstart

Run the small demo:

moon run cmd/main

In another package, import this module in moon.pkg.json :

{ "import": [{ "path": "moonbit-community/debug", "alias": "dbg" }] }

Then call:

///|
fn show_examples {
println(@dbg.pretty_print([1, 2, 3]))
println(@dbg.pretty_print_diff(Some(1), Some(2)))
}

#Implement Debug for your own types

Use record , ctor , array , and friends to build a Repr :

///|
struct Person {
name : String
age : Int
}

///|
pub impl @dbg.Debug for Person with debug(self) {
@dbg.record([("name", @dbg.debug(self.name)), ("age", @dbg.debug(self.age))])
}

#Auto deriving Debug

To automatically generate Debug implementations for your types:

  1. add moonbit-community/debug_deriving as a binary dependency in your moon.mod.json

  2. add a pre-build command that runs the debug_deriving binary, for example:

{ "pre-build": [ { "command": "$mod_dir/.mooncakes/moonbit-community/debug_deriving/debug_deriving $input $output", "input": "input.mbt", "output": "output.mbt" } ] }

  1. in your input.mbt, add #debug.derive attribute to your types:

///|
#debugderive
struct Pos(Int, Int)

#Options

All options are passed directly as optional parameters to functions:

#Pretty printing

  • max_depth?: optional depth limit; omit for default (4), or pass max_depth=n to prune
  • threshold?: controls single-line vs multi-line rendering (default: 8)
  • use_ansi?: enables +/- with ANSI colors in diffs (default: true)

#Diffing

  • max_relative_error?: float tolerance for comparing Double values

See docs_test.mbt and examples_test.mbt for runnable, snapshot-based examples.

#Doctest examples

///|
test {
inspect(pretty_print([1, 2, 3]), content="[1, 2, 3]")
inspect(
pretty_print_diff(1, 2, compact_threshold=100, use_ansi=false),
content="-1 +2",
)
}

#
Repr

Re-export Repr and smart constructors from @repr. Use Repr::int(x), Repr::string(s), etc. to construct values.

#
ReprDelta

Diffing (forwarded to @diff).

#
Debug

pub(open) trait Debug {
debug(Self) ->
Repr

}

Convert a value into a structural Repr for pretty-printing and diffing.

Once a type implements this trait:
  • debug(x) builds a Repr
  • pretty_print(x, ...), diff(x, ...), and pretty_print_diff(x, ...) work out of the box
impl Debug for Int16
impl Debug for Int64
impl Debug for UInt16
impl Debug for UInt64
impl Debug for Float
impl Debug for Double
impl Debug for String
impl Debug for Option[T]
impl Debug for Result[T, E]
impl Debug for FixedArray[T]
impl Debug for ReadOnlyArray[T]
impl Debug for Bytes
impl Debug for Ref[T]
impl Debug for Array[T]
impl Debug for Iter2[A, B]
impl Debug for Map[K, V]
impl Debug for Tuple2[A, B]
impl Debug for Tuple3[A, B, C]
impl Debug for Tuple4[A, B, C, D]
impl Debug for Tuple5[A, B, C, D, E]
impl Debug for Tuple6[A, B, C, D, E, F]
impl Debug for Tuple7[A, B, C, D, E, F, G]
impl Debug for Tuple8[A, B, C, D, E, F, G, H]
impl Debug for Tuple9[A, B, C, D, E, F, G, H, I]
impl Debug for Tuple10[A, B, C, D, E, F, G, H, I, J]
impl Debug for Tuple11[A, B, C, D, E, F, G, H, I, J, K]
impl Debug for Tuple12[A, B, C, D, E, F, G, H, I, J, K, L]
impl Debug for Tuple13[A, B, C, D, E, F, G, H, I, J, K, L, M]
impl Debug for Tuple14[A, B, C, D, E, F, G, H, I, J, K, L, M, N]
impl Debug for Tuple15[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]
impl Debug for Tuple16[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P]
impl Debug for Tuple17[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q]
impl Debug for Tuple18[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R]
impl Debug for Tuple19[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S]
impl Debug for Tuple20[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T]
impl Debug for Tuple21[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U]
impl Debug for Tuple22[A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V]
impl Debug for BytesView
impl Debug for StringView

#
debug

Build a Repr for any T that implements Debug.

#
diff

fn[T : Debug] diff(x : T, y : T, max_relative_error? : Double) ->
ReprDelta

Diff two values (by diffing their Repr).

Optional parameters:
  • max_relative_error?: relative-error tolerance used for DoubleLit comparisons. Larger values make floats less likely to be considered different. Defaults to 1e-12 when None.

#
diff_repr

Diff two Repr values.

Optional parameters:
  • max_relative_error?: relative-error tolerance for DoubleLit.
    • When None, the default is 1e-12.
    • Larger tolerances make floats less likely to be reported as different.

#
pretty_print

fn[T : Debug] pretty_print(x : T, max_depth? : Int, compact_threshold? : Int, use_ansi? : Bool) -> String

Pretty-print a value.

Optional parameters:
  • max_depth?: maximum expansion depth; deeper subtrees are replaced with .... Defaults to 4 when None.
  • compact_threshold?: compact-vs-multiline layout threshold. The printer uses a heuristic “size” for nodes; when the structure is deemed small enough under this threshold, it is kept on one line, otherwise it is broken into multiple lines. Larger values prefer single-line output. Defaults to 80 when None.
  • use_ansi?: whether to emit ANSI color escape codes. Defaults to true when None.

#
pretty_print_delta

fn pretty_print_delta(d :
ReprDelta
, max_depth? : Int, compact_threshold? : Int, use_ansi? : Bool) -> String

Pretty-print a ReprDelta.

Optional parameters:
  • max_depth?: maximum expansion depth; deeper subtrees are folded. Defaults to 4 when None. Values <= 0 are treated as 1.
  • compact_threshold?: compact-vs-multiline layout threshold (heuristic one-line vs multiline). Larger values prefer single-line output. Defaults to 80 when None.
  • use_ansi?: whether to emit ANSI color escape codes (for +/- markers). Defaults to true when None.

#
pretty_print_diff

fn[T : Debug] pretty_print_diff(x : T, y : T, max_depth? : Int, compact_threshold? : Int, use_ansi? : Bool, max_relative_error? : Double) -> String

Pretty-print the diff between two values.

Optional parameters:
  • max_depth?: maximum expansion depth; defaults to 4 when None.
  • compact_threshold?: compact-vs-multiline layout threshold (heuristic one-line vs multiline). Larger values prefer single-line output. Defaults to 80 when None.
  • use_ansi?: whether to emit ANSI color escape codes; defaults to true when None.
  • max_relative_error?: float tolerance for DoubleLit; defaults to 1e-12 when None.

#
pretty_print_repr

fn pretty_print_repr(r :
Repr
, max_depth? : Int, compact_threshold? : Int, use_ansi? : Bool) -> String

Pretty-print a Repr.

Optional parameters:
  • max_depth?: maximum expansion depth; deeper subtrees are replaced with .... Defaults to 4 when None. Values <= 0 are treated as 1.
  • compact_threshold?: compact-vs-multiline layout threshold. The printer uses a heuristic “size” for nodes; when the structure is deemed small enough under this threshold, it is kept on one line, otherwise it is broken into multiple lines. Larger values prefer single-line output. Defaults to 80 when None.
  • use_ansi?: whether to emit ANSI color escape codes. Defaults to true when None.