experimental/sexp_diff

  Source   Edit

Types

IdxCostMap = Table[(int, int), int]
  Source   Edit
SexpMismatch = object
  path*: SexpPath            ## Full path for the mismatched
  case kind*: SexpMismatchKind
  of smMissingKey:
      key*: string           ## Key missing in the input data
    
  of smDifferentLiteral, smKindMismatch, smArrayLen, smDifferentSymbol:
      expected*, found*: SexpNode ## 'expected X' but 'found Y' error messages
      arraydiff*: tuple[target, input: seq[int]] ## For comparison of the
                                                 ## lists keys - indices of the non-field elements.
    
  
Single S-expression mismatch   Source   Edit
SexpMismatchKind = enum
  smMissingKey,             ## Input data has no `:key` that was present in expected
  smDifferentLiteral,       ## Target has different literal values from the expected
  smDifferentSymbol,        ## Target has different symbol at position
  smArrayLen,               ## Mismatched array len
  smKindMismatch ## Different kinds of nodes - expected string but found
                 ## int for example
Possible kinds of the mismatches   Source   Edit
SexpPath = seq[SexpPathPart]
  Source   Edit

Procs

proc describeDiff(diff: seq[SexpMismatch]; conf: DiffFormatConf): ColText {.
    ...raises: [ValueError, Exception], tags: [RootEffect].}
Generate colortext description of the S-expression mismatch diff   Source   Edit
proc diff(target, input: SexpNode): seq[SexpMismatch] {....raises: [KeyError],
    tags: [].}

Recursively iterate over target and input trees, find all mismatches.

Comparison rules:

  • _ in expected matches to anything
  • Excess fields in input are discarded
  • Missing fields in target are treated as errors
  • List with keys are compared in two passes - only :key to :key between two lists - in unordered manner. Then all remaining elements are processed in the order of their appearance.
  • Literals and kinds are compared directly with ==
  Source   Edit
func mismatch(path: SexpPath; key: string): SexpMismatch {....raises: [], tags: [].}
Create missing key mismatch   Source   Edit
func sdiffPart(index: int): SexpPathPart {....raises: [], tags: [].}
Create single S-expression index part   Source   Edit
func sdiffPart(key: string): SexpPathPart {....raises: [], tags: [].}
Create single S-expression key path part   Source   Edit
proc stableMatch(lhsLen, rhsLen: int; weight: proc (a, b: int): int;
                 order: SortOrder = SortOrder.Ascending): tuple[
    lhsIgnore, rhsIgnore: seq[int],
    map: seq[tuple[pair: (int, int), cost: int]]] {.
    ...raises: [KeyError, Exception], tags: [RootEffect].}
Do a weighted matching of the items in lhs and rhs sequences using weight function. Return most cost-effective matching elements.
  • lhsLen and rhsLen lists number of the elements in each input sequence
  • weight - comparison proc that returns match score between two items as position a and b.
  • order - comparison ordering. If it is Ascending higher matching cost is consdered better and replaces previous mappings. If Descending prefer lower matching cost instead

For generating mapping of two sequences make weight function a closure and let it retrieve values as needed.

  Source   Edit
proc toLine(s: SexpNode; sortfield: bool = false): ColText {....raises: [],
    tags: [].}
Generate colored formatting of the S-expression.
  • sortfield - order SKeyword entries in lists by the key name
  Source   Edit

Exports

$, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, $, toString, toString, toString