fakenickels / fakenickels-blog

fakenickels - Hi, I'm fakenickels
https://blog.fakenickels.dev
6 stars 1 forks source link

My journey on building a reasonable codemod template, Friday 20 of November: How to destruct a piece of ReasonML into a mappable AST to input in the mapper #18

Open fakenickels opened 3 years ago

fakenickels commented 3 years ago

Previous post here

ah yes eme ellie devloper

ah yes eme ellie devloper

Just some tips today

How to destruct a piece of ReasonML into a mappable AST to input in the mapper

I know there is a https://astexplorer.net for Reason but it is not very useful since it actually outputs just a JSON and you can't consume that directly in Reason.


Turn Reason into OCaml

$ echo "Platform.os() === Android" | refmt -p ml
;;(Platform.os ()) == Android

Copy that expression and remove the ;; before giving to the next command ppx_tools/dumpast and it'll output the AST representation

$ ocamlfind ppx_tools/dumpast -e "(Platform.os ()) == Android"
(Platform.os ()) == Android
==>
{pexp_desc =
  Pexp_apply ({pexp_desc = Pexp_ident {txt = Lident "=="}},
   [(Nolabel,
     {pexp_desc =
       Pexp_apply
        ({pexp_desc = Pexp_ident {txt = Ldot (Lident "Platform", "os")}},
        [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})])});
    (Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "Android"}, None)})])}
=========

Now remove the weird ==> and the other one at the bottom ========= and you can convert the rest straight back to Reason

$ '{pexp_desc = Pexp_apply ({pexp_desc = Pexp_ident {txt = Lident "=="}}, [(Nolabel, {pexp_desc = Pexp_apply ({pexp_desc = Pexp_ident {txt = Ldot (Lident "Platform", "os")}}, [(Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "()"}, None)})])}); (Nolabel, {pexp_desc = Pexp_construct ({txt = Lident "Android"}, None)})])}' | refmt --parse ml

output

{
  pexp_desc:
    [@implicit_arity]
    Pexp_apply(
      {pexp_desc: Pexp_ident({txt: Lident("==")})},
      [
        (
          Nolabel,
          {
            pexp_desc:
              [@implicit_arity]
              Pexp_apply(
                {
                  pexp_desc:
                    Pexp_ident({
                      txt: [@implicit_arity] Ldot(Lident("Platform"), "os"),
                    }),
                },
                [
                  (
                    Nolabel,
                    {
                      pexp_desc:
                        [@implicit_arity]
                        Pexp_construct({txt: Lident("()")}, None),
                    },
                  ),
                ],
              ),
          },
        ),
        (
          Nolabel,
          {
            pexp_desc:
              [@implicit_arity]
              Pexp_construct({txt: Lident("Android")}, None),
          },
        ),
      ],
    ),
};

you can go ahead and remove the [@implicit_arity] things from there, they are just metadata used by refmt for disambiguation between the syntaxes.

And that's it! That's a totally valid record you can use inside a default_mapper in a new pattern match case like here

Yeah I inlined the whole thing, I'm that lazy for finding a better way and I never remember how to use multiline strings in bash.

I'm no Bash wizard probably someone can create a one-liner to handle all of that at once or even better.