Ops and functions that take a movie clip path in String form have
a very forgiving syntax. These include:
* `SetTarget`
* `CloneSprite`
* `RemoveSprite`
* `swapDepths`
This change adds `Avm1::resolve_target_display_object` to parse
these paths correctly, along with `target_paths` test to test a
wide variety of formats.
This also applies to `GetVariable`/`SetVariable`, which accept
target paths to variables and is used by some SWF4/5 content.
(fixes#324, #337).
When setting a variable in a function-local scope, if that variable
has not been defined in the function scope, it should be defined in
the executing movieclip's scope. Previously it would get defined
in the function's scope. Changed Scope::overwrite to Scope::set,
and modified the behavior to stop traversing and define the value
when it hits a movie clip Target scope.
Also, modified With scopes to properly add onto the end of the scope
chain.
`idMap` is a strange property; it's only populated with nodes which had a given `id` *at the time of parsing*, and said nodes continue to be referenced even if the node is removed from the document. I have yet to find a way by which nodes can be deleted from `idMap`.
It also takes expandos, so this has to be a new retained object on the XML document. I originally considered not creating *another* `Object` impl and populating a regular `ScriptObject` with nodes, but that meant we couldn't lazy-instantiate their AVM1 side counterparts. Boo. :/
A lot of the arithmetic ops were still using SWFv4 style coercion
(`Value::into_number_v1`) even though they use full ECMA-262
coercion in SWF5+. This would cause `undefined` to turn into 0
isntead of NaN, for example.
Fixes disappearing player in Achievement Unlocked
(https://www.newgrounds.com/portal/view/474371)
It's possible even the older ops such as ActionAdd should do this,
too. Handcrafted bytecode will need to be used to test as you
cannot export these ops in newer SWF versions from the Flash IDE.
ActionAnd, ActionOr, and ActionNot were incorrectly comparing
to 0. This only works for SWF<4. Now they all go through the
Value::as_bool method to handle version specific behavior.
Value::from_bool_v1 was also renamed to Value::from_bool.
Functions now store their base clip (the code that contains the
executing bytecode). This is because `GotoFrame` and other actions
will execute on the clip the bytecode exists on, not on `this`.
(Note that `this.gotoAndStop` uses `GetMember` actions, which
worked correctly).
`Activation` now stores `target_clip`, and `Avm1::target_clip` and
`target_clip_or_root` grab this from the current stack frame.
Renamed `start_clip` to `base_clip` to match Flash conventions.
Removed `active_clip` as this was superfluous. Now you can use
`Avm1::target_clip_or_root`.
`UpdateContext` no longer contains `target_clip` etc.
Add a check and clear the stack if it isn't empty at the end of
`run_stack_till_empty`. This is probably a bug on our side
and we a good place for breakpoints.
When running an clip event handler (e.g. onEnterFrame), a stack
frame is pushed to get the property value. However, this frame
was causing an extra Undefined to be pushed on the operand stack in
`Avm1::retire_stack_frame`, which would blow out the stack.
Now this stack frame is popped after the property is resolved and
before the function is executed. The function will push its own
stack frame when it executes.
We implement `super` by way of a new `Object` impl which wraps arbitrary objects with a modified prototype chain. Specifically, the lowest layer of the prototype chain is omitted. This new `SuperObject` script is composable: a chain of two `SuperObject`s will go two levels of inheritance upwards while still maintaining non-prototype property access.
Add DisplayObject::slash_path to get the Flash 4-style slash path
to the clip. This fixes the tellTarget regression test and removes
the superfluous `target_path` from `UpdateContext`.