eval()

new topic     » topic index » view thread      » older message » newer message

With a bit of restructuring, we can have a simple eval() function in Phix.

-- eval.e -- (approx 90% of the compiler, not an autoinclude, and not in builtins\) 
global function eval(string code, sequence rset={}, iset={}, ival={}) 

Sample use:

requires("1.0.1") 
include eval.e  -- (not an autoinclude, pulls in around 90% of the interpreter/compiler proper) 
 
string code = " ""  
--integer res = 0 
bool res_init = false 
sequence res 
if not res_init then res = {} end if 
for i=1 to 4 do 
--  res += i 
    res &= i 
end for 
"" " 
?eval(code,{"res"})     -- 10 for integer res, else {1,2,3,4} 
--?eval(code,{"res"},{"res"},{5})  -- 15 for integer res 
?eval(code,{"res"},{{"res_init",true},{"res",{5}}}) -- {5,1,2,3,4} 
 
--note: strings such as `\n` (length 2) must be passed to eval,  
--        as opposed to "\n" (length 1), otherwise you'll just 
--        get errors such as "missing closing quote". You can 
--        use backticks or triple-quotes to prevent backslash 
--        interpretation, or build the code strings manually. 
{} = eval(`puts(1,"Hello World\n")`) 

In Phix you must always declare variables before use, and such code fragments are no exception.
It is not expensive to copy variables/data from the calling code into and out of the "eval context" (for want of a better term).

The eval function accepts up to 4 parameters: 
code is the source code fragment to be interpreted, 
rset is a list of string names of (static) result variable identifiers 
iset is a list of string names of (static) variables to initialise 
ival is a list of values matching iset, alternatively ival can be 
omitted and iset instead provided as a list of {name,value} pairs. 
 
Note that static integers are initialised at compile-time and may therefore be 
overidden in iset/ival, whereas strings, sequences, and floating point values 
may need a little more care. For instance sequence res = {} is duty bound to 
overwrite any value in iset/ival whereas bool(/integer) res_init = false and 
if not res_init then res = {} end if in the code snippet can prevent any such 
unwanted overwrite, provided that iset/ival contains (both) res_init and res. 

Of course this cannot possibly work as-is under pwa/p2js, in time perhaps there could be some kind of equivalent for the transpiler, with
transpiled phix code running in a transpiled program, and until there is I will remain rather reluctant to make this a builtin/autoinclude.

One thing that is not yet clear is the lifetime/persistency of generated code. Attempts to set a callback (for instance) will likely
have the rug pulled from under its feet at some indeterminate time in the future, as the code space ends up getting reclaimed...
Maybe an rset[1] of "$" yields a reference the calling code has to cling onto for as long as it needs it.

Comments/thoughts?

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu