merl vs erl_syntax

Hugo Mills hugo@REDACTED
Sat Feb 26 14:51:40 CET 2022


On Fri, Feb 25, 2022 at 09:19:34PM +0000, Hugo Mills wrote:
>    I'm trying to write some code that compiles a small DSL into erlang
> functions. I found the merl module, but that doesn't seem to have a
> function to output its AST to a file. So I tried writing the AST with
> erl_prettypr:format/2, but it fails.
> 
> The code I'm using to generate this example is:
> 
>         MapperName = 'foo',
>         Mapper = ?Q("@MapperName(Row) -> Row."),
>         io:format("~p~n", [Mapper]),
>         io:format("~ts", [erl_prettypr:format(Mapper, [{encoding, utf8}])]),

[snip]

   I finally tracked down an actual user of merl, in the form of
erlydtl, and it seems that my mistake was in assuming that merl would
compile local values into ASTs. Instead, the value needs to be
converted to a string representation and then passed to ?Q(), so my
example above should have been:

   MapperName = "foo",
   MapperNameTree = ?Q(MapperName),
   Mapper = ?Q("'@MapperNameTree'(Row) -> Row."),

   In other words, the @Bar and _@REDACTED substitutions that merl does
must be ASTs in their own right. This isn't entirely clear from the
documentation (as an aside, I struggled with it in general).

   In the erlydtl example, they use erl_syntax:atom/1 to build the
atom, where I used ?Q().

   Hugo.


> The first io:format/2 in the above code results in this output:
> 
> {tree,function,
>     {attr,9,[],none},
>     {func,foo,[{clause,9,[{var,9,'Row'}],[],[{var,9,'Row'}]}]}}
> 
> The second io:format/2 results in this:
> 
> erl_syntax:type failed on line 734
> Reason: {badarg,foo}
> 
> === Ended at 2022-02-24 18:31:54
> === Location: [{erl_syntax,type,734},
>               {erl_prettypr,lay_2,450},
>               {erl_prettypr,lay_2,605},
>               {erl_prettypr,format,288},
>               {stad_compile,compile_relalg,11},
>               {compile_SUITE,rename,10},
>               {test_server,ts_tc,1783},
>               {test_server,run_test_case_eval1,1292}]
> === === Reason: bad argument: foo
>   in function  erl_syntax:type/1 (erl_syntax.erl, line 734)
>   in call from erl_prettypr:lay_2/2 (erl_prettypr.erl, line 450)
>   in call from erl_prettypr:lay_2/2 (erl_prettypr.erl, line 605)
>   in call from erl_prettypr:format/2 (erl_prettypr.erl, line 288)
>   in call from stad_compile:compile_relalg/1 (src/stad_compile.erl, line 11)
>   in call from compile_SUITE:rename/1 (test/compile_SUITE.erl, line 10)
>   in call from test_server:ts_tc/3 (test_server.erl, line 1783)
>   in call from test_server:run_test_case_eval1/6 (test_server.erl, line 1292)
> 
> 
> If I put the same function ("foo(Row) -> Row.") into a module, and use
> epp:parse_file/3 to read it, I get this fragment of the output:
> 
>      {tree,function,
>          {attr,4,[],none},
>          {func,
>              {tree,atom,{attr,4,[],none},foo},
>              [{tree,clause,
>                   {attr,4,[],none},
>                   {clause,[{var,4,'Row'}],none,[{var,5,'Row'}]}}]}},
> 
>    Note that this output has {tree,atom,_,foo} as the function name,
> where the merl output has simply foo. This suggests to me that merl
> isn't generating the same kind of AST as epp. Are these things
> actually incompatible?  Are they intended (or just known) to be so?
> 
>    What libraries and techniques would people recommend that I use to
> generate erlang code?
> 
>    Hugo.
> 

-- 
Hugo Mills             | ©1973 Unclear Research Ltd
hugo@REDACTED carfax.org.uk |
http://carfax.org.uk/  |
PGP: E2AB1DE4          |


More information about the erlang-questions mailing list