Packages

Open Telecom Platform Command Language

Current section

Files

Jump to
otpcl src otpcl_stdlib.erl
Raw

src/otpcl_stdlib.erl

-module(otpcl_stdlib).
-export([return/2, get/2, set/2, print/2, 'if'/2, truthy/1, unless/2,
incr/2, decr/2, send/2]).
% Modules which provide Made For OTPCL™ functions can specify them
% with the -otpcl_funs/1 module attribute, which will tell OTPCL's
% import function(s) to import these as state-changing functions
% (otherwise, it'll import them as if they're ordinary Erlang
% functions, which might not be what you want if you actually do care
% about the interpreter state).
-otpcl_funs([return, get, set, print, 'if', unless, incr, decr, import, eval,
funget, funset, funcall, funwrap, send]).
% All OTPCL functions are represented behind-the-scenes as 2-arity
% Erlang functions; the first argument is a list of the actual
% arguments, and the second argument is the interpreter state. Every
% OTPCL function's backing Erlang function in turn returns a tuple
% with a return value and an updated interpreter state.
% This standard library is pretty bare-bones, but should provide an
% adequate demonstration of how to define further functions.
return([], State) ->
{ok, State};
return([RetVal], State) ->
{RetVal, State};
return(Args, State) ->
{Args, State}.
get([Name], {Funs, Vars}) ->
case maps:find(Name, Vars) of
{ok, Val} ->
{Val, {Funs, Vars}};
_ ->
{error, {no_such_var, Name}, {Funs, Vars}}
end.
set([Name, Val], {Funs, Vars}) ->
{ok, {Funs, maps:put(Name, Val, Vars)}}.
print([], State) ->
{RetVal, State} = get(['RETVAL'], State),
{io:format("~p", [RetVal]), State};
print([Out], State) ->
case 'string?'([Out], State) of
{true, State} ->
{io:format(Out), State};
_ ->
{io:format("~p", [Out]), State}
end;
print([Text|Args], State) ->
{io:format(Text, Args), State}.
'string?'([Text], State) ->
{is_binary(Text) or io_lib:char_list(Text), State}.
'if'([Test, Then], State) ->
'if'([Test, Then, ""], State);
'if'([Test, Then, Else], State) ->
case truthy(otpcl_eval:eval(Test, State)) of
true ->
otpcl_eval:eval(Then, State);
_ ->
otpcl_eval:eval(Else, State)
end.
% Just a helper for truthiness
truthy([]) ->
false;
truthy(false) ->
false;
truthy(error) ->
false;
truthy(0) ->
false;
truthy(<<>>) ->
false;
truthy({}) ->
false;
truthy(T) when is_tuple(T) andalso element(1, T) =:= error ->
false;
truthy(_) ->
true.
unless([Test, Then], State) ->
'if'([Test, "", Then], State).
incr([], State) ->
incr([1], State);
incr([VarName], State) when is_atom(VarName) ->
incr([VarName, 1], State);
incr([By], State) ->
incr(['RETVAL', By], State);
incr([VarName, By], State) ->
{OldVal, State} = get([VarName], State),
NewVal = OldVal + By,
{ok, NewState} = set([VarName, NewVal], State),
{NewVal, NewState}.
decr([], State) ->
incr([-1], State);
decr([VarName], State) when is_atom(VarName) ->
incr([VarName, -1], State);
decr([By], State) ->
incr([By * -1], State);
decr([VarName, By], State) ->
incr([VarName, By * -1], State).
send([Pid, Msg], State) ->
Pid ! Msg,
{ok, State}.