Source locations and structured errors for text codecs (extracted from jsont)
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

xml,s3: migrate consumers to new Loc API

Pattern matches on Loc.Error use the record shape; Path.index becomes
Path.step (exhaustiveness: unknown steps pretty-print via Path.pp_step
rather than raising). Top-level Xml combinators moved into Xml.Codec;
consumers switch [open Xml] to [open Xml.Codec].

Context accessors: Context.frames (root-to-leaf pairs) /
Context.rev_frames (raw leaf-to-root). Path accessors: Path.steps /
Path.rev_steps, matching the same naming convention.

Cursor.to_context/of_context bridge to Loc.Context via
Path.steps + Context.push; the cursor frame list and the error
context spine remain the same spine.

Loc test renames rev_indices -> rev_steps; XML test 334/334 green.

+30 -16
+13 -8
lib/loc.ml
··· 257 257 let nth ?(meta = Meta.none) n p = Nth (n, meta) :: p 258 258 let mem ?(meta = Meta.none) n p = Mem (n, meta) :: p 259 259 let last = function [] -> None | s :: _ -> Some s 260 - let to_list p = List.rev p 260 + let steps p = List.rev p 261 261 let rev_steps p = p 262 262 263 263 let pp ppf steps = ··· 327 327 let push_mem sort n ctx = push ~sort (Path.Mem n) ctx 328 328 let push_array = push_nth 329 329 let push_object = push_mem 330 + (* Context's raw storage is ROOT-to-LEAF: the push-on-way-up semantics 331 + used by decoders (inner catcher fires first, outer last) means outer 332 + frames are consed LAST, so they sit at the head. Path's raw storage 333 + is LEAF-to-ROOT (cons at head during descent) -- the conventions 334 + mirror each other. Accessors bridge the two. *) 335 + let last_step ctx = match List.rev ctx with [] -> None | f :: _ -> Some f.step 336 + let last_sort ctx = match List.rev ctx with [] -> None | f :: _ -> Some f.sort 337 + let frames ctx = List.map (fun f -> (f.sort, f.step)) ctx 338 + let rev_frames ctx = List.rev (frames ctx) 330 339 331 - let path ctx = List.map (fun f -> f.step) ctx 332 - let last_step = function [] -> None | f :: _ -> Some f.step 333 - let last_sort = function [] -> None | f :: _ -> Some f.sort 334 - 340 + (* Convert Context (root-to-leaf) to Path (leaf-to-root internal). *) 341 + let path ctx = List.rev_map (fun f -> f.step) ctx 335 342 let pp_name = pp_code 336 343 let pp_int ppf i = pp_code ppf (Int.to_string i) 337 344 338 345 let pp ppf ctx = 339 346 let pp_meta ppf meta = 340 - if Meta.is_none meta then () 341 - else Fmt.pf ppf "%a: " pp (Meta.textloc meta) 347 + if Meta.is_none meta then () else Fmt.pf ppf "%a: " pp (Meta.textloc meta) 342 348 in 343 349 let pp_el ppf { sort; step } = 344 350 match step with ··· 390 396 391 397 let kind_to_string k = Format.asprintf "%a" pp_kind k 392 398 let pp_code = pp_code 393 - 394 399 let v ~ctx ~meta kind = { ctx; meta; kind } 395 400 let ctx e = e.ctx 396 401 let meta e = e.meta
+17 -8
lib/loc.mli
··· 215 215 [type step += ...] and {!register_step_printer}. *) 216 216 217 217 type step += 218 - | Mem of string node (** Name-addressed step: object member, XML element 219 - local-name, TOML table name, etc. *) 218 + | Mem of string node 219 + (** Name-addressed step: object member, XML element local-name, TOML 220 + table name, etc. *) 220 221 | Nth of int node (** Index-addressed step: array index, tuple position. *) 221 222 222 223 val register_step_printer : ··· 255 256 val last : t -> step option 256 257 (** [last p] is the innermost step of [p], or [None] if [p] is {!root}. *) 257 258 258 - val to_list : t -> step list 259 - (** [to_list p] is [p]'s steps in {b root-to-leaf} order. Costs one list 259 + val steps : t -> step list 260 + (** [steps p] is [p]'s steps in {b root-to-leaf} order. Costs one list 260 261 reversal. Use when you need a path to match/print from the outside in. *) 261 262 262 263 val rev_steps : t -> step list 263 264 (** [rev_steps p] is [p]'s steps in {b leaf-to-root} order (the raw internal 264 - order). Cheaper than {!to_list}; use when iteration order is 265 - irrelevant. *) 265 + order). Cheaper than {!steps}; use when iteration order is irrelevant. *) 266 266 267 267 val of_string : string -> (t, string) result 268 268 (** [of_string s] parses a dot-separated path like ["a.b.[2].c"]. Only the ··· 313 313 (** [last_step ctx] is the innermost step, or [None] at the root. *) 314 314 315 315 val last_sort : t -> string node option 316 - (** [last_sort ctx] is the sort label of the innermost frame's parent, 317 - or [None] at the root. *) 316 + (** [last_sort ctx] is the sort label of the innermost frame's parent, or 317 + [None] at the root. *) 318 + 319 + val frames : t -> (string node * Path.step) list 320 + (** [frames ctx] is the list of [(sort, step)] frames in root-to-leaf 321 + order. *) 322 + 323 + val rev_frames : t -> (string node * Path.step) list 324 + (** [rev_frames ctx] is the list of [(sort, step)] frames in leaf-to-root 325 + order (the raw internal order). Cheaper than {!frames}; use when 326 + iteration order is irrelevant. *) 318 327 319 328 (** {2:compat Legacy push helpers} *) 320 329