Skip to content
Browse files

Move compilation options to the code server, closes #205.

  • Loading branch information...
1 parent 834d0c8 commit 393098ff9ec2d9b3abd927f63668f897b4ea909a @josevalim josevalim committed Apr 10, 2012
Showing with 75 additions and 68 deletions.
  1. +0 −7 include/elixir.hrl
  2. +23 −12 lib/code.ex
  3. +5 −5 lib/elixir/cli.ex
  4. +11 −1 lib/elixir/server.ex
  5. +13 −27 src/elixir_compiler.erl
  6. +1 −1 src/elixir_def.erl
  7. +1 −1 src/elixir_macros.erl
  8. +15 −12 src/elixir_module.erl
  9. +6 −2 test/elixir/kernel/doc_test.exs
View
7 include/elixir.hrl
@@ -8,13 +8,6 @@
-define(ELIXIR_ATOM_CONCAT(Atoms), list_to_atom(lists:concat(Atoms))).
--record(elixir_compile, {
- docs=false, %% when true, attach docs to the defined module
- internal=false, %% when true, skip features in order to compile internal modules
- debug_info=false, %% when true, attach debug info to the defined module
- ignore_module_conflict=false %% when true, module conflicts are ignored
-}).
-
-record(elixir_scope, {
assign=false, %% when true, new variables can be defined in that subtree
guard=false, %% when true, we are inside a guard
View
35 lib/code.ex
@@ -93,23 +93,36 @@ defmodule Code do
end
@doc """
- Compiles `file` and returns a list of tuples where
- the first element is the module name and the second
- one is its binary.
+ Loads the compilation options from the code server.
+ Check compiler_options/1 for more information.
+ """
+ def compiler_options do
+ server_call :compiler_options
+ end
- ## Options
+ @doc """
+ Sets compilation options. Those options are global
+ since they are stored by Elixir's Code Server.
Available options are:
* docs - when true, retain documentation in the compiled module;
* debug_info - when true, retain debug information in the compiled module.
Notice debug information can be used to reconstruct the source code;
+ * ignore_module_conflict - when true, override modules that were already defined;
"""
- def compile_file(file, opts // []) do
- Erlang.elixir_compiler.with_opts opts, fn ->
- Erlang.elixir_compiler.file to_char_list(file)
- end
+ def compiler_options(opts) do
+ server_call { :compiler_options, opts }
+ end
+
+ @doc """
+ Compiles `file` and returns a list of tuples where
+ the first element is the module name and the second
+ one is its binary.
+ """
+ def compile_file(file) do
+ Erlang.elixir_compiler.file to_char_list(file)
end
@doc """
@@ -118,10 +131,8 @@ defmodule Code do
See compile_file/2 for available options.
"""
- def compile_file_to_dir(file, destination, opts // []) do
- Erlang.elixir_compiler.with_opts opts, fn ->
- Erlang.elixir_compiler.file_to_path to_char_list(file), to_char_list(destination)
- end
+ def compile_file_to_dir(file, destination) do
+ Erlang.elixir_compiler.file_to_path to_char_list(file), to_char_list(destination)
end
## Helpers
View
10 lib/elixir/cli.ex
@@ -1,5 +1,5 @@
defrecord Elixir.CLI.Config, commands: [], close: [],
- output: '.', compile: false, halt: true, compile_options: []
+ output: '.', compile: false, halt: true, compiler_options: []
defmodule Elixir.CLI do
import Exception, only: [format_stacktrace: 1]
@@ -147,17 +147,17 @@ defmodule Elixir.CLI do
end
defp process_compiler(['--docs'|t], config) do
- process_compiler t, config.merge_compile_options(docs: true)
+ process_compiler t, config.merge_compiler_options(docs: true)
end
defp process_compiler(['--debug-info'|t], config) do
- process_compiler t, config.merge_compile_options(debug_info: true)
+ process_compiler t, config.merge_compiler_options(debug_info: true)
end
# This option is used internally so we can compile
# Elixir with Elixir without raising module conflicts
defp process_compiler(['--ignore-module-conflict'|t], config) do
- process_compiler t, config.merge_compile_options(ignore_module_conflict: true)
+ process_compiler t, config.merge_compiler_options(ignore_module_conflict: true)
end
defp process_compiler([h|t] = list, config) do
@@ -191,7 +191,7 @@ defmodule Elixir.CLI do
lines = Enum.map lines, File.wildcard(&1)
concat = List.uniq(List.concat(lines))
- Erlang.elixir_compiler.set_opts(config.compile_options)
+ Code.compiler_options(config.compiler_options)
Enum.map concat, fn(file) ->
IO.puts "Compiling #{list_to_binary(file)}"
View
12 lib/elixir/server.ex
@@ -1,6 +1,8 @@
-defrecord Elixir.Server.Config, argv: [], loaded: [], at_exit: []
+defrecord Elixir.Server.Config, argv: [], loaded: [], at_exit: [], compiler_options: []
defmodule Elixir.Server do
+ @moduledoc false
+
use GenServer.Behavior
def start_link do
@@ -23,6 +25,10 @@ defmodule Elixir.Server do
{ :reply, :ok, config.argv(argv) }
end
+ def handle_call({:compiler_options, record}, _from, config) do
+ { :reply, :ok, config.compiler_options(record) }
+ end
+
def handle_call(:loaded, _from, config) do
{ :reply, config.loaded, config }
end
@@ -35,6 +41,10 @@ defmodule Elixir.Server do
{ :reply, config.argv, config }
end
+ def handle_call(:compiler_options, _from, config) do
+ { :reply, config.compiler_options, config }
+ end
+
def handle_call(request, from, config) do
super(request, from, config)
end
View
40 src/elixir_compiler.erl
@@ -1,32 +1,25 @@
-module(elixir_compiler).
--export([with_opts/2, set_opts/1, get_opts/0, file/1, file_to_path/2]).
+-export([get_opts/0, get_opt/1, get_opt/2, file/1, file_to_path/2]).
-export([core/0, module/3, eval_forms/4]).
-include("elixir.hrl").
%% Public API
-%% Set and get compilation options.
+%% Get compilation options.
-with_opts(Opts, Function) ->
- Previous = get(elixir_compiler_opts),
- try
- set_opts(Opts),
- Function()
- after
- put(elixir_compiler_opts, Previous)
- end.
+get_opt(Key) -> get_opt(Key, get_opts()).
-set_opts(Opts) ->
- put(elixir_compiler_opts, #elixir_compile {
- docs=get_value(Opts, docs, false),
- debug_info=get_value(Opts, debug_info, false),
- ignore_module_conflict=get_value(Opts, ignore_module_conflict, false)
- }).
+get_opt(Key, Dict) ->
+ case orddict:find(Key, Dict) of
+ { ok, Value } -> Value;
+ error -> false
+ end.
get_opts() ->
- case get(elixir_compiler_opts) of
- undefined -> #elixir_compile{};
- Else -> Else
+ try
+ gen_server:call(elixir_code_server, compiler_options)
+ catch
+ exit:{ noproc, _ } -> [{internal,true}]
end.
%% Compile a file, return a tuple of module names and binaries.
@@ -80,7 +73,7 @@ eval_forms(Forms, Line, RawModule, Value, S) ->
%% executes the callback in case of success. This automatically
%% handles errors and warnings. Used by this module and elixir_module.
module(Forms, S, Callback) ->
- Options = case (get_opts())#elixir_compile.debug_info of
+ Options = case get_opt(debug_info) of
true -> [debug_info];
_ -> []
end,
@@ -101,20 +94,13 @@ module(Forms, Filename, Options, Callback) ->
%% Invoked from the Makefile.
core() ->
- put(elixir_compiler_opts, #elixir_compile{internal=true}),
[core_file(File) || File <- core_main()],
AllLists = [filelib:wildcard(Wildcard) || Wildcard <- core_list()],
Files = lists:append(AllLists) -- core_main(),
[core_file(File) || File <- '__MAIN__.List':uniq(Files)].
%% HELPERS
-get_value(Keyword, Key, Default) ->
- case orddict:find(Key, Keyword) of
- { ok, Value } -> Value;
- error -> Default
- end.
-
no_auto_import() ->
{ attribute, 0, compile, {
no_auto_import, [
View
2 src/elixir_def.erl
@@ -139,7 +139,7 @@ compile_super(Module, #elixir_scope{function=Function, super=true}) ->
compile_super(_Module, _S) -> [].
compile_docs(Kind, Line, Module, Name, Arity, S) ->
- case (elixir_compiler:get_opts())#elixir_compile.internal of
+ case elixir_compiler:get_opt(internal) of
true -> [];
_ ->
case '__MAIN__.Module':compile_doc(Module, Line, Kind, { Name, Arity }) of
View
2 src/elixir_macros.erl
@@ -28,7 +28,7 @@ translate_macro({ Op, Line, Exprs }, S) when is_list(Exprs),
translate_macro({'@', Line, [{ Name, _, Args }]}, S) ->
assert_module_scope(Line, '@', S),
assert_no_function_scope(Line, '@', S),
- case is_reserved_data(Name) andalso (elixir_compiler:get_opts())#elixir_compile.internal of
+ case is_reserved_data(Name) andalso elixir_compiler:get_opt(internal) of
true ->
{ { nil, Line }, S };
_ ->
View
27 src/elixir_module.erl
@@ -143,14 +143,16 @@ load_form(Forms, S) ->
end
end).
-check_module_availability(Line, Filename, Module, #elixir_compile{ignore_module_conflict=false}) ->
- case code:ensure_loaded(Module) of
- { module, _ } -> elixir_errors:form_error(Line, Filename, ?MODULE, { module_defined, Module });
- { error, _ } -> []
- end;
-
-check_module_availability(_Line, _Filename, _Module, _C) ->
- [].
+check_module_availability(Line, Filename, Module, Compiler) ->
+ case elixir_compiler:get_opt(ignore_module_conflict, Compiler) of
+ false ->
+ case code:ensure_loaded(Module) of
+ { module, _ } -> elixir_errors:form_error(Line, Filename, ?MODULE, { module_defined, Module });
+ { error, _ } -> []
+ end;
+ true ->
+ []
+ end.
% EXTRA FUNCTIONS
@@ -159,11 +161,12 @@ add_info_function(Line, Filename, Module, Export, Functions, Macros, C) ->
case lists:member(Pair, Export) of
true -> elixir_errors:form_error(Line, Filename, ?MODULE, {internal_function_overridden, Pair});
false ->
+ Docs = elixir_compiler:get_opt(docs, C),
Contents = { function, Line, '__info__', 1, [
macros_clause(Line, Macros),
data_clause(Line, Module),
- docs_clause(Line, Module, C),
- moduledoc_clause(Line, Module, C),
+ docs_clause(Line, Module, Docs),
+ moduledoc_clause(Line, Module, Docs),
else_clause(Line)
] },
{ [Pair|Export], [Contents|Functions] }
@@ -173,14 +176,14 @@ macros_clause(Line, Macros) ->
Sorted = lists:sort(Macros),
{ clause, Line, [{ atom, Line, macros }], [], [elixir_tree_helpers:abstract_syntax(Sorted)] }.
-docs_clause(Line, Module, #elixir_compile { docs = true }) ->
+docs_clause(Line, Module, true) ->
Docs = ets:tab2list(docs_table(Module)),
{ clause, Line, [{ atom, Line, docs }], [], [elixir_tree_helpers:abstract_syntax(Docs)] };
docs_clause(Line, _Module, _) ->
{ clause, Line, [{ atom, Line, docs }], [], [{ atom, Line, nil }] }.
-moduledoc_clause(Line, Module, #elixir_compile { docs = true }) ->
+moduledoc_clause(Line, Module, true) ->
Docs = '__MAIN__.Module':read_data(Module, moduledoc),
{ clause, Line, [{ atom, Line, moduledoc }], [], [elixir_tree_helpers:abstract_syntax({ Line, Docs })] };
View
8 test/elixir/kernel/doc_test.exs
@@ -1,22 +1,26 @@
Code.require_file "../../test_helper", __FILE__
defmodule Kernel.DocTest do
- use ExUnit.Case
+ # Since this module is changing the code
+ # server state, we need to run it in sync.
+ use ExUnit.Case, sync: true
test :compiled_docs do
tmp = File.expand_path("../../tmp", __FILE__)
path = File.expand_path("../../fixtures/compiled_with_docs.ex", __FILE__)
try do
:file.make_dir(tmp)
- Code.compile_file_to_dir(path, tmp, docs: true)
+ Code.compiler_options(docs: true)
+ Code.compile_file_to_dir(path, tmp)
Code.prepend_path(tmp)
assert_equal [], CompiledWithDocs.__info__(:data)
expected = [{{:example,1},5,:def,"Some example"},{{:nodoc,0},8,:def,nil}]
assert_equal expected, CompiledWithDocs.__info__(:docs)
assert_equal { 1, "moduledoc" }, CompiledWithDocs.__info__(:moduledoc)
after:
+ Code.compiler_options(docs: false)
:os.cmd('rm -rf #{tmp}')
end
end

0 comments on commit 393098f

Please sign in to comment.
Something went wrong with that request. Please try again.