Expressions can be evaluated using the 'eval' builtin function, and statements can be executed using the 'exec' statement.
However, in Viper, expressions and statements are tightly coupled as follows: every statement can be turned into an expression and vice versa. Expressions are executed by evaluating them and discarding the result. Statements are evaluated like function bodies, and return whatever an internal return statement returns, or None if no value is returned.
Both grammar extensions and AST manipulators may be made available to utilise this capability.
The second major feature of Viper code objects is partial evaluation. Consider an expression which refers to some undefined variable. It can be evaluated, and the result is an expression in which some sub-expressions are reduced. Total reduction would lead to a datum value: which is itself just an irreducible expression.
This effect is achieved because Viper does not distinguish encoded language terms and run-time objects. The language term 'PyInt 1' is evaluated to the run time object 'PyInt 1'; i.e. itself. But, the expression Plus (PyInt 1, PyName "var") is evaluated recursively: if the evaluation of PyName "var" is an integer, say PyInt 2, then the result is PyInt 3, however, if lookup of "var" fails, the result is the original expression. On the other hand, the result of Plus (Plus (PyInt 1, PyInt 2), PyName "var") would be Plus (PyInt 3, PyName "var")": the expression is partially evaluated.
Normally, Viper disallows partial evaluation; an exception is thrown if an expression cannot be fully evaluated. Functions will be provided to support partial evaluation. At present, the builtins bind_function and bind_module are the only partial evaluators, and these do not compute values, but rather replace named lookup by a faster indexing scheme.