[erlang-questions] Programmatic interface to the shell

Joe Armstrong erlang@REDACTED
Mon Aug 10 19:08:16 CEST 2015


Wonderful - thanks

The main problem now is that the error messages are not exactly the same
as in the shell.

ie: The above code for X/0 says

> Send(P, "X/0.").
** exception error: an error occurred when evaluating an arithmetic expression

But X/0. in the shell says:

> X/0.
** exception error: an error occurred when evaluating an arithmetic expression
     in operator  '/'/2
        called as 4 / 0

Do you have any idea how to dig out the error message so it's exactly the same?

I'm asking because I'm writing a tutorial in a "markdown like" language
and I want to automate production of examples :-)


Thanks again

/Joe







On Mon, Aug 10, 2015 at 6:23 PM, Fred Hebert <mononcqc@REDACTED> wrote:
> On 08/10, Joe Armstrong wrote:
>>
>> Hello,
>>
>> Is there a *simple* programmatic interface to the Erlang shell?
>>
>> I'd like a module "shell_interface" that works like this:
>>
>>      Pid = shell_interface:new_shell(),
>>
>> Returns a new process that behaves like the Erlang shell
>>
>>      OutStr = shell_interface:eval(Pid, InStr)
>>
>
> Short answer is no. The Erlang shell in the `shell' module asks for
> information via the IO protocol and pulls it in, rather than you pushing it
> out.
>
> There's ways to inject yourself in there, but it's not simple.
>
>> This behaves like the Erlang shell. InStr should be what I typed into the
>> shell. OutStr should be what the shell replied.
>>
>> For this purpose we can assume that InStr represents a complete
>> sequence of expressions.
>>
>
> This sounds more like an evaluator/interpreter:
>
>    1> {ok, Tokens, _} = erl_scan:string("X + 4 * lists:sum([1,2,3,4]).").
>    ...
>    2> {ok, [Form]} = erl_parse:parse_exprs(Tokens).
>    ...
>    3> Bindings = erl_eval:add_binding('X', 17, erl_eval:new_bindings()).
>    [{'X',17}]
>    4> {value, Value, _} = erl_eval:expr(Form, Bindings).
>    {value,57,[{'X',17}]}
>    5> Value.
>    57
>
> With these basic forms it becomes doable to write a mini-shell the way you'd
> like it.
>
>    Eval = fun EvalLoop(Bindings) ->
>        receive
>            {cmd, Caller, Ref, String} ->
>                try
>                    {ok, Tokens, _} = erl_scan:string(String),
>                    %% many forms can be comma-separated
>                    {ok, Forms} = erl_parse:parse_exprs(Tokens),
>                    %% eval individually
>                    {value, Val, NewBindings} = erl_eval:exprs(Forms,
> Bindings),
>                    Caller ! {ok, Ref, Val},
>                    EvalLoop(NewBindings)
>                catch
>                    T:R ->
>                        Caller ! {raise, Ref, T, R},
>                        EvalLoop(Bindings)
>                end
>        end end.
>
>    Send = fun(Pid, String) ->
>        Ref = erlang:monitor(process, Pid),
>        Pid ! {cmd, self(), Ref, String},
>        receive
>            {ok, Ref, Value} -> Value;
>            {raise, Ref, T, R} -> erlang:T(R)
>        end end.
>
>    18> P = spawn(fun() -> Eval([]) end).
>    <0.62.0>
>    19> Send(P, "X=2+2.").
>    4
>    20> Send(P, "X*X.").
>    16
>    21> Send(P, "X/0.").
>    ** exception error: an error occurred when evaluating an arithmetic
> expression
>    22> Send(P, "X.").
>    4
>
> And there  you have an evaluator. It doesn't support all the stuff like
> 'h().' and whatnot, but is close enough otherwise.
>



More information about the erlang-questions mailing list