// Execute the ToString algorithm as described in ECMA-262 Section 9.8. // This is ToString(ToPrimitive(input argument, hint String)) // ToPrimitive(input argument, hint String) calls [[DefaultValue]] // described in ECMA-262 8.6.2.6. The [[DefaultValue]] algorithm // with hint String is inlined here. Stringp ScriptObject::toString() { AvmCore *core = this->core(); Toplevel* toplevel = this->toplevel(); Atom atomv_out[1]; // call this.toString() // NOTE use callers versioned public to get correct toString Multiname tempname(core->findPublicNamespace(), core->ktoString); atomv_out[0] = atom(); Atom result = toplevel->callproperty(atom(), &tempname, 0, atomv_out, vtable); // if result is primitive, return its ToString if (atomKind(result) != kObjectType) return core->string(result); // otherwise call this.valueOf() tempname.setName(core->kvalueOf); atomv_out[0] = atom(); result = toplevel->callproperty(atom(), &tempname, 0, atomv_out, vtable); // if result is primitive, return it if (atomKind(result) != kObjectType) return core->string(result); // could not convert to primitive. toplevel->throwTypeError(kConvertToPrimitiveError, core->toErrorString(traits())); return NULL; // unreachable }
// this = argv[0] (ignored) // arg1 = argv[1] // argN = argv[argc] Atom RegExpClass::construct(int argc, Atom* argv) { AvmCore* core = this->core(); Stringp pattern; Atom patternAtom = (argc>0) ? argv[1] : undefinedAtom; Atom optionsAtom = (argc>1) ? argv[2] : undefinedAtom; if (AvmCore::istype(patternAtom, traits()->itraits)) { // Pattern is a RegExp object if (optionsAtom != undefinedAtom) { // ECMA 15.10.4.1 says to throw an error if flags specified toplevel()->throwTypeError(kRegExpFlagsArgumentError); } // Return a clone of the RegExp object RegExpObject* regExpObject = (RegExpObject*)AvmCore::atomToScriptObject(patternAtom); return (new (core->GetGC(), ivtable()->getExtraSize()) RegExpObject(regExpObject))->atom(); } else { if (patternAtom != undefinedAtom) { pattern = core->string(argv[1]); } else { // cn: disable this, breaking ecma3 tests. was: todo look into this. it's what SpiderMonkey does. pattern = core->kEmptyString; //core->newConstantStringLatin1("(?:)"); } } Stringp options = NULL; if (optionsAtom != undefinedAtom) { options = core->string(optionsAtom); } RegExpObject* inst = new (core->GetGC(), ivtable()->getExtraSize()) RegExpObject(this, pattern, options); return inst->atom(); }
Stringp StringClass::_replace(Stringp subject, Atom pattern, Atom replacementAtom) { AvmCore* core = this->core(); ScriptObject *replaceFunction = NULL; Stringp replacement = NULL; if (AvmCore::istype(replacementAtom, core->traits.function_itraits)) { replaceFunction = AvmCore::atomToScriptObject(replacementAtom); } else { replacement = core->string(replacementAtom); } if (AvmCore::istype(pattern, core->traits.regexp_itraits)) { // RegExp mode RegExpObject *reObj = (RegExpObject*) core->atomToScriptObject(pattern); if (replaceFunction) { return core->string(reObj->replace(subject, replaceFunction)); } else { return core->string(reObj->replace(subject, replacement)); } } else { // String replace mode Stringp searchString = core->string(pattern); int index = subject->indexOf(searchString); if (index == -1) { // Search string not found; return input unchanged. return subject; } if (replaceFunction) { // Invoke the replacement function to figure out the // replacement string Atom argv[4] = { undefinedAtom, searchString->atom(), core->uintToAtom(index), subject->atom() }; replacement = core->string(toplevel()->op_call(replaceFunction->atom(), 3, argv)); } Stringp out = subject->substring(0, index); out = String::concatStrings(out, replacement); out = String::concatStrings(out, subject->substring(index + searchString->length(), subject->length())); return out; } }
void SystemClass::trace(ArrayObject* a) { if (!a) toplevel()->throwArgumentError(kNullArgumentError, "array"); AvmCore* core = this->core(); PrintWriter& console = core->console; for (int i=0, n = a->getLength(); i < n; i++) { if (i > 0) console << ' '; Stringp s = core->string(a->getUintProperty(i)); for (int j = 0; j < s->length(); j++) { wchar c = (*s)[j]; // '\r' gets converted into '\n' // '\n' is left alone // '\r\n' is left alone if (c == '\r') { if (((j+1) < s->length()) && (*s)[j+1] == '\n') { console << '\r'; j++; } console << '\n'; } else { console << c; } } } console << '\n'; }
ArrayObject* StringClass::_split(Stringp in, Atom delimAtom, uint32 limit) { AvmCore* core = this->core(); if (limit == 0) return toplevel()->arrayClass->newArray(); if (in->length() == 0) { ArrayObject* out = toplevel()->arrayClass->newArray(); out->setUintProperty(0,in->atom()); return out; } // handle RegExp case if (AvmCore::istype(delimAtom, core->traits.regexp_itraits)) { RegExpObject *reObj = (RegExpObject*) AvmCore::atomToScriptObject(delimAtom); return reObj->split(in, limit); } ArrayObject *out = toplevel()->arrayClass->newArray(); Stringp delim = core->string(delimAtom); int ilen = in->length(); int dlen = delim->length(); int count = 0; if (dlen <= 0) { // delim is empty string, split on each char for (int i = 0; i < ilen && (unsigned)i < limit; i++) { Stringp sub = in->substr(i, 1); out->setUintProperty(count++, sub->atom()); } return out; } int32_t start = 0; while (start <= in->length()) { if ((limit != 0xFFFFFFFFUL) && (count >= (int) limit)) break; int32_t bgn = in->indexOf(delim, start); if (bgn < 0) // not found, use the string remainder bgn = in->length(); Stringp sub = in->substring(start, bgn); out->setUintProperty(count++, sub->atom()); start = bgn + delim->length(); } return out; }
int StringClass::_search(Stringp in, Atom regexpAtom) { AvmCore* core = this->core(); if (!AvmCore::istype(regexpAtom, core->traits.regexp_itraits)) { // ECMA-262 15.5.4.10 // If the argument is not a RegExp, invoke RegExp(exp) regexpAtom = core->newRegExp(toplevel()->regexpClass(), core->string(regexpAtom), core->kEmptyString)->atom(); } RegExpObject *reObj = (RegExpObject*) AvmCore::atomToScriptObject(regexpAtom); return reObj->search(in); }
// helper method // sets index to the uint32 value of name, if it can be converted // isNumber is set to true if name was a number (whether it was a uint32 value or not) bool VectorBaseObject::getVectorIndex(Atom name, uint32& index, bool& isNumber) const { AvmCore* core = this->core(); isNumber = false; if (AvmCore::getIndexFromAtom(name, &index)) { isNumber = true; return true; } else { if( AvmCore::isString(name) ) { Stringp s = core->string(name); const wchar c = s->charAt(0); // Does it look like a number? if( s->length() > 0 && c >= '0' && c <= '9' ) { double index_d = s->toNumber(); if( !MathUtils::isNaN(index_d) ) { isNumber = true; // name is a string that looks like a number int i = MathUtils::real2int(index_d); if ((double)i == index_d) { // It's an indexed property name index = i; return true; } else { return false; } } } } } return false; }
Atom VectorBaseObject::getAtomProperty(Atom name) const { uint32 index; bool isNumber=false; AvmCore* core = this->core(); if (getVectorIndex(name, index, isNumber)) { return getUintProperty(index); } else { if(isNumber) { // Not a valid indexed name - has a decimal part Multiname mn(core->publicNamespace,core->string(name)); toplevel()->throwReferenceError(kReadSealedError, &mn, traits()); } // Check the prototype chain - that will throw if there is no match return getAtomPropertyFromProtoChain(name, getDelegate(), traits()); } }
// this = argv[0] (ignored) // arg1 = argv[1] // argN = argv[argc] Atom NamespaceClass::construct(int argc, Atom* argv) { AvmCore* core = this->core(); // See E4X 13.2.2, pg 65 if (argc < 1) return core->newNamespace(core->kEmptyString->atom())->atom(); else if (argc == 1) return core->newNamespace(argv[1])->atom(); else { // Rhino throws an error when prefix is specified and uri is not a valid string String *p = core->string (argv[1]); String *u = core->string (argv[2]); if (p->length() && !u->length()) { toplevel()->throwTypeError(kXMLNamespaceWithPrefixAndNoURI, p); } return core->newNamespace(argv[1], argv[2])->atom(); } }
// E4X 10.4, pg 36 Atom XMLListClass::ToXMLList(Atom arg) { AvmCore* core = this->core(); if (AvmCore::isNullOrUndefined(arg)) { toplevel()->throwTypeError( (arg == undefinedAtom) ? kConvertUndefinedToObjectError : kConvertNullToObjectError); return arg; } if (AvmCore::isXMLList(arg)) { return arg; } else if (AvmCore::isXML(arg)) { XMLObject *x = AvmCore::atomToXMLObject(arg); Multiname m; bool bFound = x->getQName (&m); Atom parent = x->parent(); if (parent == undefinedAtom) parent = nullObjectAtom; XMLListObject *xl = XMLListObject::create(core->GetGC(), toplevel()->xmlListClass(), parent, bFound ? &m : 0); xl->_append (arg); return xl->atom(); } else { Toplevel* toplevel = this->toplevel(); Stringp s = core->string(arg); if (s->matchesLatin1("<>", 2, 0) && s->matchesLatin1("</>", 3, s->length()-3)) s = s->substr(2, s->length() - 5); Namespace *defaultNamespace = toplevel->getDefaultNamespace(); // We handle this step in the XMLObject constructor to avoid concatenation huge strings together // parentString = <parent xnlns=defaultNamespace> s </parent> // 3. Parse parentString as a W3C element information info e // 4. If the parse fails, throw a SyntaxError exception // 5. x = toXML(e); //StringBuffer parentString (core); //parentString << "<parent xmlns=\""; //parentString << defaultNamespace->getURI(); //parentString << "\">"; //parentString << s; //parentString << "</parent>"; XMLObject *x = XMLObject::create(core->GetGC(), toplevel->xmlClass(), s, defaultNamespace); XMLListObject *xl = XMLListObject::create(core->GetGC(), toplevel->xmlListClass()); for (uint32_t i = 0; i < x->getNode()->_length(); i++) { E4XNode *c = x->getNode()->_getAt (i); c->setParent (NULL); // !!@ trying to emulate rhino behavior here // Add the default namespace to our top element. Namespace *ns = toplevel->getDefaultNamespace(); c->_addInScopeNamespace (core, ns, core->findPublicNamespace()); xl->_appendNode (c); } return xl->atom(); } }
// E4X 10.3, page 32 Atom XMLClass::ToXML(Atom arg) { Toplevel* toplevel = this->toplevel(); AvmCore* core = this->core(); if (AvmCore::isNullOrUndefined(arg)) { toplevel->throwTypeError( (arg == undefinedAtom) ? kConvertUndefinedToObjectError : kConvertNullToObjectError); return arg; } else if (AvmCore::isXML(arg)) { return arg; } else if (AvmCore::isXMLList(arg)) { XMLListObject *xl = AvmCore::atomToXMLList(arg); if (xl->_length() == 1) { return xl->_getAt(0)->atom(); } else { toplevel->throwTypeError(kXMLMarkupMustBeWellFormed); return 0;//notreached } } else { Namespace *defaultNamespace = toplevel->getDefaultNamespace(); // 2. Parse parentString as a W3C element information info e // 3. If the parse fails, throw a SyntaxError exception XMLObject *x = new (core->GetGC()) XMLObject(toplevel->xmlClass(), core->string(arg), defaultNamespace); // 4. x = toXML(e); // 5. if x.length == 0 // return new xml object if (!x->getNode()->_length()) { x->setNode( new (core->GetGC()) TextE4XNode(0, core->kEmptyString) ); } // 6. else if x.length == 1 // x[0].parent = null // return x[0] else if (x->getNode()->_length() == 1) { x->setNode( x->getNode()->_getAt (0)); // discard parent node x->getNode()->setParent (0); } // 7. else throw a syntaxError else { // check for multiple nodes where the first n-1 are PI/comment nodes and the // last one is an element node. Just ignore the PI/comment nodes and return // the element node. (bug 148526). // Will also now ignore any text nodes that just contain whitespace (leading // or trailing) the one valid element node. If multiple element nodes are found, // that is a failing case as well. (bug 192355) E4XNode *node = x->getNode(); E4XNode *validNode = NULL; for (uint32 i = 0; i < node->_length(); i++) { E4XNode *n = node->_getAt (i); if (n->getClass() == E4XNode::kElement) { if (validNode != NULL) toplevel->throwTypeError(kXMLMarkupMustBeWellFormed); validNode = n; } else if (n->getClass() == E4XNode::kText) { if (!n->getValue()->isWhitespace()) { toplevel->throwTypeError(kXMLMarkupMustBeWellFormed); } } } // No valid nodes found if (!validNode) toplevel->throwTypeError(kXMLMarkupMustBeWellFormed); x->setNode( validNode ); // discard parent node validNode->setParent (0); } return x->atom(); } }