Interactively-defined functions

Julian Fondren <>
Tue Nov 26 18:51:40 CET 2002


This should be a gen_server, but I'm too busy right now to clean it
up -- hopefully this is clear enough.  I won't be available to respond
to email (and my hotmail account will probably be frozen before I can
get back to it), sorry.

Note:  The server's state is a list of parsed functions


-module(shell_funs).
-author('').
-export([start/0,
         load/0, save/0, list/0, show/2,
         add/0, add/1, add/3, remove/2, get/2]).
-export([loop/1]).
-define(SERVER, ?MODULE).

% ----------------------------------------------------------------------
start() ->
    register(?SERVER, spawn(?MODULE, loop, [[]])).

% ----------------------------------------------------------------------
load() ->
    Funs = load_funs(),
    ?SERVER ! {load, Funs},
    ok.

save() ->
    save_funs(funs()).

% ----------------------------------------------------------------------
list() ->
    lists:map(fun name_of_fun/1, funs()).

show(Name, Arity) ->
    case fun_by_name of
        {ok, Fun} ->
            io:format("~s", [erl_pp:function(Fun)]);
        not_found ->
            not_found
    end.

get(Name, Arity) ->
    ?SERVER ! {self(), get, Name, Arity},
    receive
        {?SERVER, function, Fun} ->
            {ok, Fun};
        {?SERVER, not_found} ->
            not_found
    end.

% ----------------------------------------------------------------------
add() ->
    {ok, Fun={function, _What_is_this, Name, Arity, _Clauses}, _} =
        io:parse_erl_form(': '),
    ?SERVER ! {add, Fun, Name, Arity},
    ok.

add(FunString) ->
    {ok, Tokens, _} = erl_scan:string(FunString),
    {ok, Fun={function, _What_is_this, Name, Arity, _Clauses}} =
        erl_parse:parse_form(Tokens),
    ?SERVER ! {add, Fun, Name, Arity},
    ok.

add(Fun, Name, Arity) ->
    ?SERVER ! {add, Fun, Name, Arity},
    ok.

remove(Name, Arity) ->
    ?SERVER ! {remove, Name, Arity}.

% ----------------------------------------------------------------------
funs() ->
    ?SERVER ! {self(), save},
    receive
        {?SERVER, functions, Funs} ->
            Funs
    end.

% ----------------------------------------------------------------------
loop(Funs) ->
    receive
        {add, Fun, Name, Arity} ->
            NewFuns = [Fun|case fun_by_name(Name, Arity, Funs) of
                               {ok, CollideFun} ->
                                   lists:delete(CollideFun, Funs);
                               not_found ->
                                   Funs
                           end],
            make_module(NewFuns),
            loop(NewFuns);
        {remove, Name, Arity} ->
            case fun_by_name(Name, Arity, Funs) of
                {ok, Fun} ->
                    NewFuns = lists:delete(Fun, Funs),
                    make_module(NewFuns),
                    loop(NewFuns);
                not_found ->
                    loop(Funs)
            end;
        {load, Funs1} ->
            make_module(Funs1),
            loop(Funs1);
        {Pid, save} ->
            Pid ! {?SERVER, functions, Funs},
            loop(Funs);
        {Pid, get, Name, Arity} ->
            case fun_by_name(Name, Arity, funs) of
                {ok, Fun} ->
                    Pid ! {?SERVER, function, Fun};
                not_found ->
                    Pid ! {?SERVER, not_found}
            end,
            loop(Funs)
    end.
% ----------------------------------------------------------------------
name_of_fun({function, _What_is_this, Name, Arity, _Clauses}) ->
    {Name, Arity}.

fun_by_name(Name, Arity, [Fun={function, _What_is_this,
                               Name, Arity, _Clauses}|_]) ->
    {ok, Fun};
fun_by_name(Name, Arity, [_|T]) ->
    fun_by_name(Name, Arity, T);
fun_by_name(_, _, []) ->
    not_found.

% ----------------------------------------------------------------------
the_save_file() ->
    os:getenv("HOME") ++ "/.user_default.erl".

load_funs() ->
    {ok, Bin} = file:read_file(the_save_file()),
    functions(binary_to_list(Bin)).

save_funs(Funs) ->
    % Syntax error:
    % FunStrings = lists:map(fun erl_pp:function/1, Funs),
    FunStrings = lists:map(fun (F) -> erl_pp:function(F) end, Funs),
    file:write_file(the_save_file(), FunStrings).

functions([]) ->
    [];
functions(S) ->
    case erl_scan:tokens([], S, 0) of
        {done, {ok, Tokens, _}, Rest} ->
            {ok, Parsed} = erl_parse:parse_form(Tokens),
            [Parsed|functions(Rest)]
    end.

make_module(Funs) ->
    {ok, Module, Bin} = 
compile:forms([{attribute,1,module,user_default}|Funs],
                                      [export_all]),
    code:load_binary(Module, the_save_file(), Bin).


_________________________________________________________________
The new MSN 8: advanced junk mail protection and 2 months FREE* 
http://join.msn.com/?page=features/junkmail




More information about the erlang-questions mailing list