Skip to content

Commit

Permalink
Basic unparameterized alias support.
Browse files Browse the repository at this point in the history
A type with a single untagged member and no type parameters on the
left-hand side will now be interpretted as an alias.  Makes reusing
things like records and tuples a bit easier.
  • Loading branch information
j14159 committed Sep 30, 2018
1 parent d802668 commit 36ee000
Show file tree
Hide file tree
Showing 7 changed files with 417 additions and 103 deletions.
5 changes: 5 additions & 0 deletions src/alpaca.erl
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,11 @@ list_item_expression_test() ->
?assertMatch(Matrix, M:getMatrix({})),
pd(M).

future_ast_test() ->
Files = ["test_files/future_ast.alp"],
[M] = compile_and_load(Files, [test]),
pd(M).

destructuring_test() ->
Files = ["test_files/destructuring.alp"],
[M] = compile_and_load(Files, [test]),
Expand Down
8 changes: 8 additions & 0 deletions src/alpaca_ast.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,14 @@
}).
-type alpaca_type() :: #alpaca_type{}.

-record(alpaca_type_alias, {
line=0 :: integer(),
module=undefined :: atom(),
name={type_name, -1, ""} :: alpaca_type_name(),
target=undefined :: alpaca_types()
}).
-type alpaca_type_alias() :: #alpaca_type{}.

-record(alpaca_type_apply, {
type=undefined :: typ(),
name=#type_constructor{} :: alpaca_constructor_name(),
Expand Down
51 changes: 27 additions & 24 deletions src/alpaca_ast_gen.erl
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ parse_module([], #alpaca_module{name=no_module}=M) ->
parse_error(M, 1, no_module);
parse_module([], #alpaca_module{name=N, functions=Funs, types=Ts}=M) ->
OrderedFuns = group_funs(Funs, N),
TypesWithModule = [T#alpaca_type{module=N} || T <- Ts],
F = fun(#alpaca_type{}=T) -> T#alpaca_type{module=N};
(#alpaca_type_alias{}=T) -> T#alpaca_type_alias{module=N}
end,
TypesWithModule = lists:map(F, Ts),
M#alpaca_module{functions=OrderedFuns, types = TypesWithModule};
parse_module([{break, _}], Mod) ->
parse_module([], Mod);
Expand Down Expand Up @@ -430,6 +433,8 @@ update_memo(#alpaca_module{functions=Funs}=M, #alpaca_binding{} = Def) ->
M#alpaca_module{functions=[Def|Funs]};
update_memo(#alpaca_module{types=Ts}=M, #alpaca_type{}=T) ->
M#alpaca_module{types=[T|Ts]};
update_memo(#alpaca_module{types=Ts}=M, #alpaca_type_alias{}=Alias) ->
M#alpaca_module{types=[Alias|Ts]};
update_memo(#alpaca_module{tests=Tests}=M, #alpaca_test{}=T) ->
M#alpaca_module{tests=[T|Tests]};
update_memo(M, #alpaca_comment{}) ->
Expand Down Expand Up @@ -2044,24 +2049,22 @@ type_expr_in_type_declaration_test() ->
?assertMatch({error, _}, test_parse("type a not_a_var = A not_a_var")).


ambiguous_type_expressions_test() ->
?assertMatch({ok, #alpaca_type{
name={type_name,1,<<"my_map">>},
vars=[],
members=[{t_map,
ambiguous_type_expressions_test_() ->
[?_assertMatch({ok, #alpaca_type_alias{
name={type_name,1,<<"my_map">>},
target={t_map,
#alpaca_type{
name={type_name,1,<<"foo">>},
vars=[],
members=[]},
t_atom}]}},
test_parse("type my_map = map foo atom")),
?assertMatch({error, _}, test_parse("type my_map = map foo bar atom")),
?assertMatch({error, _}, test_parse("type my_list = list foo atom")),
?assertMatch({error, _}, test_parse("type my_pid = pid foo atom")),
?assertMatch({ok, #alpaca_type{
name={type_name,1,<<"my_type">>},
vars=[],
members=[#alpaca_type{
t_atom}}},
test_parse("type my_map = map foo atom")),
?_assertMatch({error, _}, test_parse("type my_map = map foo bar atom")),
?_assertMatch({error, _}, test_parse("type my_list = list foo atom")),
?_assertMatch({error, _}, test_parse("type my_pid = pid foo atom")),
?_assertMatch({ok, #alpaca_type_alias{
name={type_name,1,<<"my_type">>},
target=#alpaca_type{
name={type_name,1,<<"foo">>},
vars=[{_, #alpaca_type{
name={type_name, _, <<"bar">>}}},
Expand All @@ -2074,19 +2077,18 @@ ambiguous_type_expressions_test() ->
#alpaca_type{
name={type_name, 1, <<"baz">>},
vars=[],
members=[]}]}]}},
test_parse("type my_type = foo bar baz")),
?assertMatch({ok, #alpaca_type{
name={type_name, 1, <<"my_type">>},
vars=[],
members=[#alpaca_type{
members=[]}]}}},
test_parse("type my_type = foo bar baz")),
?_assertMatch({ok, #alpaca_type_alias{
name={type_name, 1, <<"my_type">>},
target=#alpaca_type{
name={type_name, 1, <<"foo">>},
vars=[{_,
#alpaca_type{
name={type_name, _, <<"bar">>},
vars=[{_,
#alpaca_type{
name={_, _, <<"baz">>}}}]}}],
name={_, _, <<"baz">>}}}]}}],
members=
[#alpaca_type{
name={type_name, 1, <<"bar">>},
Expand All @@ -2095,8 +2097,9 @@ ambiguous_type_expressions_test() ->
[#alpaca_type{
name={type_name, 1, <<"baz">>},
vars=[],
members=[]}]}]}]}},
test_parse("type my_type = foo (bar baz)")).
members=[]}]}]}}},
test_parse("type my_type = foo (bar baz)"))
].



Expand Down
18 changes: 13 additions & 5 deletions src/alpaca_parser.yrl
Original file line number Diff line number Diff line change
Expand Up @@ -310,11 +310,19 @@ type -> type_declare poly_type_decl assign type_members :
'$2'#alpaca_type{members='$4'}.
type -> type_declare symbol assign type_members :
{L, N} = symbol_line_name('$2'),
#alpaca_type{
line=L,
name={type_name, L, N},
vars=[],
members='$4'}.
%% Breaking this out to reduce repetition:
MakeType = fun() ->
#alpaca_type{
line=L,
name={type_name, L, N},
vars=[],
members='$4'}
end,
case '$4' of
[#alpaca_constructor{}] -> MakeType();
[M] -> #alpaca_type_alias{line=L, name={type_name, L, N}, target=M};
_ -> MakeType()
end.

poly_type_decl -> symbol type_vars :
{L, N} = symbol_line_name('$1'),
Expand Down
9 changes: 7 additions & 2 deletions src/alpaca_printer.erl
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,10 @@ format_type_def(#alpaca_type{vars=Vars, name={_, _, Name}, members=Members}) ->
format_type_arg(Other)
end,
Members))),
<<"type ", Name/binary, TypeVars/binary, " = ", MemberRepr/binary>>.
<<"type ", Name/binary, TypeVars/binary, " = ", MemberRepr/binary>>;
format_type_def(#alpaca_type_alias{name={_, _, Name}, target=T}) ->
TargetRepr = format_type_arg(T),
<<"type ", Name/binary, " = ", TargetRepr/binary>>.

format_module(#alpaca_module{functions=Funs,
name=Name,
Expand Down Expand Up @@ -222,6 +225,8 @@ format_module(#alpaca_module{functions=Funs,

{PublicTypes, PrivateTypes} = lists:partition(
fun(#alpaca_type{name={_, _, TName}}) ->
lists:member(TName, TypeExports);
(#alpaca_type_alias{name={_, _, TName}}) ->
lists:member(TName, TypeExports)
end,
ModTypes),
Expand Down Expand Up @@ -368,7 +373,7 @@ format_module_test() ->
"---------------------\n\n"
"val hello : string\n\n"
"val add : fn int int -> int\n\n"
"val pair : fn int -> my_tuple\n\n"
"val pair : fn int -> (int, int)\n\n"
"val identity 'a : fn 'a -> 'a\n"
>>,

Expand Down
Loading

0 comments on commit 36ee000

Please sign in to comment.