diff --git a/core/src/avm2/activation.rs b/core/src/avm2/activation.rs index 216e8e814..9bee056e8 100644 --- a/core/src/avm2/activation.rs +++ b/core/src/avm2/activation.rs @@ -450,6 +450,7 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Op::DeleteProperty { index } => self.op_delete_property(method, index), Op::GetSuper { index } => self.op_get_super(method, index), Op::SetSuper { index } => self.op_set_super(method, index), + Op::In => self.op_in(), Op::PushScope => self.op_push_scope(), Op::PushWith => self.op_push_with(), Op::PopScope => self.op_pop_scope(), @@ -1033,6 +1034,24 @@ impl<'a, 'gc, 'gc_context> Activation<'a, 'gc, 'gc_context> { Ok(FrameControl::Continue) } + fn op_in(&mut self) -> Result, Error> { + let obj = self.context.avm2.pop().coerce_to_object(self)?; + let name = self.context.avm2.pop().coerce_to_string(self)?; + + let mut has_prop = false; + + if let Some(ns) = obj.resolve_any(name)? { + if !ns.is_private() { + let qname = QName::new(ns, name); + has_prop = obj.has_property(&qname)?; + } + } + + self.context.avm2.push(has_prop); + + Ok(FrameControl::Continue) + } + fn op_push_scope(&mut self) -> Result, Error> { let object = self.context.avm2.pop().coerce_to_object(self)?; let scope_stack = self.scope(); diff --git a/core/tests/regression_tests.rs b/core/tests/regression_tests.rs index 86b7132d4..3f1cfe491 100644 --- a/core/tests/regression_tests.rs +++ b/core/tests/regression_tests.rs @@ -351,6 +351,7 @@ swf_tests! { (as3_rshift, "avm2/rshift", 1), (as3_subtract, "avm2/subtract", 1), (as3_urshift, "avm2/urshift", 1), + (as3_in, "avm2/in", 1), } // TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough. diff --git a/core/tests/swfs/avm2/in/Test.as b/core/tests/swfs/avm2/in/Test.as new file mode 100644 index 000000000..8db2bb63c --- /dev/null +++ b/core/tests/swfs/avm2/in/Test.as @@ -0,0 +1,177 @@ +package { + public class Test {} +} + +class ES4Class extends Object { + public var test_var = "var"; + public const test_const = "const"; + + public function test_function() { + trace("test_function"); + } + + public function get test_virt() { + return "test_virt"; + } + + public function set test_virt(val) { + trace("test_virt"); + } + + public static var test_static_var = "var"; + public static const test_static_const = "const"; + + public static function test_static_function() { + trace("test_static_function"); + } + + public static function get test_static_virt() { + return "test_static_virt"; + } + + public static function set test_static_virt(val) { + trace("test_static_virt"); + } + + private var test_private_var = "private_var"; + private const test_private_const = "private_const"; + + private function test_private_function() { + trace("test_private_function"); + } + + private function get test_private_virt() { + return "test_private_virt"; + } + + private function set test_private_virt(val) { + trace("test_private_virt"); + } +} + +function ES3Class() { + this.test_var = "var"; +} + +ES3Class.test_static_var = "var"; + +ES3Class.test_static_function = function () { + trace("test_static_function"); +} + +ES3Class.prototype.test_function = function() { + trace("test_function"); +} + +ES3Class.prototype.test_proto = "proto_var"; + +var es4inst = new ES4Class(); +var es3inst = new ES3Class(); + +trace("//'test_var' in es4inst"); +trace('test_var' in es4inst); +trace("//'test_const' in es4inst"); +trace('test_const' in es4inst); +trace("//'test_function' in es4inst"); +trace('test_function' in es4inst); +trace("//'test_virt' in es4inst"); +trace('test_virt' in es4inst); +trace("//'test_static_var' in es4inst"); +trace('test_static_var' in es4inst); +trace("//'test_static_const' in es4inst"); +trace('test_static_const' in es4inst); +trace("//'test_static_function' in es4inst"); +trace('test_static_function' in es4inst); +trace("//'test_static_virt' in es4inst"); +trace('test_static_virt' in es4inst); +trace("//'test_private_var' in es4inst"); +trace('test_private_var' in es4inst); +trace("//'test_private_const' in es4inst"); +trace('test_private_const' in es4inst); +trace("//'test_private_function' in es4inst"); +trace('test_private_function' in es4inst); +trace("//'test_private_virt' in es4inst"); +trace('test_private_virt' in es4inst); + +trace("//'test_var' in ES4Class"); +trace('test_var' in ES4Class); +trace("//'test_const' in ES4Class"); +trace('test_const' in ES4Class); +trace("//'test_function' in ES4Class"); +trace('test_function' in ES4Class); +trace("//'test_virt' in ES4Class"); +trace('test_virt' in ES4Class); +trace("//'test_static_var' in ES4Class"); +trace('test_static_var' in ES4Class); +trace("//'test_static_const' in ES4Class"); +trace('test_static_const' in ES4Class); +trace("//'test_static_function' in ES4Class"); +trace('test_static_function' in ES4Class); +trace("//'test_static_virt' in ES4Class"); +trace('test_static_virt' in ES4Class); +trace("//'test_private_var' in ES4Class"); +trace('test_private_var' in ES4Class); +trace("//'test_private_const' in ES4Class"); +trace('test_private_const' in ES4Class); +trace("//'test_private_function' in ES4Class"); +trace('test_private_function' in ES4Class); +trace("//'test_private_virt' in ES4Class"); +trace('test_private_virt' in ES4Class); + +trace("//'test_var' in ES4Class.prototype"); +trace('test_var' in ES4Class.prototype); +trace("//'test_const' in ES4Class.prototype"); +trace('test_const' in ES4Class.prototype); +trace("//'test_function' in ES4Class.prototype"); +trace('test_function' in ES4Class.prototype); +trace("//'test_virt' in ES4Class.prototype"); +trace('test_virt' in ES4Class.prototype); +trace("//'test_static_var' in ES4Class.prototype"); +trace('test_static_var' in ES4Class.prototype); +trace("//'test_static_const' in ES4Class.prototype"); +trace('test_static_const' in ES4Class.prototype); +trace("//'test_static_function' in ES4Class.prototype"); +trace('test_static_function' in ES4Class.prototype); +trace("//'test_static_virt' in ES4Class.prototype"); +trace('test_static_virt' in ES4Class.prototype); +trace("//'test_private_var' in ES4Class.prototype"); +trace('test_private_var' in ES4Class.prototype); +trace("//'test_private_const' in ES4Class.prototype"); +trace('test_private_const' in ES4Class.prototype); +trace("//'test_private_function' in ES4Class.prototype"); +trace('test_private_function' in ES4Class.prototype); +trace("//'test_private_virt' in ES4Class.prototype"); +trace('test_private_virt' in ES4Class.prototype); + +trace("//'test_var' in es3inst"); +trace('test_var' in es3inst); +trace("//'test_function' in es3inst"); +trace('test_function' in es3inst); +trace("//'test_proto' in es3inst"); +trace('test_proto' in es3inst); +trace("//'test_static_var' in es3inst"); +trace('test_static_var' in es3inst); +trace("//'test_static_function' in es3inst"); +trace('test_static_function' in es3inst); + +trace("//'test_var' in ES3Class"); +trace('test_var' in ES3Class); +trace("//'test_function' in ES3Class"); +trace('test_function' in ES3Class); +trace("//'test_proto' in ES3Class"); +trace('test_proto' in ES3Class); +trace("//'test_static_var' in ES3Class"); +trace('test_static_var' in ES3Class); +trace("//'test_static_function' in ES3Class"); +trace('test_static_function' in ES3Class); + +trace("//'test_var' in ES3Class.prototype"); +trace('test_var' in ES3Class.prototype); +trace("//'test_function' in ES3Class.prototype"); +trace('test_function' in ES3Class.prototype); +trace("//'test_proto' in ES3Class.prototype"); +trace('test_proto' in ES3Class.prototype); +trace("//'test_static_var' in ES3Class.prototype"); +trace('test_static_var' in ES3Class.prototype); +trace("//'test_static_function' in ES3Class.prototype"); +trace('test_static_function' in ES3Class.prototype); \ No newline at end of file diff --git a/core/tests/swfs/avm2/in/output.txt b/core/tests/swfs/avm2/in/output.txt new file mode 100644 index 000000000..a643aba1f --- /dev/null +++ b/core/tests/swfs/avm2/in/output.txt @@ -0,0 +1,102 @@ +//'test_var' in es4inst +true +//'test_const' in es4inst +true +//'test_function' in es4inst +true +//'test_virt' in es4inst +true +//'test_static_var' in es4inst +false +//'test_static_const' in es4inst +false +//'test_static_function' in es4inst +false +//'test_static_virt' in es4inst +false +//'test_private_var' in es4inst +false +//'test_private_const' in es4inst +false +//'test_private_function' in es4inst +false +//'test_private_virt' in es4inst +false +//'test_var' in ES4Class +false +//'test_const' in ES4Class +false +//'test_function' in ES4Class +false +//'test_virt' in ES4Class +false +//'test_static_var' in ES4Class +true +//'test_static_const' in ES4Class +true +//'test_static_function' in ES4Class +true +//'test_static_virt' in ES4Class +true +//'test_private_var' in ES4Class +false +//'test_private_const' in ES4Class +false +//'test_private_function' in ES4Class +false +//'test_private_virt' in ES4Class +false +//'test_var' in ES4Class.prototype +false +//'test_const' in ES4Class.prototype +false +//'test_function' in ES4Class.prototype +false +//'test_virt' in ES4Class.prototype +false +//'test_static_var' in ES4Class.prototype +false +//'test_static_const' in ES4Class.prototype +false +//'test_static_function' in ES4Class.prototype +false +//'test_static_virt' in ES4Class.prototype +false +//'test_private_var' in ES4Class.prototype +false +//'test_private_const' in ES4Class.prototype +false +//'test_private_function' in ES4Class.prototype +false +//'test_private_virt' in ES4Class.prototype +false +//'test_var' in es3inst +true +//'test_function' in es3inst +true +//'test_proto' in es3inst +true +//'test_static_var' in es3inst +false +//'test_static_function' in es3inst +false +//'test_var' in ES3Class +false +//'test_function' in ES3Class +false +//'test_proto' in ES3Class +false +//'test_static_var' in ES3Class +true +//'test_static_function' in ES3Class +true +//'test_var' in ES3Class.prototype +false +//'test_function' in ES3Class.prototype +true +//'test_proto' in ES3Class.prototype +true +//'test_static_var' in ES3Class.prototype +false +//'test_static_function' in ES3Class.prototype +false diff --git a/core/tests/swfs/avm2/in/test.fla b/core/tests/swfs/avm2/in/test.fla new file mode 100644 index 000000000..9117e9f0b Binary files /dev/null and b/core/tests/swfs/avm2/in/test.fla differ diff --git a/core/tests/swfs/avm2/in/test.swf b/core/tests/swfs/avm2/in/test.swf new file mode 100644 index 000000000..fbdcef2da Binary files /dev/null and b/core/tests/swfs/avm2/in/test.swf differ