string literals and pattern matching on the same

This commit is contained in:
Ulf Norell 2019-04-26 10:34:38 +02:00
parent 0ce144db13
commit b7153b1d75
2 changed files with 52 additions and 24 deletions

View File

@ -27,6 +27,7 @@
-type binop() :: '+' | '-' | '==' | '::'.
-type fexpr() :: {int, integer()}
| {string, binary()}
| {bool, false | true}
| nil
| {var, var_name()}
@ -46,6 +47,7 @@
-type fsplit_pat() :: {var, var_name()}
| {bool, false | true}
| {int, integer()}
| {string, binary()}
| nil
| {'::', var_name(), var_name()}
| {con, arities(), tag(), [var_name()]}
@ -258,6 +260,7 @@ expr_to_fcode(Env, Expr) ->
%% Literals
expr_to_fcode(_Env, _Type, {int, _, N}) -> {int, N};
expr_to_fcode(_Env, _Type, {bool, _, B}) -> {bool, B};
expr_to_fcode(_Env, _Type, {string, _, S}) -> {string, S};
%% Variables
expr_to_fcode(_Env, _Type, {id, _, X}) -> {var, X};
@ -364,6 +367,7 @@ alts_to_fcode(Env, Type, X, Alts) ->
-type fpat() :: {var, var_name()}
| {bool, false | true}
| {int, integer()}
| {string, binary()}
| nil | {'::', fpat(), fpat()}
| {tuple, [fpat()]}
| {con, arities(), tag(), [fpat()]}.
@ -404,6 +408,7 @@ merge_alt(I, X, {P, A}, [{Q, As} | Rest]) ->
({tuple, _}, {tuple, _}) -> match;
({bool, B}, {bool, B}) -> match;
({int, N}, {int, N}) -> match;
({string, S}, {string, S}) -> match;
(nil, nil) -> match;
({'::', _, _}, {'::', _, _}) -> match;
({con, _, C, _}, {con, _, C, _}) -> match;
@ -430,6 +435,7 @@ expand(I, X, P, Q, Case = {'case', Ps, E}) ->
Type = fun({tuple, Xs}) -> {tuple, length(Xs)};
({bool, _}) -> bool;
({int, _}) -> int;
({string, _}) -> string;
(nil) -> list;
({'::', _, _}) -> list;
({con, As, _, _}) -> {variant, As}
@ -439,6 +445,7 @@ expand(I, X, P, Q, Case = {'case', Ps, E}) ->
{tuple, N} -> {[MkCase(Q, N)], []};
bool -> {[MkCase({bool, B}, 0) || B <- [false, true]], []};
int -> {[MkCase(Q, 0)], [{P, Case}]};
string -> {[MkCase(Q, 0)], [{P, Case}]};
list -> {[MkCase(nil, 0), MkCase({'::', fresh_name(), fresh_name()}, 2)], []};
{variant, As} -> {[MkCase({con, As, C - 1, [fresh_name() || _ <- lists:seq(1, Ar)]}, Ar)
|| {C, Ar} <- indexed(As)], []}
@ -454,6 +461,7 @@ split_alt(I, {'case', Pats, Body}) ->
split_pat(P = {var, _}) -> {{var, fresh_name()}, [P]};
split_pat({bool, B}) -> {{bool, B}, []};
split_pat({int, N}) -> {{int, N}, []};
split_pat({string, N}) -> {{string, N}, []};
split_pat(nil) -> {nil, []};
split_pat({'::', P, Q}) -> {{'::', fresh_name(), fresh_name()}, [P, Q]};
split_pat({con, As, I, Pats}) ->
@ -466,6 +474,7 @@ split_pat({tuple, Pats}) ->
-spec split_vars(fsplit_pat(), ftype()) -> [{var_name(), ftype()}].
split_vars({bool, _}, boolean) -> [];
split_vars({int, _}, integer) -> [];
split_vars({string, _}, string) -> [];
split_vars(nil, {list, _}) -> [];
split_vars({'::', X, Xs}, {list, T}) -> [{X, T}, {Xs, {list, T}}];
split_vars({con, _, I, Xs}, {variant, Cons}) ->
@ -478,6 +487,7 @@ split_vars({var, X}, T) -> [{X, T}].
rename(Ren, Expr) ->
case Expr of
{int, _} -> Expr;
{string, _} -> Expr;
{bool, _} -> Expr;
nil -> nil;
{var, X} -> {var, rename_var(Ren, X)};
@ -516,6 +526,7 @@ rename_fpats(Ren, [P | Ps]) ->
rename_fpat(Ren, P = {bool, _}) -> {P, Ren};
rename_fpat(Ren, P = {int, _}) -> {P, Ren};
rename_fpat(Ren, P = {string, _}) -> {P, Ren};
rename_fpat(Ren, P = nil) -> {P, Ren};
rename_fpat(Ren, {'::', P, Q}) ->
{P1, Ren1} = rename_fpat(Ren, P),
@ -533,6 +544,7 @@ rename_fpat(Ren, {tuple, Ps}) ->
rename_spat(Ren, P = {bool, _}) -> {P, Ren};
rename_spat(Ren, P = {int, _}) -> {P, Ren};
rename_spat(Ren, P = {string, _}) -> {P, Ren};
rename_spat(Ren, P = nil) -> {P, Ren};
rename_spat(Ren, {'::', X, Y}) ->
{X1, Ren1} = rename_binding(Ren, X),
@ -587,6 +599,8 @@ pat_to_fcode(_Env, _Type, {bool, _, B}) ->
{bool, B};
pat_to_fcode(_Env, _Type, {int, _, N}) ->
{int, N};
pat_to_fcode(_Env, _Type, {string, _, N}) ->
{string, N};
pat_to_fcode(Env, _Type, {list, _, Ps}) ->
lists:foldr(fun(P, Qs) ->
{'::', pat_to_fcode(Env, P), Qs}
@ -752,6 +766,8 @@ fcode_error(Err) ->
format_fexpr(E) ->
prettypr:format(pp_fexpr(E)).
pp_text(<<>>) -> prettypr:text("\"\"");
pp_text(Bin) when is_binary(Bin) -> prettypr:text(lists:flatten(io_lib:format("~p", [binary_to_list(Bin)])));
pp_text(S) -> prettypr:text(lists:concat([S])).
pp_beside([]) -> prettypr:empty();
@ -773,8 +789,13 @@ pp_punctuate(_Sep, []) -> [];
pp_punctuate(_Sep, [X]) -> [X];
pp_punctuate(Sep, [X | Xs]) -> [pp_beside(X, Sep) | pp_punctuate(Sep, Xs)].
pp_par([]) -> prettypr:empty();
pp_par(Xs) -> prettypr:par(Xs).
pp_fexpr({int, N}) ->
pp_text(N);
pp_fexpr({string, S}) ->
pp_text(S);
pp_fexpr({bool, B}) ->
pp_text(B);
pp_fexpr(nil) ->
@ -787,25 +808,25 @@ pp_fexpr({con, _, I, Es}) ->
pp_beside(pp_fexpr({con, [], I, []}),
pp_fexpr({tuple, Es}));
pp_fexpr({tuple, Es}) ->
pp_parens(prettypr:par(pp_punctuate(pp_text(","), [pp_fexpr(E) || E <- Es])));
pp_parens(pp_par(pp_punctuate(pp_text(","), [pp_fexpr(E) || E <- Es])));
pp_fexpr({proj, E, I}) ->
pp_beside([pp_fexpr(E), pp_text("."), pp_text(I)]);
pp_fexpr({set_proj, E, I, A}) ->
pp_beside(pp_fexpr(E), pp_braces(pp_beside([pp_text(I), pp_text(" = "), pp_fexpr(A)])));
pp_fexpr({binop, Op, A, B}) ->
pp_parens(prettypr:par([pp_fexpr(A), pp_text(Op), pp_fexpr(B)]));
pp_parens(pp_par([pp_fexpr(A), pp_text(Op), pp_fexpr(B)]));
pp_fexpr({'let', X, A, B}) ->
prettypr:par([pp_beside([pp_text("let "), pp_text(X), pp_text(" = "), pp_fexpr(A), pp_text(" in")]),
pp_par([pp_beside([pp_text("let "), pp_text(X), pp_text(" = "), pp_fexpr(A), pp_text(" in")]),
pp_fexpr(B)]);
pp_fexpr({switch, Split}) -> pp_split(Split).
pp_ftype(T) when is_atom(T) -> pp_text(T);
pp_ftype({tuple, Ts}) ->
pp_parens(prettypr:par(pp_punctuate(pp_text(","), [pp_ftype(T) || T <- Ts])));
pp_parens(pp_par(pp_punctuate(pp_text(","), [pp_ftype(T) || T <- Ts])));
pp_ftype({list, T}) ->
pp_beside([pp_text("list("), pp_ftype(T), pp_text(")")]);
pp_ftype({variant, Cons}) ->
prettypr:par(
pp_par(
pp_punctuate(pp_text(" |"),
[ case Args of
[] -> pp_fexpr({con, [], I - 1, []});

View File

@ -144,7 +144,10 @@ lookup_var(Env = #env{ vars = Vars }, X) ->
%% -- The compiler --
to_scode(_Env, {int, N}) ->
[aeb_fate_code:push(?i(N))]; %% Doesn't exist (yet), translated by desugaring
[aeb_fate_code:push(?i(N))];
to_scode(_Env, {string, S}) ->
[aeb_fate_code:push(?i(aeb_fate_data:make_string(S)))];
to_scode(_Env, {bool, B}) ->
[aeb_fate_code:push(?i(B))];
@ -236,9 +239,9 @@ split_to_scode(Env, {split, {list, _}, X, Alts}) ->
SAlts = [GetAlt('::'), GetAlt(nil)],
[aeb_fate_code:is_nil(?a, Arg),
{switch, ?a, boolean, SAlts, Def}];
split_to_scode(Env, {split, integer, X, Alts}) ->
split_to_scode(Env, {split, Type, X, Alts}) when Type == integer; Type == string ->
{Def, Alts1} = catchall_to_scode(Env, X, Alts),
literal_split_to_scode(Env, integer, lookup_var(Env, X), Alts1, Def);
literal_split_to_scode(Env, Type, lookup_var(Env, X), Alts1, Def);
split_to_scode(Env, {split, {variant, Cons}, X, Alts}) ->
{Def, Alts1} = catchall_to_scode(Env, X, Alts),
Arg = lookup_var(Env, X),
@ -261,14 +264,18 @@ split_to_scode(_, Split = {split, _, _, _}) ->
literal_split_to_scode(_Env, _Type, Arg, [], Def) ->
{switch, Arg, boolean, [missing, missing], Def};
literal_split_to_scode(Env, integer, Arg, [{'case', {int, N}, Body} | Alts], Def) ->
literal_split_to_scode(Env, Type, Arg, [{'case', Lit, Body} | Alts], Def) when Type == integer; Type == string ->
True = split_to_scode(Env, Body),
False =
case Alts of
[] -> missing;
_ -> literal_split_to_scode(Env, integer, Arg, Alts, missing)
_ -> literal_split_to_scode(Env, Type, Arg, Alts, missing)
end,
[aeb_fate_code:eq(?a, Arg, ?i(N)),
SLit = case Lit of
{int, N} -> N;
{string, S} -> aeb_fate_data:make_string(S)
end,
[aeb_fate_code:eq(?a, Arg, ?i(SLit)),
{switch, ?a, boolean, [False, True], Def}].
catchall_to_scode(Env, X, Alts) -> catchall_to_scode(Env, X, Alts, []).