eval

Edward Kmett ekmett at gmail.com
Wed Jul 19 13:13:26 PDT 2006


Hello, I've been lurking here for a couple of weeks now. I put together an
ECMAScript 3-in-ECMAScript 3 CPS transformer so I could use javascript to do
some heavy-lifting for a commercial application, and decided I would try my
hand at writing an ECMAScript 4 compiler/interpreter in Haskell using the
"hsplugins" interface and Template Haskell to dynamically compile code
fragments as needed.

To that end, I have been combing through the public export of the es4 wiki,
and while I have seen mention of a comment or two recommending that eval be
turned into an expression level keyword, I am curious to know if a more
tenable resolution has been proposed. As has been noted, eval can't be
written as a function in the language presently. * *It is currently noted as
a function on the global object, but this leaves open to question what the
behavior of a function variable assigned to 'eval' is.

Investigating yields:

var myeval = eval;
var foo = function() { var foo = 12; myeval("foo = 13"); print(foo); }
foo();
print(foo);*

*Spidermonkey prints:
12
13

while JScript.NET <http://jscript.net> prints (with an appropriate
definition for print)
13
function() { ... }

While one could argue that the JScript.NET implementation is more correct
for the interpretation of *"*eval as a function," it is not conducive to
being able to construct any form of optimized compiled form for the language
in strict mode.

I also realize that eval can't be granted full keyword status without
breaking legacy code that relies on the old Object.eval behavior or the
ability to run across windows, but I am curious if the Spidermonkey behavior
exhibited above might be formalized or allowed by making it so that eval
occuring in a primary expression context to be treated like a keyword, much
like the other contextual keywords get, set, each, etc.

This would allow us to code to skim the AST for "eval expression" as a
primary expression or "with" and optimize the representation of lexical
scopes if they are not present in the subtree of a given function/block.
This wouldn't violate the one-pass rule because it would be a strict
optimization anyways and is _almost_ invisible, and would appear to affect
the vast majority of lexical scopes.

Making it 'eval expression' instead of a function call makes the difference
in semantics clear, and still allows the legacy syntax, because the
expression can be parenthesized.

The existing "otherwindow.eval" cases can still function by way of invoking
a member function with the same name as the non-reserved keyword.

Consequences and variations:

Using it formally as a non-reserved keyword in the grammar might or might
not be more headache than just skimming for the appropriate identifier in
'primary' position, but either way this approach might be a viable partial
resolution to the efficiency problem it poses.
**
Attempting to rename 'eval' to 'evaluate' by  "var evaluate = eval;" would
grab a reference to the member function eval on the global object, and calls
to evaluate would resolve in the global scope rather than the local scope.
On the other hand, from the spidermonkey example above, it seems like some
implementations out there do something like this way already, so any
existing code out there that relies on the jscript behavior won't work in a
good fraction of existing browsers anyways.

An alternative behavior would be to make eval a bound member function of the
current lexical scope, then the statement 'var evaluate = eval;' actualy
gains the power to say that i want to evaluate the expression in whatever
the current lexical scope is. This would allow you to return the result
function and use it multiple times accessing the appropriate closure, and
you don't pay for the feature in the scopes that don't use eval. One
advantage of this is that it would allow function decorator hacks that need
to evaluate their output as a string in the function's originating context
like: eval((function (...) {...}).cps()) to be reexpressed as
(function(..){...}).cps(eval); where the eval function passed in grants
access to the current lexical scope, and since its in primary position, it
is clear that the current function scope needs to support eval.

How should either of these interact with a user who redefines the global
object's eval function or creates a function named eval that is in scope?

The above approach would let actionscript-style strict implemetations
continue to enjoy the compiled speed advantage except where the flexibility
of eval is needed.

The alternative behavior mentioned above lets you extend the power of eval
to evaluate in a particular scope chain repeatedly as a playground of sorts,
but might be needlessly complex and doesn't follow the existing behavior of
any existing implementation.

Anyways, am I totally off the mark here? In either case, I think perhaps
"what you can assume about eval" should at least be specified.

-Edward Kmett
http://slipwave.info/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.mozilla.org/pipermail/es-discuss/attachments/20060719/45c94dcd/attachment.html 


More information about the Es4-discuss mailing list