string_exec()
- Posted by petelomax Feb 28, 2015
- 2533 views
An old idea, but I thought it is about time I at least got a start on some design.
Implementation may be some time off, this is all just some preliminary musings, and not particularly well thought through at that, but as I'm currently doing some design work on the optable (not that you need to know or care what that is), now seems as good a time as any to consider this. I haven't seen any examples that make me think "you know what, that's a really good idea", so now is your chance.
Obviously this has something of a Phix bias that may need ironing out. It must (somehow) include a complete copy of the compiler/interpreter, or re-use the one already running. I imagine OpenEuphoria might use eu.ex, the hll interpreter.
Firstly, there is no security model whatsoever. If you put this on a web server and let visitors type in and execute code, you may as well just give them the root password. However, if this is an app they have downloaded and installed locally, it is, literally, the same deal as installing a compiler. All I am really saying is that I have no plans to go down the Java route of 12 security patches a day from now until the end of time; if someone else wants that then they can jolly well do it themselves! That said, I would support an optional "draconian safe mode" whereby such things as file i/o, system_exec, inline assembly, etc are all completely prohibited inside string_exec() - if someone else takes the time to carefully sift through the manual and compose a comprehensive list of all potential dangers.
Let's begin simple:
integer i = 5 ctrl = string_exec(ctrl,"i+=1")
While (on Phix) when interpreted there might be a few salvage-able bits of lookup and the possibility of extending the symbol table, when compiled we have:
- original symbol table (damaged, fixed size, non-extendable, no lookup)
- static data block (fixed size, non-extendable)
- executable code (fixed size, non-extendable)
So during string_exec(), we will need:
- a completely rebuilt symbol table, extendable, with rebuilt lookup
- original and new static data blocks, with index ranges (lists of)
- original and new executable code blocks (lists of)
Such things could be preserved in ctrl1 so that subsequent invocations are not quite so expensive, even if that might only be half a second per call to string_exec, and for reasons that should become clear soon.
Question: Are we hoping for something like this?
integer i = 5 ctrl = string_exec(ctrl,"integer j\n"& "function add1(integer i)"& " return i+1"& "end function") ctrl = string_exec(ctrl,"j = add1(i)")
In other words, are the rebuilt and extended symbol table, new data, and new code all available for use in subsequent invocations of string_exec()? Or should the symbol table be reset for each invocation and any temporary code/data discarded? Or do we need to cater for both? [Examples to backup any claims, please.]
Next question: What sort of context are we looking for?
procedure p() integer i=5 ctrl = string_exec(ctrl,"i+=1") end procedure
Should scope be as per EOF of main file or at the point of invoking string_exec? The latter is much harder - and if there are multiple string_exec calls, we might need different scopes for each. I would need some blinding examples to convince me that is worthwhile.
What error messages (compile-time and run-time) if any do we really need?
What sort of clean-up (deallocating temps, freeing allocated memory, closing files, etc) do we really need? As per the add1 example above, we could go too far and trash something we might want later.
Is there any need for expression results?
integer i = 5, j j = string_expr(ctrl,"i") -- (or maybe -- ctrl = string_expr(ctrl,"i") -- j = ctrl[RESULT])
Note that you couldn't define any vars/funcs, unless you made "return <expr>" at top level legal in string expressions. Again, I'd need convincing examples.
We probably ought to be able to "nest" string evaluation, though I hope someone can provide a much better example than this:
j = string_expr(ctrl,"string_expr(ctrl,\"i\")")
I can see a use for "standalone" string evaluation, that starts with the basic "empty" symbol table2, such as:
a = string_expr(NULL,"5+4/3")
which might be quite useful in say a calculator, anything else? (Obviously that assumes support for expression results, but we could achieve equivalent functionality via something like "res=5+4/3")
Also, it is not particularly clear what command_line() should return when it is invoked from inside a string_exec().
This is far from over, but I think that's probably enough for now, plus I just spotted a major flaw in nested opInterp/thread safety that I must go and fix asap.
Please try to provide examples that I have a vague chance of understanding
Pete
1 the content and structure of ctrl is deliberately left vague and undefined.
2 maybe: string_expr(NULL,...)=>empty; string_expr({},...)=>rebuild, or vice versa.