CVSROOT: /sources/gnash Module name: gnash Changes by: Sandro Santilli <strk> 07/11/01 16:14:21
Modified files: . : ChangeLog libbase : GnashException.h server : as_value.cpp as_value.h server/vm : ASHandlers.cpp fn_call.h testsuite/actionscript.all: toString_valueOf.as testsuite/swfdec: PASSING Log message: * libbase/GnashException.h: Add ActionTypeError exception. * server/as_value.{cpp,h} (to_primitive): a closer to ECMA-262 [[ToPrimitive]] implementation. * server/vm/ASHandlers.cpp: update use of as_value::to_primitive. * testsuite/actionscript.all/toString_valueOf.as: two successes. * testsuite/swfdec/PASSING: some more successes. * server/vm/fn_call.h (dump_args): print debug string version for each argument. CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.4754&r2=1.4755 http://cvs.savannah.gnu.org/viewcvs/gnash/libbase/GnashException.h?cvsroot=gnash&r1=1.10&r2=1.11 http://cvs.savannah.gnu.org/viewcvs/gnash/server/as_value.cpp?cvsroot=gnash&r1=1.91&r2=1.92 http://cvs.savannah.gnu.org/viewcvs/gnash/server/as_value.h?cvsroot=gnash&r1=1.72&r2=1.73 http://cvs.savannah.gnu.org/viewcvs/gnash/server/vm/ASHandlers.cpp?cvsroot=gnash&r1=1.147&r2=1.148 http://cvs.savannah.gnu.org/viewcvs/gnash/server/vm/fn_call.h?cvsroot=gnash&r1=1.11&r2=1.12 http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/toString_valueOf.as?cvsroot=gnash&r1=1.28&r2=1.29 http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/swfdec/PASSING?cvsroot=gnash&r1=1.52&r2=1.53 Patches: Index: ChangeLog =================================================================== RCS file: /sources/gnash/gnash/ChangeLog,v retrieving revision 1.4754 retrieving revision 1.4755 diff -u -b -r1.4754 -r1.4755 --- ChangeLog 1 Nov 2007 10:29:54 -0000 1.4754 +++ ChangeLog 1 Nov 2007 16:14:19 -0000 1.4755 @@ -1,3 +1,14 @@ +2007-11-01 Sandro Santilli <[EMAIL PROTECTED]> + + * libbase/GnashException.h: Add ActionTypeError exception. + * server/as_value.{cpp,h} (to_primitive): a closer to ECMA-262 + [[ToPrimitive]] implementation. + * server/vm/ASHandlers.cpp: update use of as_value::to_primitive. + * testsuite/actionscript.all/toString_valueOf.as: two successes. + * testsuite/swfdec/PASSING: some more successes. + * server/vm/fn_call.h (dump_args): print debug string version + for each argument. + 2007-11-01 Bastiaan Jacques <[EMAIL PROTECTED]> * backend/render_handler_cairo.cpp: Implement draw_poly. Index: libbase/GnashException.h =================================================================== RCS file: /sources/gnash/gnash/libbase/GnashException.h,v retrieving revision 1.10 retrieving revision 1.11 diff -u -b -r1.10 -r1.11 --- libbase/GnashException.h 1 Jul 2007 10:54:06 -0000 1.10 +++ libbase/GnashException.h 1 Nov 2007 16:14:20 -0000 1.11 @@ -116,6 +116,31 @@ }; +/// An ActionScript type error +// +/// This exception can be thrown by as_value::to_primitive when an object +/// can't be converted to a primitive value or by native function when +/// they are called as method of an unexpected type +/// +class ActionTypeError: public ActionException +{ + +public: + + ActionTypeError(const std::string& s) + : + ActionException(s) + {} + + ActionTypeError() + : + ActionException("ActionTypeError") + {} + + virtual ~ActionTypeError() throw() {} + +}; + } // namespace gnash #endif // def _GNASH_GNASHEXCEPTION__H Index: server/as_value.cpp =================================================================== RCS file: /sources/gnash/gnash/server/as_value.cpp,v retrieving revision 1.91 retrieving revision 1.92 diff -u -b -r1.91 -r1.92 --- server/as_value.cpp 30 Oct 2007 18:55:42 -0000 1.91 +++ server/as_value.cpp 1 Nov 2007 16:14:20 -0000 1.92 @@ -46,7 +46,10 @@ #endif // Define the macro below to make abstract equality operator verbose -//#define GNASH_DEBUG_EQUALITY +//#define GNASH_DEBUG_EQUALITY 1 + +// Define the macro below to make to_primitive verbose +//#define GNASH_DEBUG_CONVERSION_TO_PRIMITIVE 1 namespace gnash { @@ -115,49 +118,31 @@ case AS_FUNCTION: { as_object* obj = m_type == OBJECT ? getObj().get() : getFun().get(); - - //printf("as_value to string conversion, env=%p\n", env); - // @@ Moock says, "the value that results from - // calling toString() on the object". - // - // When the toString() method doesn't exist, or - // doesn't return a valid number, the default - // text representation for that object is used - // instead. - // - if ( ! obj->useCustomToString() ) - { - return obj->get_text_value(); - } - - bool gotValidToStringResult = false; if ( env ) { - string_table::key methodname = NSV::PROP_TO_STRING; - as_value method; - if ( obj->get_member(methodname, &method) ) - { - as_value ret = call_method0(method, env, obj); - if ( ret.is_string() ) + try { - gotValidToStringResult=true; - return ret.to_string(); // no need to env, it's a string already - } - log_msg(_("[object %p].%s() did not return a string: %s"), - (void*)obj, VM::get().getStringTable().value(methodname).c_str(), - ret.to_debug_string().c_str()); + as_value ret = to_primitive(*env, STRING); + // This additional is_string test is NOT compliant with ECMA-262 + // specification, but seems required for compatibility with the + // reference player. +#if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug(" %s.to_primitive(STRING) returned %s", to_debug_string().c_str(), ret.to_debug_string().c_str()); +#endif + if ( ret.is_string() ) return ret.to_string(); } - else + catch (ActionTypeError& e) { - log_msg(_("get_member(%s) returned false"), VM::get().getStringTable().value(methodname).c_str()); + log_debug(_("to_primitive(%s, STRING) threw an ActionTypeError %s"), + to_debug_string().c_str(), e.what()); } } - if ( m_type == OBJECT ) - { - return "[type Object]"; - } + else log_debug("%s.to_number() called w/out env", to_debug_string().c_str()); + + if ( m_type == OBJECT ) return "[type Object]"; assert(m_type == AS_FUNCTION); return "[type Function]"; + } default: @@ -228,6 +213,13 @@ hint = STRING; } +#if 0 + else if ( m_type == MOVIECLIP && swfVersion > 5 ) + { + throw ActionTypeError(); + } +#endif + return to_primitive(env, hint); } @@ -236,28 +228,102 @@ as_value::to_primitive(as_environment& env, type hint) const { if ( m_type != OBJECT && m_type != AS_FUNCTION ) return *this; + //if ( ! is_object() ) return *this; // include MOVIECLIP !! + +#if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug("to_primitive(%s)", hint==NUMBER ? "NUMBER" : "STRING"); +#endif + + // TODO: implement as_object::DefaultValue (ECMA-262 - 8.6.2.6) - as_object* obj; + as_value method; + as_object* obj = NULL; + + if (hint == NUMBER) + { +#if 1 + if ( m_type == MOVIECLIP ) + { + return as_value(NAN); + } +#endif if ( m_type == OBJECT ) obj = getObj().get(); else obj = getFun().get(); - // TODO: implement DefaultValue (ECMA-262 - 8.6.2.6) + if ( (!obj->get_member(NSV::PROP_VALUE_OF, &method)) || (!method.is_function()) ) // ECMA says ! is_object() + { +#if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug(" valueOf not found"); +#endif + if ( (!obj->get_member(NSV::PROP_TO_STRING, &method)) || (!method.is_function()) ) // ECMA says ! is_object() + { +#if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug(" toString not found"); +#endif + throw ActionTypeError(); + } + } + } + else + { + assert(hint==STRING); - string_table::key methodname; - if (hint == NUMBER) { methodname=NSV::PROP_VALUE_OF; } - else { assert(hint==STRING); methodname=NSV::PROP_TO_STRING; } +#if 1 + if ( m_type == MOVIECLIP ) + { + return as_value(getSpriteProxy().getTarget()); + } +#endif - as_value method; - if ( obj->get_member(methodname, &method) ) + if ( m_type == OBJECT ) obj = getObj().get(); + else obj = getFun().get(); + + //printf("as_value to string conversion, env=%p\n", env); + // @@ Moock says, "the value that results from + // calling toString() on the object". + // + // When the toString() method doesn't exist, or + // doesn't return a valid number, the default + // text representation for that object is used + // instead. + // + if ( ! obj->useCustomToString() ) { - return call_method0(method, &env, obj); +#if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug(" not using custom toString"); +#endif + return as_value(obj->get_text_value()); } - else + + if ( (!obj->get_member(NSV::PROP_TO_STRING, &method)) || (!method.is_function()) ) // ECMA says ! is_object() + { +#if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug(" toString not found"); +#endif + if ( (!obj->get_member(NSV::PROP_VALUE_OF, &method)) || (!method.is_function()) ) // ECMA says ! is_object() + { +#if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug(" valueOf not found"); +#endif + //return as_value(obj->get_text_value()); + throw ActionTypeError(); + } + } + } + + assert(obj); + + as_value ret = call_method0(method, &env, obj); +#if GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug("to_primitive: method call returned %s", ret.to_debug_string().c_str()); +#endif + if ( ret.m_type == OBJECT || ret.m_type == AS_FUNCTION ) // not a primitive { - log_msg(_("get_member(%s) returned false"), VM::get().getStringTable().value(methodname).c_str()); + throw ActionTypeError(); } - return *this; + + return ret; } @@ -322,24 +388,16 @@ as_object* obj = m_type == OBJECT ? getObj().get() : getFun().get(); if ( env ) { - string_table::key methodname = NSV::PROP_VALUE_OF; - as_value method; - if (obj->get_member(methodname, &method) ) - { - as_value ret = call_method0(method, env, obj); - if ( ret.is_number() ) - { - return ret.getNum(); - } - else if ( ret.is_string() ) + try { + as_value ret = to_primitive(*env, NUMBER); + // env shouldn't be needed as to_primitive ensure a primitive type is returned return ret.to_number(); } - else + catch (ActionTypeError& e) { - log_msg(_("[object %p].%s() did not return a number: %s"), - (void*)obj, VM::get().getStringTable().value(methodname).c_str(), - ret.to_debug_string().c_str()); + log_debug(_("to_primitive(%s, NUMBER) threw an ActionTypeError %s"), + to_debug_string().c_str(), e.what()); if ( m_type == AS_FUNCTION && swfversion < 6 ) { return 0; @@ -352,11 +410,10 @@ } else { - log_msg(_("get_member(%s) returned false"), VM::get().getStringTable().value(methodname).c_str()); - } - } + log_debug("%s.to_number() called w/out env", to_debug_string().c_str()); return obj->get_numeric_value(); } + } case MOVIECLIP: // This is tested, no valueOf is going @@ -746,53 +803,117 @@ // 20. If Type(x) is either String or Number and Type(y) is Object, // return the result of the comparison x == ToPrimitive(y). - if ( (m_type == STRING || m_type == NUMBER ) && ( v.is_object() ) ) // v.m_type == OBJECT || v.m_type == AS_FUNCTION ) ) + if ( (m_type == STRING || m_type == NUMBER ) && ( v.m_type == OBJECT || v.m_type == AS_FUNCTION ) ) { // convert this value to a primitive and recurse + try + { as_value v2 = v.to_primitive(env); + if ( v.strictly_equals(v2) ) return false; + #ifdef GNASH_DEBUG_EQUALITY - log_debug(" convertion to primitive : %s -> %s", v.to_debug_string().c_str(), v2.to_debug_string().c_str()); + log_debug(" 20: convertion to primitive : %s -> %s", v.to_debug_string().c_str(), v2.to_debug_string().c_str()); #endif - if ( v.strictly_equals(v2) ) // returned self ? + + return equals(v2, env); + } + catch (ActionTypeError& e) { +//#ifdef GNASH_DEBUG_EQUALITY + log_debug(" %s.to_primitive() threw an ActionTypeError %s", v.to_debug_string().c_str(), e.what()); +//#endif return false; // no valid conversion } - else return equals(v2, env); + } // 21. If Type(x) is Object and Type(y) is either String or Number, // return the result of the comparison ToPrimitive(x) == y. - if ( (v.m_type == STRING || v.m_type == NUMBER ) && ( is_object() ) ) // m_type == OBJECT || m_type == AS_FUNCTION ) ) + if ( (v.m_type == STRING || v.m_type == NUMBER ) && ( m_type == OBJECT || m_type == AS_FUNCTION ) ) { // convert this value to a primitive and recurse + try + { as_value v2 = to_primitive(env); + if ( strictly_equals(v2) ) return false; + #ifdef GNASH_DEBUG_EQUALITY - log_debug(" convertion to primitive : %s -> %s", to_debug_string().c_str(), v2.to_debug_string().c_str()); + log_debug(" 21: convertion to primitive : %s -> %s", to_debug_string().c_str(), v2.to_debug_string().c_str()); #endif - if ( strictly_equals(v2) ) // returned self ? + + return v2.equals(v, env); + } + catch (ActionTypeError& e) { + +//#ifdef GNASH_DEBUG_EQUALITY + log_debug(" %s.to_primitive() threw an ActionTypeError %s", to_debug_string().c_str(), e.what()); +//#endif + return false; // no valid conversion } - else return v2.equals(v, env); + } // Both operands are objects (OBJECT,AS_FUNCTION,MOVIECLIP) - assert(is_object() && v.is_object()); + if ( ! is_object() || ! v.is_object() ) + { + log_error("Equals(%s,%s)", to_debug_string().c_str(), v.to_debug_string().c_str()); + } // If any of the two converts to a primitive, we recurse - as_value p = to_primitive(env); - as_value vp = v.to_primitive(env); + as_value p = *this; + as_value vp = v; + + int converted = 0; + try + { + p = to_primitive(env); + if ( ! strictly_equals(p) ) ++converted; #ifdef GNASH_DEBUG_EQUALITY log_debug(" convertion to primitive (this): %s -> %s", to_debug_string().c_str(), p.to_debug_string().c_str()); +#endif + } + catch (ActionTypeError& e) + { +#ifdef GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug(" %s.to_primitive() threw an ActionTypeError %s", + to_debug_string().c_str(), e.what()); +#endif + } + + try + { + vp = v.to_primitive(env); + if ( ! v.strictly_equals(vp) ) ++converted; +#ifdef GNASH_DEBUG_EQUALITY log_debug(" convertion to primitive (that): %s -> %s", v.to_debug_string().c_str(), vp.to_debug_string().c_str()); #endif - if ( strictly_equals(p) && v.strictly_equals(vp) ) // both returned self ? + } + catch (ActionTypeError& e) { - return false; // no valid conversion +#ifdef GNASH_DEBUG_CONVERSION_TO_PRIMITIVE + log_debug(" %s.to_primitive() threw an ActionTypeError %s", + v.to_debug_string().c_str(), e.what()); +#endif } + if ( converted ) + { +#ifdef GNASH_DEBUG_EQUALITY + log_debug(" some conversion took place, recurring"); +#endif return p.equals(vp, env); + } + else + { +#ifdef GNASH_DEBUG_EQUALITY + log_debug(" no conversion took place, returning false"); +#endif + return false; + } + } Index: server/as_value.h =================================================================== RCS file: /sources/gnash/gnash/server/as_value.h,v retrieving revision 1.72 retrieving revision 1.73 diff -u -b -r1.72 -r1.73 --- server/as_value.h 26 Oct 2007 07:39:47 -0000 1.72 +++ server/as_value.h 1 Nov 2007 16:14:20 -0000 1.73 @@ -15,7 +15,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -/* $Id: as_value.h,v 1.72 2007/10/26 07:39:47 strk Exp $ */ +/* $Id: as_value.h,v 1.73 2007/11/01 16:14:20 strk Exp $ */ #ifndef GNASH_AS_VALUE_H #define GNASH_AS_VALUE_H @@ -387,6 +387,8 @@ /// @param env /// The environment to use for calling the valueOf method. /// + /// @throw ActionTypeError if an object can't be converted to a primitive + /// as_value to_primitive(as_environment& env) const; /// Return value as a primitive type, with a preference @@ -400,6 +402,8 @@ /// @param hint /// NUMBER or STRING, the preferred representation we're asking for. /// + /// @throw ActionTypeError if an object can't be converted to a primitive + /// as_value to_primitive(as_environment& env, type hint) const; /// Force type to number. Index: server/vm/ASHandlers.cpp =================================================================== RCS file: /sources/gnash/gnash/server/vm/ASHandlers.cpp,v retrieving revision 1.147 retrieving revision 1.148 diff -u -b -r1.147 -r1.148 --- server/vm/ASHandlers.cpp 31 Oct 2007 08:28:41 -0000 1.147 +++ server/vm/ASHandlers.cpp 1 Nov 2007 16:14:20 -0000 1.148 @@ -17,7 +17,7 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // -/* $Id: ASHandlers.cpp,v 1.147 2007/10/31 08:28:41 strk Exp $ */ +/* $Id: ASHandlers.cpp,v 1.148 2007/11/01 16:14:20 strk Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -2814,17 +2814,30 @@ size_t stackSize = env.stack_size(); #endif - as_value v1 = env.top(0).to_primitive(env); - as_value v2 = env.top(1).to_primitive(env); + as_value v1 = env.top(0); + as_value v2 = env.top(1); - assert( stackSize == env.stack_size() ); + try { v1 = v1.to_primitive(env); } + catch (ActionTypeError& e) + { + log_debug("%s.to_primitive() threw an error during ActionNewAdd", + env.top(0).to_debug_string().c_str()); + } + + try { v2 = v2.to_primitive(env); } + catch (ActionTypeError& e) + { + log_debug("%s.to_primitive() threw an error during ActionNewAdd", + env.top(1).to_debug_string().c_str()); + } - //log_debug(_("ActionNewAdd(%s, %s) [prim %s, %s] called"), - // env.top(0).to_debug_string().c_str(), - // v2_in.to_debug_string().c_str(), - // env.top(1).to_debug_string().c_str(), - // v2.to_debug_string().c_str()); + assert( stackSize == env.stack_size() ); +#if GNASH_DEBUG + log_debug(_("ActionNewAdd(%s, %s) [primitive conversion done]"), + v1.to_debug_string().c_str(), + v2.to_debug_string().c_str()); +#endif if (v1.is_string() || v2.is_string() ) { @@ -2860,8 +2873,22 @@ as_value& op1_in = env.top(1); as_value& op2_in = env.top(0); - as_value operand1 = op1_in.to_primitive(env); - as_value operand2 = op2_in.to_primitive(env); + as_value operand1; + as_value operand2; + + try { operand1 = op1_in.to_primitive(env); } + catch (ActionTypeError& e) + { + log_debug("%s.to_primitive() threw an error during ActionNewLessThen", + op1_in.to_debug_string().c_str()); + } + + try { operand2 = op2_in.to_primitive(env); } + catch (ActionTypeError& e) + { + log_debug("%s.to_primitive() threw an error during ActionNewLessThen", + op2_in.to_debug_string().c_str()); + } if ( operand1.is_string() && operand2.is_string() ) { Index: server/vm/fn_call.h =================================================================== RCS file: /sources/gnash/gnash/server/vm/fn_call.h,v retrieving revision 1.11 retrieving revision 1.12 diff -u -b -r1.11 -r1.12 --- server/vm/fn_call.h 30 Aug 2007 01:02:49 -0000 1.11 +++ server/vm/fn_call.h 1 Nov 2007 16:14:21 -0000 1.12 @@ -105,7 +105,7 @@ for (unsigned int i=0; i<nargs; ++i) { if ( i ) os << ", "; - os << arg(i).to_string(); + os << arg(i).to_debug_string(); } } Index: testsuite/actionscript.all/toString_valueOf.as =================================================================== RCS file: /sources/gnash/gnash/testsuite/actionscript.all/toString_valueOf.as,v retrieving revision 1.28 retrieving revision 1.29 diff -u -b -r1.28 -r1.29 --- testsuite/actionscript.all/toString_valueOf.as 31 Oct 2007 10:22:23 -0000 1.28 +++ testsuite/actionscript.all/toString_valueOf.as 1 Nov 2007 16:14:21 -0000 1.29 @@ -21,7 +21,7 @@ */ -rcsid="$Id: toString_valueOf.as,v 1.28 2007/10/31 10:22:23 strk Exp $"; +rcsid="$Id: toString_valueOf.as,v 1.29 2007/11/01 16:14:21 strk Exp $"; #include "check.as" @@ -477,9 +477,9 @@ o.v = new Object(); a = "" + o; check_equals(o.valueOfCalls, 1); -xcheck_equals(o.toStringCalls, 1); +check_equals(o.toStringCalls, 1); check_equals(typeof(a), "string"); -xcheck_equals(a, "[type Object]"); +check_equals(a, "[type Object]"); #if OUTPUT_VERSION < 6 Index: testsuite/swfdec/PASSING =================================================================== RCS file: /sources/gnash/gnash/testsuite/swfdec/PASSING,v retrieving revision 1.52 retrieving revision 1.53 diff -u -b -r1.52 -r1.53 --- testsuite/swfdec/PASSING 27 Oct 2007 17:05:21 -0000 1.52 +++ testsuite/swfdec/PASSING 1 Nov 2007 16:14:21 -0000 1.53 @@ -42,6 +42,7 @@ bitwise-5.swf:98475055aae4796a066e7728d5a7a944 bitwise-6.swf:ef818f643cc14a4cc57248473e05a48c bitwise-7.swf:c18505cd0d075c512d15b6d96ab221d0 +call-arguments-5.swf:422c391a2abd3e864eb8ed8a1e05ad31 callfunction-stack.swf:21d0c957f4caf0eb0ccd0dcadaf17500 case1-6.swf:ba805f628a3a2d1bbd292ec1e56d1708 case1-7.swf:ad4cfa4c3df86421237239167414fb40 @@ -439,6 +440,9 @@ this-localfunction-6.swf:02e2d34657330766997697cc52f3f2cf this-localfunction-7.swf:9f25bfae3408892742d94ca208e035ac this-localfunction-8.swf:f917712fb915df27699b0f2615f5f9fa +tointeger-various-5.swf:25fab4b9f2e8739ac63863933a4c7ead +tointeger-various-6.swf:71257f69e5f3feb6ae18ebf26ad2eb22 +tointeger-various-7.swf:6251bc39b6449a82c89b6c821f9af0ff transform.swf:5c8533f9168ca3e92d000ce1693ed5ef try-throw-in-finally-6.swf:1c12d4b0f949704bd0794d73f0385007 try-throw-in-finally-7.swf:0342b214948d6bec886863f6f66cab33 _______________________________________________ Gnash-commit mailing list Gnash-commit@gnu.org http://lists.gnu.org/mailman/listinfo/gnash-commit