Current section

Files

Jump to
gustav src scheme reader.erl
Raw

src/scheme/reader.erl

-module(reader).
-export([read/1]).
-ifdef(EUNIT).
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
-endif.
%%====================================================================
%% API functions
%%====================================================================
read([]) ->
{error, "unexpected EOF read[]"};
read(["("|Tokens]) ->
read_list(Tokens, []);
read([")"|_Tokens]) ->
{error, "unexpected EOF read(')')"};
read([Token]) ->
try
list_to_integer(Token)
catch
error:badarg ->
try
list_to_float(Token)
catch
error:badarg ->
{symbol, Token}
end
end;
read(Error) ->
{error, "unable to read", Error}.
%%====================================================================
%% Internal functions
%%====================================================================
read_list([], Acc) ->
{error, "unexpected EOF read_list([],", Acc, ")"};
read_list([")"], Acc) ->
lists:reverse(Acc);
read_list(["("|Tokens], Acc) ->
case read_list(Tokens, []) of
{L, _Rem} ->
[L|Acc];
L ->
[L|Acc]
end;
read_list([")"|Tokens], Acc) ->
{lists:reverse(Acc), Tokens};
read_list([Head|Tail], Acc) ->
SubExpr = read([Head]),
read_list(Tail, [SubExpr|Acc]).
%%====================================================================
%% Tests
%%====================================================================
-ifdef(EUNIT).
read_integer_1_test() ->
Text = "42",
Tokens = read(tokenizer:tokenize(Text)),
?assert(Tokens =:= 42).
read_integer_2_test() ->
Text = "x",
Tokens = read(tokenizer:tokenize(Text)),
?assert(Tokens =:= {symbol, "x"}).
read_integer_3_test() ->
Text = "(xy)",
Tokens = tokenizer:tokenize(Text),
Read = read(Tokens),
?assert(Read =:= [{symbol, "xy"}]).
read_integer_4_test() ->
Text = "(xy zy)",
Tokens = tokenizer:tokenize(Text),
Read = read(Tokens),
?assert(Read =:= [{symbol, "xy"}, {symbol, "zy"}]).
read_integer_5_test() ->
Text = "((xy))",
Tokens = tokenizer:tokenize(Text),
Read = read(Tokens),
?assert(Read =:= [[{symbol, "xy"}]]).
read_integer_6_test() ->
Text = "(((xy)))",
Tokens = tokenizer:tokenize(Text),
Read = read(Tokens),
?assert(Read =:= [[[{symbol, "xy"}]]]).
read_integer_7_test() ->
Text = "((xy qr))",
Tokens = tokenizer:tokenize(Text),
Read = read(Tokens),
?assert(Read =:= [[{symbol, "xy"}, {symbol, "qr"}]]).
-endif.