[erlang-questions] compile module from string, containing macro definitions

Chris Newcombe <>
Thu Mar 8 00:48:39 CET 2007


I'm using this code from Ulf Wiger to compile a module from a string:

  http://www.erlang.org/ml-archive/erlang-questions/200607/msg00080.html

It is supposed to support epp-style macros.
However, when I test it with code containing a macro definition I get an error.

My compilation steps, test output and test code are all below.

e.g. This string compiles, loads, and executes correctly:

   "-module(test_module).\n-export([test/1]).\ntest(P1) -> {test_result, P1}.\n"

But adding a single "-define(MY_MACRO, 1).\n"    (which compiles fine
from a file)

   "-module(test_module2).\n-export([test/1]).\n-define(MY_MACRO,
1).\ntest(P1) -> {test_result, P1}.\n",

… compile:forms/2 gives this error:

              {error,
               [{".",
                 [{none,
                   compile,
                   {crash,
                    lint_module,
                    {function_clause,
                     [{erl_lint,
                       function_state,
                       [{tree,
                         {".",attribute},
	...

I've never used syntax_tools/epp_dodger or compile:forms before so any
help would be greatly appreciated!

Thanks,

Chris

> c("/home/cnewcom/backups/ram_file_io_server", [{outdir, "/home/cnewcom/backups/"}]).
{ok,ram_file_io_server}
> c("/home/cnewcom/backups/test_compile_string", [{outdir, "/home/cnewcom/backups/"}]).
{ok,test_compile_string}

> test_compile_string:test_no_macros().
{test_result,p1}

> test_compile_string:test_macros().

=ERROR REPORT==== 7-Mar-2007::15:29:25 ===
Error in process <0.60.0> with exit value:
{{nocatch,{compile_forms_error,{error,[{".",[{none,compile,{crash,lint_module,{function_clause,[{erl_lint,function_state,[{tree,{".",attribute},{attr,{".",3},[],none},{attribute,{".",{atom,3,define}},[{var,{".",3},'MY_MACRO'...

** exited: {{nocatch,
             {compile_forms_error,
              {error,
               [{".",
                 [{none,
                   compile,
                   {crash,
                    lint_module,
                    {function_clause,
                     [{erl_lint,
                       function_state,
                       [{tree,
                         {".",attribute},
                         {attr,{...},...},
                         {attribute,...}},
                        {lint,function,test_module2,[],...}]},
                      {lists,foldl,3},
                      {erl_lint,forms,2},
                      {erl_lint,module,3},
                      {compile,lint_module,1},
                      {compile,'-internal_comp/4-anonymous-1-',2},
                      {compile,fold_comp,3},
                      {compile,internal_comp,...}]}}}]}],
               []}}},
            [{test_compile_string,compile,3},
             {erl_eval,do_apply,5},
             {shell,exprs,6},
             {shell,eval_loop,3}]} **


%% Test code

-module(test_compile_string).
-compile(export_all).

test_no_macros() ->
    ModNameStr  = "test_module",
    Bin = compile(ModNameStr,
                  "-module(" ++ ModNameStr ++
").\n-export([test/1]).\ntest(P1) -> {test_result, P1}.\n",
                  [return_errors, return_warnings, verbose]),
    {module, TestModuleNameAtom}
        = code:load_binary(list_to_atom(ModNameStr), ModNameStr ++ ".erl", Bin),
    {test_result, p1} = TestModuleNameAtom:test(p1).

test_macros() ->
    ModNameStr  = "test_module2",
    _Bin = compile(ModNameStr,
                   "-module(" ++ ModNameStr ++
").\n-export([test/1]).\n-define(MY_MACRO, 1).\ntest(P1) ->
{test_result, P1}.\n",
                   [return_errors, return_warnings, verbose]).

compile(ModuleNameStr, CodeStr, CompileFormsOptions) ->
    Filename = ModuleNameStr ++ ".erl",
    {ok, Fd} = open_ram_file(Filename),
    file:write(Fd, CodeStr),
    file:position(Fd, 0),
    case epp_dodger:parse(Fd) of
	{ok, Tree} ->
	    Forms = revert_tree(Tree),
	    close_ram_file(Fd),

            ModuleNameAtom = list_to_atom(ModuleNameStr),
            %% note: 'binary' is forced as an implicit option, whether
it is provided or not.
            case compile:forms(Forms, CompileFormsOptions) of
                {ok, ModuleNameAtom, Binary} when is_binary(Binary) ->
                    Binary;
                {ok, ModuleNameAtom, Binary, []} when
is_binary(Binary) ->  % empty warnings list
                    Binary;
                {ok, ModuleNameAtom, _, Warnings} ->
                    throw({compile_forms_warnings, Warnings});
                Error ->
                    throw({compile_forms_error, Error})
            end;
	Error ->
	    close_ram_file(Fd),
	    throw({?MODULE, epp, Error})
    end.

open_ram_file(Filename) ->
    ram_file_io_server:start(self(), Filename, [read,write]).

close_ram_file(Fd) ->
    file:close(Fd).

revert_tree(Tree) ->
    [erl_syntax:revert(T) || T <- Tree].




More information about the erlang-questions mailing list