Erlang Central

Difference between revisions of "String Eval"

From ErlangCentral Wiki

(Problem)
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
== Problem ==
 
== Problem ==
  
You want to evaluate Erlang code stored in a string.  
+
You want to evaluate Erlang code stored in a string (this is Meta Programming on the fly).
  
 
== Solution ==
 
== Solution ==
Line 27: Line 27:
  
 
test()->
 
test()->
 +
    %% Create a code string with unbound variables 'A' and 'B'
 
     String="Results=A+B/2.",
 
     String="Results=A+B/2.",
 +
   
 +
    %% Scan the code into tokens
 
     {ok,ErlTokens,_}=erl_scan:string(String),
 
     {ok,ErlTokens,_}=erl_scan:string(String),
 
     io:format("ErlTokens are ~p~n",[ErlTokens]),
 
     io:format("ErlTokens are ~p~n",[ErlTokens]),
 +
 +
    %% Now parse the tokens into the abstract form
 
     {ok,ErlAbsForm}=erl_parse:parse_exprs(ErlTokens),
 
     {ok,ErlAbsForm}=erl_parse:parse_exprs(ErlTokens),
 
     io:format("ErlAbsForm are ~p~n",[ErlAbsForm]),
 
     io:format("ErlAbsForm are ~p~n",[ErlAbsForm]),
 +
 +
    %% Now we need to bind values to variable 'A' and 'B'
 
     Bindings=erl_eval:add_binding('A',20,erl_eval:new_bindings()),
 
     Bindings=erl_eval:add_binding('A',20,erl_eval:new_bindings()),
 
     NewBindings=erl_eval:add_binding('B',45,Bindings),
 
     NewBindings=erl_eval:add_binding('B',45,Bindings),
 
     io:format("The bindings are ~p~n",[erl_eval:bindings(NewBindings)]),
 
     io:format("The bindings are ~p~n",[erl_eval:bindings(NewBindings)]),
 +
 +
    %% Now evaluate the string
 
     io:format("Going into erl_eval:exprs~n",[]),
 
     io:format("Going into erl_eval:exprs~n",[]),
 
     {value,Value,_}=erl_eval:exprs(ErlAbsForm,NewBindings),
 
     {value,Value,_}=erl_eval:exprs(ErlAbsForm,NewBindings),
Line 66: Line 75:
 
</code>
 
</code>
  
 +
Note: If you bind variables that don't exist in the code string/token set/abstract form then when you erl_eval the abstract form will simply silently ignore your additional bindings
  
 
[[Category:CookBook]][[Category:StringRecipes]]
 
[[Category:CookBook]][[Category:StringRecipes]]
 
 
 
[http://www.casinos-go.com/online-casino-tips/index.html online casino tips]
 
[http://www.casino-theory.com/online-casino-royale/play-free-online-casino.html play free online casino]
 
[http://www.fortune-slots.com/ slots]
 
[http://www.slots-wiki.com/index.php/slots_online_bonus slots online bonus]
 
[http://www.casino-theory.com/bingo-online/gambling-online-bingo.html gambling online bingo]
 
[http://www.gambling-online-theory.com/casinos/on-line-casinos.html on line casinos]
 
[http://www.online-casino-wiki.com/index.php/online_casino_tips online casino tips]
 
[http://www.casino-games-wiki.com/index.php/casino_games_online casino games online]
 
[http://www.casino-theory.com/online-casino-bonus/online-casino-net.html online casino net]
 
[http://www.gambling-online-theory.com/online-casino/bet-online-casino.html bet online casino]
 

Revision as of 22:42, 21 November 2006

Problem

You want to evaluate Erlang code stored in a string (this is Meta Programming on the fly).

Solution

Use erl_scan:string/1 to convert the string into a list of tokens, then use erl_parse:parse_exprs/1 to generate the Erlang intermediate representation, then finally use erl_eval:exprs/2 to generate the final output:

eval(S,Environ) ->
    {ok,Scanned,_} = erl_scan:string(S),
    {ok,Parsed} = erl_parse:parse_exprs(Scanned),
    erl_eval:exprs(Parsed,Environ).

1> eval("A = 1 + 2.",[]).
{value,3,[{'A',3}]}


Now, this is an admittedly baroque way to determine the value of 1 + 2, but it does give you interesting access to the inner workings of the Erlang interpreter.

In addition, you can bind in variables into the string as shown in the test module below:

-module(test).

-export([test/0]).

test()->
    %% Create a code string with unbound variables 'A' and 'B'
    String="Results=A+B/2.",
    
    %% Scan the code into tokens
    {ok,ErlTokens,_}=erl_scan:string(String),
    io:format("ErlTokens are ~p~n",[ErlTokens]),

    %% Now parse the tokens into the abstract form
    {ok,ErlAbsForm}=erl_parse:parse_exprs(ErlTokens),
    io:format("ErlAbsForm are ~p~n",[ErlAbsForm]),

    %% Now we need to bind values to variable 'A' and 'B'
    Bindings=erl_eval:add_binding('A',20,erl_eval:new_bindings()),
    NewBindings=erl_eval:add_binding('B',45,Bindings),
    io:format("The bindings are ~p~n",[erl_eval:bindings(NewBindings)]),

    %% Now evaluate the string
    io:format("Going into erl_eval:exprs~n",[]),
    {value,Value,_}=erl_eval:exprs(ErlAbsForm,NewBindings),
    io:format("Value is ~p~n",[Value]).

You can compile and run this in the shell:

(arrian@psyduck)17> c(test).
{ok,test}
(arrian@psyduck)18> test:test().
ErlTokens are [{var,1,'Results'},
               {'=',1},
               {var,1,'A'},
               {'+',1},
               {var,1,'B'},
               {'/',1},
               {integer,1,2},
               {dot,1}]
ErlAbsForm are [{match,1,
                       {var,1,'Results'},
                       {op,1,
                           '+',
                           {var,1,'A'},
                           {op,1,'/',{var,1,'B'},{integer,1,2}}}}]
The bindings are [{'A',20},{'B',45}]
Going into erl_eval:exprs
Value is 42.5000
ok
(arrian@psyduck)19>            

Note: If you bind variables that don't exist in the code string/token set/abstract form then when you erl_eval the abstract form will simply silently ignore your additional bindings