[erlang-questions] Programmatic interface to the shell

Éric Pailleau eric.pailleau@REDACTED
Mon Aug 10 20:27:17 CEST 2015


Hi,
This allows to "write" in a Pid but without underlying file. This simulate a shell in the way you can send incomplete Erlang statements until a dot is detected. Then the complete statement can be evaluated and result sent back to the caller.
(note the example gives only the io server layer).

Le 10 août 2015 20:13, Joe Armstrong <erlang@REDACTED> a écrit :
>
> On Mon, Aug 10, 2015 at 7:17 PM, Éric Pailleau <eric.pailleau@REDACTED> wrote: 
> > Hello Joe, 
> > 
> > In bottom of this code 
> > 
> > https://github.com/erlang/otp/blob/maint/lib/observer/src/observer_procinfo.erl 
> > 
> > Is a simple io server, thanks to Dan Gudmunson. 
> > This may help ? 
>
> I'm not sure how? 
>
> /Joe 
>
> > Regards 
> > 
> > 
> > Le 10 août 2015 19:08, Joe Armstrong <erlang@REDACTED> a écrit : 
> >> 
> >> 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. 
> >> > 
> >> _______________________________________________ 
> >> erlang-questions mailing list 
> >> erlang-questions@REDACTED 
> >> http://erlang.org/mailman/listinfo/erlang-questions 


More information about the erlang-questions mailing list