Tuesday, August 28, 2007

MVEL's Compiled vs. Interpreted Mode.

One of the things which makes MVEL so neat is the fact it functions in both purely interpreted (ie. execute while parsing) and as pre-compiled scripts.

Contrary to what you might think, calling eval in MVEL does not simply bootstrap the compiler and execute. Rather no AST is generated at all. The compiler parses tokens, reduces them at the first ability opportunity, and pushes the values down to an execution stack. This is very much unlike running a compiled script, which often involves little or no use of the execution stack.

Take the following example:

(4 + 5) - 2 + a

When you compile this statement, MVEL generates a very efficient evaluation tree, or even bytecode to accelerate the execution. But when you run in interpreted mode, MVEL doesn't bother with all of that overhead. Instead, MVEL takes the shortest possible path to solve the problem.  It does this by emitting instructions and values onto an execution stack as it parses. Here is how it works:

1. "(" is encountered. The parser scans forward to determine where this nest ends.
2. The nest
"4 + 5" is returned.
3. MVEL pushes
4 onto the stack.
4. MVEL pushes
5 onto the stack.
5. MVEL pushes the
'+' opcode onto the stack.
6. MVEL determines that the stack can be reduced.
7. MVEL pops the opcode off the stack, and the 2 parameters (4 and 5), and passes it to the operation handling code.
8. MVEL pushes the result (
9) onto the stack.
9. MVEL pushes
2 onto the stack.
10. MVEL pushes the
'-' opcode onto the stack.
11. MVEL pops the opcode off the stack, and the 2 parameters (9 and 2), and passes it to the operation handling code.
12. MVEL pushes the result (
7) onto the stack.
13. MVEL resolves the value of
a, and pushes it onto the stack. (which for the sake of argument is: 10)
14. MVEL pushes the
'+' opcode onto the stack.
15. MVEL pops the opcode off the stack, and the 2 parameters (7 and 10), and passes it to the operation handling code.
16. MVEL pushes the result (
17) onto the stack.
17. MVEL has nothing left to parse, MVEL pops the value off the stack (
17) and returns.

Which should gives you the basic idea of how MVEL is able to parse and execute on the fly versus use an AST for eval() :)

3 comments:

Ivan said...

Nice if MVEL support some things like :-

x like '%Java%'

and

x in ( 'Java', 'Compiler' )

David Medinets said...

Hi. MVEL looks interesting. I have noticed a misspelling on your Getting Started page. The misspelled word should be 'whet' not 'wet'.

Mike Brock said...

Ivan,

I like the idea of having a wild card comparator in MVEL. You should submit a feature JIRA for MVEL 2.0.

Also, you can do what you're trying to do by writing:

{'Java', 'Compiler'} contains x