Skip to content

Commit

Permalink
Support for includes
Browse files Browse the repository at this point in the history
  • Loading branch information
dazuma committed Dec 28, 2015
1 parent 74b91c8 commit 1ecb32b
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 12 deletions.
1 change: 0 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ This is a (certainly partial) list of known issues and missing capabilities.

## Preprocessor

* Support file inclusion (P1)
* Check that macro defines work with guard fragments. See examples in elixir/src/elixir_tokenizer.erl (P1)
* Allow defining macros from env variables, e.g. debug (P2)
* Make sure defined_* attributes are properly initialized (P2)
Expand Down
6 changes: 3 additions & 3 deletions lib/erl2ex/convert.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ defmodule Erl2ex.Convert do
alias Erl2ex.Convert.VarRenamer


@auto_registered_attrs [:vsn, :compile, :on_load, :behaviour, :behavior]


def module(erl_module, opts \\ []) do
context = Context.build(erl_module, opts)
forms = erl_module.forms |> Enum.map(&(conv_form(context, &1)))
Expand All @@ -42,9 +45,6 @@ defmodule Erl2ex.Convert do
end


@auto_registered_attrs [:vsn, :compile, :on_load, :behaviour, :behavior]


defp conv_form(context, %ErlFunc{name: name, arity: arity, clauses: clauses, comments: comments}) do
mapped_name = Context.local_function_name(context, name)
spec_info = Context.specs_for_func(context, name)
Expand Down
6 changes: 2 additions & 4 deletions lib/erl2ex/convert/headers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ defmodule Erl2ex.Convert.Headers do
alias Erl2ex.Convert.Context


@import_bitwise_metadata [context: Elixir, import: Bitwise]


def build_header(context, forms) do
header = forms
|> Enum.reduce(%ExHeader{}, &header_check_form/2)
Expand Down Expand Up @@ -42,7 +39,8 @@ defmodule Erl2ex.Convert.Headers do
header_check_expr(elem(expr, 1), header)

defp header_check_expr(expr, header) when is_tuple(expr) and tuple_size(expr) >= 3 do
if elem(expr, 1) == @import_bitwise_metadata do
imported = expr |> elem(1) |> Keyword.get(:import, nil)
if imported == Bitwise do
header = %ExHeader{header | use_bitwise: true}
end
expr
Expand Down
48 changes: 44 additions & 4 deletions lib/erl2ex/erl_parse.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ defmodule Erl2ex.ErlParse do
def from_file(path, opts \\ []) do
path
|> File.read!
|> from_str([{:i, Path.dirname(path)} | opts])
|> from_str([{:cur_file_dir, Path.dirname(path)} | opts])
end


Expand All @@ -42,17 +42,45 @@ defmodule Erl2ex.ErlParse do

defmodule Context do
@moduledoc false
defstruct include_path: []
defstruct include_path: [],
cur_file_dir: nil,
reverse_forms: false
end


defp build_context(opts) do
include_path = opts
|> Keyword.get_values(:include_dir)
|> Enum.uniq
%Context{
include_path: Keyword.get_values(opts, :i)
include_path: include_path,
cur_file_dir: Keyword.get(opts, :cur_file_dir, nil),
reverse_forms: Keyword.get(opts, :reverse_forms, false)
}
end


defp build_opts_for_include(context) do
context.include_path
|> Enum.map(&({:include_dir, &1}))
|> Keyword.put(:reverse_forms, true)
end


defp find_file(context, path) do
include_path = context.include_path
if context.cur_file_dir != nil do
include_path = [context.cur_file_dir | include_path]
end
include_path = [File.cwd!() | include_path]
include_path
|> Enum.find_value(fn dir ->
full_path = Path.expand(path, dir)
if File.regular?(full_path), do: full_path, else: false
end)
end


defp generate_token_group_stream(str) do
{str, 1}
|> Stream.unfold(fn {ch, pos} ->
Expand Down Expand Up @@ -111,7 +139,10 @@ defmodule Erl2ex.ErlParse do
module = form_stream
|> Enum.reduce(%ErlModule{},
fn ({ast, comments}, module) -> add_form(module, ast, comments, context) end)
%ErlModule{module | forms: Enum.reverse(module.forms)}
if not context.reverse_forms do
module = %ErlModule{module | forms: Enum.reverse(module.forms)}
end
module
end


Expand All @@ -127,6 +158,15 @@ defmodule Erl2ex.ErlParse do
}
end

defp add_form(module, {:attribute, _line, :include, path}, _comments, context) do
file_path = find_file(context, path)
opts = build_opts_for_include(context)
included_module = from_file(file_path, opts)
%ErlModule{module |
forms: included_module.forms ++ module.forms
}
end

defp add_form(module, {:attribute, _line, :export, arg}, comments, _context) do
%ErlModule{module |
exports: module.exports ++ arg,
Expand Down
1 change: 1 addition & 0 deletions test/files/files2/include2.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-define(INCLUDE2_CONST, 2).
2 changes: 2 additions & 0 deletions test/files/include1.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-define(INCLUDE1_CONST, 1).
-include("files2/include2.hrl").
1 change: 1 addition & 0 deletions test/files/include3.hrl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-define(INCLUDE3_CONST, 3).
18 changes: 18 additions & 0 deletions test/preprocessor_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,22 @@ defmodule PreprocessorTest do
end


test "File includes injecting forms inline" do
input = """
-include("test/files/include1.hrl").
-include("include3.hrl").
"""

expected = """
@erlmacro_INCLUDE1_CONST 1
@erlmacro_INCLUDE2_CONST 2
@erlmacro_INCLUDE3_CONST 3
"""

assert Erl2ex.convert_str(input, include_dir: "test/files") == expected
end


end

0 comments on commit 1ecb32b

Please sign in to comment.