This is a really sick hack that should only be used internally in the
compiler. It's something I'm pretty embarrassed about that I put in
the compiler as a quick fix when I first started working on it.
Basically, it used to be that <script> tags were just compiled at the
top level. But this really confused people when they mixed <script>
and any other subclass of <node>, because it was as if all the
<script> bodies were evaluated first (which led to many errors when
people expected the script bodies to be evaluated in lexical order).
So, the hack was to enclose each script in a function, but set a flag
in the compiler so that when you compiled that function you turned any
top-level (to the function body) variable or function declarations
into global assignments. See CodeGenerator line 2061 and
JavascriptGenerator line 1481. The resulting function is then emitted
in a way that puts it in the instantiation queue in the right order so
that it gets evaluated in the lexical order the user expects. (And
you can turn this rewrite off in LZX by saying <script
when="immediate" />.)
The reason I call this a hack is that what we _really_ want in the
compiler is to have separate phases for source-to-source
transformations (like what scriptElement does, and like what we do to
optimize setAttribute) and have a separate phase for code generation.
Instead both phases are muddled together and Don and I had to invent
the 'passThroughNode' to get around cases where you don't want a
rewrite of a rewrite. It's not clear to me how to fix this without a
complete overhaul of the compiler...
The reason for the scriptElement in the debugger evals is because the
debugger eval compiler depends on compiling, loading, and executing an
anonymous function, but we want to give the debug user the illusion
that his expressions are being evaluated in a persistent environment
and can be referred to in subsequent statements -- so we take
advantage of that hack in the compiler to make it so when the user
types:
var foo = 3;
it has the effect of a global declaration, creating `foo` and setting
it to `3`. Similarly for if the user types a function declaration, we
want it to define a global binding. Otherwise, the user's
declarations would only be in effect for the one evaluation and would
be useless.
Putting these declarations in the global environment isn't really
right, just expedient. Ideally, what we'd like to do is have any
variable and function declarations typed to the debug evaluator define
properties in Debug.environment, not in the global scope. The only
time a expression in the debug evaluator should affect the global
(application) scope is for an assignment expression, not for a
declaration.
On 2009-09-27, at 09:08, André Bargull wrote:
I've just started the work and now I stumbled across this unknown
pragma: #pragma 'scriptElement'
What does it do?
On 9/27/2009 2:52 PM, P T Withington wrote:
Yes, they should be accessible in complex expressions (evaluated in
the debugger). And yes, it is probably a simple matter of updating
compileAndWriteToSWF. I just think no one ever got around to it.
It would be great if you want to do that.
On 2009-09-27, at 08:49, André Bargull wrote:
So, should it be possible to access these shortcuts anywhere else
than while eval'ing an expression and/or should it be possible to
use them in complex expressions? At least according to the Lisp
reference, it should be possible to use them in complex
expressions, but that's currently only possible in swf8 and dhtml.
And only in swf8, you can access the values globally, but that
doesn't seem to be intended as you said below.
If Compiler#compileAndWriteToSWF() and
Compiler#compileAndWriteToAS3() are changed to include `with
(Debug.environment) { ... }`, it should be possible to use the
shortcuts in complex expressions and avoid polluting the global
namespace. These changes seem to be quite easy or did I miss
anything?
On 9/27/2009 1:46 PM, P T Withington wrote:
These are shortcuts that old Lisp hackers know by heart (http://bit.ly/2Ll3qS
), although they have been renamed to be legal Javascript
symbols. This is why we have not felt any need to document
them. :)
They are supposed to work in all runtimes. In an attempt to
reduce global namespace pollution, I moved them out of the global
namespace into `Debug.environment` (which is where they more
properly belong -- the Debugger should not be storing its state
in the application's namespace), as is stated in your first
reference. See the note at line 91 of swf9/LzDebug.as. What
really needs to happen is for the swf9 debug evaluator to wrap
`with (Debug.environment) { ... }` around the expressions it
compiles, just as dhtml/LzDebug.js does in `doEval`. I think
this has to happen in the compiler, not the debugger, because of
the other code the compiler wraps around evaluations to
heuristicate whether it is an expression or statement and to
report errors.
On 2009-09-27, at 07:06, André Bargull wrote:
The last three results of debugger evals are stored in '_', '__'
and '___' to provide a fast way to access these values again.
Currently, swf8 stores the values in the global object, whereas
AS3 runtimes store the values in the global object "global".
This means in swf8 you could write 'Debug.write("last result was
%#w", _)', but this is currently not possible in swf9/swf10. My
question: Should this be considered as a bug? I don't think
there is any official documentation for these short-hands [1],
so maybe it was only intended that '_' as a single expression
should work?!
PS: '_' as a single expression works in swf9/swf10, because
that's a "simple expression" and therefore handled by
"evalSimpleExpr" which calls "globalValue" and "globalValue"
looks up values in the global object "global".
[1] Google only found these two results:
- http://www.openlaszlo.org/pipermail/laszlo-dev/2009-June/021356.html
- http://jira.openlaszlo.org/jira/browse/LPP-630