PageRenderTime 48ms CodeModel.GetById 29ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ce/src/ce_lib.erl

https://github.com/gebi/jungerl
Erlang | 219 lines | 100 code | 33 blank | 86 comment | 0 complexity | b9bf2d3396b7ecfc05711cbeee344c86 MD5 | raw file
  1%%% BEGIN ce_lib.erl %%%
  2%%%
  3%%% ce - Miscellaneous Programming Support Libraries for Erlang/OTP
  4%%% Copyright (c)2003 Cat's Eye Technologies.  All rights reserved.
  5%%%
  6%%% Redistribution and use in source and binary forms, with or without
  7%%% modification, are permitted provided that the following conditions
  8%%% are met:
  9%%%
 10%%%   Redistributions of source code must retain the above copyright
 11%%%   notice, this list of conditions and the following disclaimer.
 12%%%
 13%%%   Redistributions in binary form must reproduce the above copyright
 14%%%   notice, this list of conditions and the following disclaimer in
 15%%%   the documentation and/or other materials provided with the
 16%%%   distribution.
 17%%%
 18%%%   Neither the name of Cat's Eye Technologies nor the names of its
 19%%%   contributors may be used to endorse or promote products derived
 20%%%   from this software without specific prior written permission.
 21%%%
 22%%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 23%%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 24%%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 25%%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 26%%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
 27%%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
 28%%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 29%%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 30%%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 31%%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 32%%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 33%%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 34%%% POSSIBILITY OF SUCH DAMAGE. 
 35
 36%% @doc Miscellaneous spiffy stuff library.
 37%%
 38%% @end
 39
 40-module(ce_lib).
 41-vsn('JUNGERL').
 42-author('catseye@catseye.mb.ca').
 43-copyright('Copyright (c)2003 Cat`s Eye Technologies. All rights reserved.').
 44
 45-export([iterate/4, repeat/2]).
 46-export([breed/1]).
 47-export([eval/1]).
 48-export([call_stack/0]).
 49-export([clean/2, place/2]).
 50-export([attempt/2, attempt/3]).
 51-export([compose/1]).
 52-export([to_integer/2, to_float/2, to_string/1, to_string/2]).
 53
 54%% @spec iterate(integer(), integer(), fun(), term()) -> term()
 55%% @doc Implements iteration with a counter variable.
 56%% Not dissimilar to 'for loops' in other languages.
 57
 58iterate(I, Q, Fun, Acc) when Q < I -> Acc;
 59iterate(I, N, Fun, Acc) ->
 60  Acc0 = Fun(I, Acc),
 61  iterate(I+1, N, Fun, Acc0).
 62
 63%% @spec repeat(integer(), fun()) -> [term()]
 64%% @doc Implements opaque finite repetition.
 65%% Not dissimilar to the 'repeat' loop in LOGO.
 66%% This version is tail-recursive and returns a list of all
 67%% evaluated results.
 68
 69repeat(N, F) when integer(N) -> lists:reverse(repeat(N, F, [])).
 70
 71repeat(0, F, A) -> A;
 72repeat(N, F, A) -> repeat(N - 1, F, [F() | A]).
 73
 74%% @spec breed(term()) -> term()
 75%% @doc Returns a copy of a deep aggregate of data
 76%% with each Fun/0 object contained within replaced by
 77%% the result of running it.
 78
 79breed([H|T]) -> [breed(H) | breed(T)];
 80breed(F) when function(F) -> apply(F, []);
 81breed(T) when tuple(T) -> breed_tuple(T, size(T));
 82breed(Q) -> Q.
 83
 84breed_tuple(T, 0) -> {};
 85breed_tuple(T, N) ->
 86  erlang:append_element(breed_tuple(T, N-1), breed(element(N, T))).
 87
 88%% @spec eval(string()) -> term()
 89%% @doc Evaluates a string as an Erlang expression.
 90%% This adds reflectivity to Erlang with a simple, Perl-like
 91%% interface.
 92
 93eval(S) -> eval(S, []).
 94eval(S, PT) when list(S) ->
 95  {ok, T, _} = erl_scan:string(S),
 96  {ok, C} = erl_parse:parse_exprs(T),
 97  % execute all parse transforms in PT
 98  {value, Y, _} = erl_eval:exprs(C, erl_eval:bindings(erl_eval:new_bindings())),
 99  Y.
100
101%% @spec call_stack() -> [{Module, Function, Arity}]
102%% @doc Returns the current Erlang call stack (not including
103%% <code>ce_lib:call_stack/0</code>).
104
105call_stack() ->
106  {'EXIT', {Error, CallStack}} = (catch 1 = 2),
107  tl(CallStack).
108
109%% @spec place(term(), term()) -> ok
110%% @doc Places the given value in the process dictionary iff the given key
111%% does not yet exist.  Exclusive use of place/2 instead of erlang:put/2
112%% imposes the restriction of single-assignment on the process dictionary.
113
114place(Key, Value) ->
115  case erlang:get(Key, Value) of
116    undefined ->
117      put(Key, Value),
118      ok;
119    _ ->
120      throw({error, already_set})
121  end.
122
123%% @spec clean(fun(), [{key(), value()}]) -> term()
124%% @doc Evaluate a given Fun with a new, temporary process dictionary.
125%% The new process dictionary will contain only the values given to clean/2,
126%% and will be reset to the old process dictionary after the Fun has been
127%% evaluated.  Simulates local variables with dynamic scope as found in 
128%% many non-single-assignment languages.
129
130clean(F, L) ->
131  ProcessDictionary = erase(),
132  lists:foreach(fun({K,V}) -> put(K,V) end, L),
133  Result = F(),
134  erase(),
135  lists:foreach(fun({K,V}) -> put(K,V) end, ProcessDictionary),
136  Result.
137
138%% @spec attempt(function(), [term()]) -> {ok, term()} | {error, term()}
139%% @doc Catches errors from an error-throwing function.
140%% Thanks to Thomas Arts for this code.
141
142attempt(F, Args) ->
143  case catch apply(F, Args) of
144    {'EXIT', Why} -> {error, Why};
145            Other -> {ok, Other}
146  end.
147
148%% @spec attempt(function(), [term()], term()) -> term()
149%% @doc Catches errors and returns a default value if error thrown.
150%% Also can be used with functions which return {ok, Result} | {error, Why}.
151
152attempt(F, Args, Default) ->
153  case catch apply(F, Args) of
154    {'EXIT', _} -> Default;
155     {error, _} -> Default;
156    {ok, Value} -> Value;
157          Other -> Other
158  end.
159
160%% @spec compose([function()]) -> function()
161%% @doc Composes a function by chaining the results of a list of functions.
162%% Thanks to Alex Peake for this code.
163
164compose([Fn]) -> Fn;
165compose([Fn | FnTail]) ->
166  fun(Args) ->
167    apply(Fn, [apply(compose(FnTail), [Args])])
168  end.
169
170%% @spec to_integer(term(), integer()) -> integer()
171%% @doc Tries to convert any term into an integer, using default value if it
172%% cannot be done.
173
174to_integer(F, D) when is_float(F) ->
175  trunc(F + 0.5);
176to_integer(I, D) when is_integer(I) ->
177  I;
178to_integer(S, D) when is_list(S) ->
179  case catch list_to_integer(S) of
180    F when integer(F) -> F;
181    {'EXIT', Reason} -> D
182  end;
183to_integer(X, D) -> D.
184
185%% @spec to_float(term(), float()) -> float()
186%% @doc Tries to convert any term into a float, using default value if it
187%% cannot be done.
188
189to_float(F, D) when is_float(F) ->
190  F;
191to_float(I, D) when is_integer(I) ->
192  I * 1.0;
193to_float(S, D) when is_list(S) ->
194  case catch list_to_float(S) of
195    F when number(F) -> F;
196    {'EXIT', Reason} ->
197      case catch list_to_integer(S) of
198        G when integer(G) -> G * 1.0;
199	{'EXIT', Reason0} -> D
200      end
201  end;
202to_float(X, D) -> D.
203
204to_string(X) -> to_string(X, "").
205
206%% @spec to_string(term(), string()) -> string()
207%% @doc Tries to convert any term into a string, using default value if it
208%% cannot be done.
209
210to_string(F, D) when is_float(F) ->
211  float_to_list(F);
212to_string(I, D) when is_integer(I) ->
213  integer_to_list(I);
214to_string(A, D) when is_atom(A) ->
215  atom_to_list(A);
216to_string(S, D) when is_list(S) -> S;
217to_string(X, D) -> io_lib:format("~w", [X]).
218
219%%% END of ce_lib.erl %%%