Skip to content

Interest in effects to replace ~loc #635

@N1ark

Description

@N1ark

Hi! I started using ppxlib quite heavily recently, and it's super useful, thanks! However, I find that having to pass a ~loc to all constructors / having to always have a loc variable in scope is a bit tedious, and sometimes leads to overly verbose code.

In my ppx deriver I defined a tiny wrapper around all constructors that take in a ~loc, and defined a simple algebraic effect to instead store the location without having to make it explicit. The implementation is just this:

open Ppxlib
open Ast_builder.Default

type _ Effect.t += Get_loc : location Effect.t

let with_loc (loc : location) f =
  let open Effect.Deep in
  try f () with effect Get_loc, k -> continue k loc

let get_loc () = Effect.perform Get_loc

let ( let@ ) = ( @@ )

(* Override anything we need *)
let pexp_ident x = pexp_ident ~loc:(get_loc ()) x
let ppat_any () = ppat_any ~loc:(get_loc ())
(* etc ... *)

(* Usage is simple! *)
let@ () = with_loc my_loc in
let my_ident = pexp_ident (Lident "foo") in ...

This allows me to write the ppx without having to worry about locations: I just wrap the top-most element with the location i care about, and optionally re-wrap sub-items if i want a more precise location there. I still need a loc in scope when using the ppx, but that just requires a let loc = get_loc ()

Is this something that would be of interest to other users of ppxlib? I would be happy to open a PR and add this as an optional replacement to Ast_builder.Default. Or does this go completely against the intended use of locations? At least in our codebase this has proven quite useful :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions