Skip to content

Feature/moving to rebar #55

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Dec 24, 2011
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/src/*_parser.erl
/test/ebin
/test/tmp
/ebin/*.beam
/ebin/*
/exbin/*.beam
/src/*rl.old
/.eunit/*
Expand Down
17 changes: 0 additions & 17 deletions ebin/elixir.app

This file was deleted.

19 changes: 10 additions & 9 deletions include/elixir.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
% 1) when true, new variables can be defined in that subtree
% 2) when true, we are inside a guard
% 3) when true, don't resolve sub references
% 4) the current method
% 5) the current namespace
% 6) a dict of defined variables and their alias
% 7) a list of all variables defined in a particular assign
% 8) a dict of all variables defined in a particular clause
% 9) a counter with the variables defined
% 10) the current scope filename
% 4) when true, don't add new names. used by try.
% 5) the current method
% 6) the current namespace
% 7) a dict of defined variables and their alias
% 8) a list of all variables defined in a particular assign
% 9) a dict of all variables defined in a particular clause
% 10) a counter with the variables defined
% 11) the current scope filename
%
-record(elixir_scope, {assign=false, guard=false, noref=false, method=[], namespace=[], vars=dict:new(),
temp_vars=[], clause_vars=dict:new(), counter=0, filename="nofile"}).
-record(elixir_scope, {assign=false, guard=false, noref=false, noname=false, method=[],
namespace=[], vars=dict:new(), temp_vars=[], clause_vars=dict:new(), counter=0, filename="nofile"}).
38 changes: 22 additions & 16 deletions lib/elixir/macros.ex
Original file line number Diff line number Diff line change
@@ -1,52 +1,56 @@
ns Elixir::Macros

# Provides an integer division macro according to Erlang semantics.
# Raises an error if one of the arguments is not an integer.
# Can be used in guard tests.
#
# == Examples
#
# 5 div 2 #=> 2
#
defmacro div(left, right), do:
quote(erlang_op :div, unquote(left), unquote(right))

# Provides an 'private' macro for restrict visibility of functions
# Provides a 'private' macro for restrict visibility of functions
#
# == Examples
#
# ns Foo # definition of Foo namespace
#
# private # make function an private
# private # mark following functions as private
#
# def secret do
# :secret
# end
#
# endns # ends namespace here
#
# Foo.secret #=> it will raise 'undef' error
#
defmacro private do
quote(Erlang.elixir_def_method.set_visibility(__NAMESPACE__, :private))
end

# Provides an 'public' macro for restrict visibility of functions
# Provides a 'public' macro for restrict visibility of functions
#
# == Examples
#
# ns Foo # definition of Foo namespace
#
# public # make function an public
# public # mark following functions as public (the default)
#
# def secret do
# :secret
# end
#
# endns # ends namespace here
#
# Foo.secret #=> :secret
#
defmacro public do
quote(Erlang.elixir_def_method.set_visibility(__NAMESPACE__, :public))
end

# Provides an integer division macro according to Erlang semantics.
# Raises an error if one of the arguments is not an integer.
# Can be used in guard tests.
#
# == Examples
#
# 5 div 2 #=> 2
#
defmacro div(left, right), do:
quote(erlang_op :div, unquote(left), unquote(right))

# Provides an integer remainder macro according to Erlang semantics.
# Raises an error if one of the arguments is not an integer.
# Can be used in guard tests.
Expand Down Expand Up @@ -212,7 +216,9 @@ defmacro !(expr) do
)
end

# private
# Mark visibility from here on to private. We can't use the
# private macro because it is defined in this namespace.
Erlang.elixir_def_method.set_visibility(__NAMESPACE__, :private)

# Build if clauses by nesting them recursively.
# For instance, the following clause:
Expand Down
Binary file modified rebar
Binary file not shown.
3 changes: 0 additions & 3 deletions rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
debug_info
]}.

%% make executable landed in bin
{escript_name, "bin/elixir"}.

%% enable verbos for yecc
{yrl_opts, [
{report, false},
Expand Down
58 changes: 46 additions & 12 deletions src/elixir_clauses.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
-module(elixir_clauses).
-export([match/3, assigns/3, assigns_blocks/4, assigns_blocks/5, extract_guards/1]).
-export([match/3, assigns/3, assigns_blocks/4,
try_catch/3, assigns_blocks/5, extract_guards/1]).
-include("elixir.hrl").

% Function for translating assigns.
Expand All @@ -19,11 +20,7 @@ assigns_blocks(Fun, Args, Exprs, Guards, S) ->
{ TGuards, SG } = elixir_translator:translate(Guards, SA#elixir_scope{guard=true}),
{ TExprs, SE } = elixir_translator:translate(Exprs, SG#elixir_scope{guard=false}),

% Properly listify args
case is_list(TArgs) of
true -> FArgs = TArgs;
false -> FArgs = [TArgs]
end,
FArgs = listify(TArgs),

% Properly listify guards
FGuards = case TGuards of
Expand All @@ -33,7 +30,7 @@ assigns_blocks(Fun, Args, Exprs, Guards, S) ->

% Uncompact expressions from the block.
case TExprs of
{ block, _, FExprs } -> [];
[{ block, _, FExprs }] -> [];
_ -> FExprs = TExprs
end,

Expand All @@ -44,13 +41,19 @@ assigns_blocks(Fun, Args, Exprs, Guards, S) ->
extract_guards({ '|', _, [Left, Right] }) -> { Left, [Right] };
extract_guards(Else) -> { Else, [] }.

% Function for translating macros with match style
% clauses like case, try and receive.
% Function for translating macros for try's catch.

match(Line, Clauses, RawS) ->
S = RawS#elixir_scope{clause_vars=dict:new()},
try_catch(Line, Clauses, S) ->
DecoupledClauses = decouple_clauses(Clauses, []),
% Just pass the variable counter forward between each clause.
Transformer = fun(X, Acc) -> translate_each(X, umergec(S, Acc)) end,
lists:mapfoldl(Transformer, S, DecoupledClauses).

% Function for translating macros with match style like case and receive.

match(Line, Clauses, RawS) ->
S = RawS#elixir_scope{clause_vars=dict:new()},
DecoupledClauses = decouple_clauses(handle_else(match, Line, Clauses), []),
case DecoupledClauses of
[DecoupledClause] ->
{ TDecoupledClause, TS } = translate_each(DecoupledClause, S),
Expand Down Expand Up @@ -113,6 +116,20 @@ match(Line, Clauses, RawS) ->
end
end.

% Handle else clauses by moving them under the given Kind.
handle_else(Kind, Line, Clauses) ->
case orddict:find(else, Clauses) of
{ ok, Else } ->
ElseClause = prepend_to_block(Line, {'_', Line, false}, Else),
TClauses = orddict:erase(else, Clauses),
case orddict:find(Kind, TClauses) of
{ ok, KindClauses } ->
orddict:store(Kind, listify(KindClauses) ++ [ElseClause], TClauses);
_ -> [{Kind,ElseClause}]
end;
_ -> Clauses
end.

% Decouple clauses. A clause is a key-value pair. If the value is an array,
% it is broken into several other key-value pairs with the same key. This
% process is only valid for :match and :catch keys (as they are the only
Expand Down Expand Up @@ -145,7 +162,11 @@ translate_each({Key,{block,_,Exprs}}, S) ->
translate_each({Key,Expr}, S) when not is_list(Expr) ->
translate_each({Key,[Expr]}, S);

% Clauses must return at least two elements.
% Do clauses have no conditions. So we are done.
translate_each({Key,Expr}, S) when Key == do ->
elixir_translator:translate(Expr, S);

% Condition clauses must return at least two elements.
translate_each({Key,[Expr]}, S) ->
translate_each({Key,[Expr, nil]}, S);

Expand Down Expand Up @@ -198,3 +219,16 @@ normalize_clause_var(Var, OldValue, ClauseVars) ->

umergec(S1, S2) ->
S1#elixir_scope{counter=S2#elixir_scope.counter}.

%% Listify

listify(Expr) when not is_list(Expr) -> [Expr];
listify(Expr) -> Expr.

%% Prepend a given expression to a block.

prepend_to_block(_Line, Expr, { block, Line, Args }) ->
{ block, Line, [Expr|Args] };

prepend_to_block(Line, Expr, Args) ->
{ block, Line, [Expr, Args] }.
23 changes: 14 additions & 9 deletions src/elixir_parser.yrl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Nonterminals
expr block_expr curly_expr call_expr max_expr base_expr
matched_expr matched_op_expr unmatched_expr unmatched_op_expr
comma_separator kv_eol
match_op add_op mult_op unary_op addadd_op multmult_op pipe_op
match_op add_op mult_op unary_op addadd_op multmult_op pipe_op arrow_op
andand_op oror_op andalso_op orelse_op and_op or_op comp_expr_op
open_paren close_paren
open_bracket close_bracket
Expand All @@ -27,7 +27,7 @@ Terminals
number signed_number atom ref string
call_op special_op dot_call_op comp_op
'not' 'and' 'or' 'xor' 'andalso' 'orelse'
'=' '+' '-' '*' '/' '++' '--' '**' '//'
'=' '+' '-' '*' '/' '++' '--' '**' '//' '<-'
'(' ')' eol ',' '[' ']' '|' '{' '}' '.' '::'
'&&' '||' '!'
.
Expand All @@ -38,13 +38,13 @@ Right 10 match_op.
Left 20 do.
Left 30 ','. % Solve nested call_args conflicts
Left 40 pipe_op.
Left 50 oror_op.
Left 60 andand_op.
Left 70 orelse_op.
Left 80 andalso_op.
Left 90 or_op.
Left 100 and_op.
% Right 90 right_op.
Right 50 arrow_op.
Left 60 oror_op.
Left 70 andand_op.
Left 80 orelse_op.
Left 90 andalso_op.
Left 100 or_op.
Left 110 and_op.
Left 150 comp_expr_op.
Left 160 add_op.
Left 170 mult_op.
Expand Down Expand Up @@ -88,6 +88,7 @@ unmatched_op_expr -> expr orelse_op expr : build_op('$2', '$1', '$3').
unmatched_op_expr -> expr and_op expr : build_op('$2', '$1', '$3').
unmatched_op_expr -> expr or_op expr : build_op('$2', '$1', '$3').
unmatched_op_expr -> expr pipe_op expr : build_op('$2', '$1', '$3').
unmatched_op_expr -> expr arrow_op expr : build_op('$2', '$1', '$3').
unmatched_op_expr -> expr comp_expr_op expr : build_expr_op('$2', '$1', '$3').
unmatched_op_expr -> unary_op expr : build_unary_op('$1', '$2').
unmatched_op_expr -> special_op expr : build_special_op('$1', '$2').
Expand All @@ -105,6 +106,7 @@ matched_op_expr -> matched_expr orelse_op matched_expr : build_op('$2', '$1', '$
matched_op_expr -> matched_expr and_op matched_expr : build_op('$2', '$1', '$3').
matched_op_expr -> matched_expr or_op matched_expr : build_op('$2', '$1', '$3').
matched_op_expr -> matched_expr pipe_op matched_expr : build_op('$2', '$1', '$3').
matched_op_expr -> matched_expr arrow_op matched_expr : build_op('$2', '$1', '$3').
matched_op_expr -> matched_expr comp_expr_op matched_expr : build_expr_op('$2', '$1', '$3').
matched_op_expr -> unary_op matched_expr : build_unary_op('$1', '$2').
matched_op_expr -> special_op matched_expr : build_special_op('$1', '$2').
Expand Down Expand Up @@ -223,6 +225,9 @@ or_op -> 'xor' eol : '$1'.
pipe_op -> '|' : '$1'.
pipe_op -> '|' eol : '$1'.

arrow_op -> '<-' : '$1'.
arrow_op -> '<-' eol : '$1'.

comp_expr_op -> comp_op : '$1'.
comp_expr_op -> comp_op eol : '$1'.

Expand Down
15 changes: 10 additions & 5 deletions src/elixir_tokenizer.erl
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ tokenize(Line, [$.,T1,T2|Rest], Tokens) when T1 == $& andalso T2 == $&;
T1 == $= andalso T2 == $=; T1 == $! andalso T2 == $=;
T1 == $< andalso T2 == $=; T1 == $> andalso T2 == $=;
T1 == $+ andalso T2 == $+; T1 == $- andalso T2 == $-;
T1 == $* andalso T2 == $*; T1 == $/ andalso T2 == $/ ->
T1 == $* andalso T2 == $*; T1 == $/ andalso T2 == $/;
T1 == $< andalso T2 == $- ->
tokenize(Line, Rest, [tokenize_call_identifier(identifier, Line, list_to_atom([T1,T2]), Rest),{'.',Line}|Tokens]);

% ## Single Token Operators
Expand Down Expand Up @@ -104,7 +105,8 @@ tokenize(Line, [$:,T1,T2|Rest], Tokens) when T1 == $& andalso T2 == $&;
T1 == $= andalso T2 == $=; T1 == $! andalso T2 == $=;
T1 == $< andalso T2 == $=; T1 == $> andalso T2 == $=;
T1 == $+ andalso T2 == $+; T1 == $- andalso T2 == $-;
T1 == $* andalso T2 == $*; T1 == $/ andalso T2 == $/ ->
T1 == $* andalso T2 == $*; T1 == $/ andalso T2 == $/;
T1 == $< andalso T2 == $- ->
tokenize(Line, Rest, [{atom,Line,[list_to_atom([T1,T2])]}|Tokens]);

% ## Single Token Operators
Expand All @@ -130,7 +132,8 @@ tokenize(Line, [T1,T2,$:|Rest], Tokens) when T1 == $& andalso T2 == $&;
T1 == $= andalso T2 == $=; T1 == $! andalso T2 == $=;
T1 == $< andalso T2 == $=; T1 == $> andalso T2 == $=;
T1 == $+ andalso T2 == $+; T1 == $- andalso T2 == $-;
T1 == $* andalso T2 == $*; T1 == $/ andalso T2 == $/ ->
T1 == $* andalso T2 == $*; T1 == $/ andalso T2 == $/;
T1 == $< andalso T2 == $- ->
tokenize(Line, Rest, [{kv_identifier,Line,list_to_atom([T1,T2])}|Tokens]);

% ## Single Token Operators
Expand All @@ -156,7 +159,8 @@ tokenize(Line, [T1,T2,$(|Rest], Tokens) when T1 == $& andalso T2 == $&;
T1 == $= andalso T2 == $=; T1 == $! andalso T2 == $=;
T1 == $< andalso T2 == $=; T1 == $> andalso T2 == $=;
T1 == $+ andalso T2 == $+; T1 == $- andalso T2 == $-;
T1 == $* andalso T2 == $*; T1 == $/ andalso T2 == $/ ->
T1 == $* andalso T2 == $*; T1 == $/ andalso T2 == $/;
T1 == $< andalso T2 == $- ->
tokenize(Line, [$(|Rest], [{call_op,Line,list_to_atom([T1,T2])}|Tokens]);

% ## Single Token Operators
Expand Down Expand Up @@ -191,7 +195,8 @@ tokenize(Line, [T1,T2,T3|Rest], Tokens) when
% ## Comparison two token operators
tokenize(Line, [T1,T2|Rest], Tokens) when
T1 == $= andalso T2 == $=; T1 == $! andalso T2 == $=;
T1 == $< andalso T2 == $=; T1 == $> andalso T2 == $= ->
T1 == $< andalso T2 == $=; T1 == $> andalso T2 == $=;
T1 == $< andalso T2 == $- ->
tokenize(Line, Rest, [{comp_op, Line, list_to_atom([T1,T2])}|Tokens]);

% ## Two Token Operators
Expand Down
Loading