diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index b1893ce732d449d72fc645aedcfc6229d64d1120..2ae71243e3d146d9ee4de7a07b2d89a5f6d6c5b5 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -32,39 +32,297 @@ using namespace QmlJS::Interpreter; +namespace { + +//////////////////////////////////////////////////////////////////////////////// +// constructors +//////////////////////////////////////////////////////////////////////////////// +class ObjectCtor: public Function +{ +public: + ObjectCtor(Engine *engine); + + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; +}; + +class FunctionCtor: public Function +{ +public: + FunctionCtor(Engine *engine); + + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; +}; + +class ArrayCtor: public Function +{ +public: + ArrayCtor(Engine *engine); + + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; +}; + +class StringCtor: public Function +{ +public: + StringCtor(Engine *engine); + + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; +}; + +class BooleanCtor: public Function +{ +public: + BooleanCtor(Engine *engine); + + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; +}; + +class NumberCtor: public Function +{ +public: + NumberCtor(Engine *engine); + + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; +}; + +class DateCtor: public Function +{ +public: + DateCtor(Engine *engine); + + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; +}; + +class RegExpCtor: public Function +{ +public: + RegExpCtor(Engine *engine); + + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; +}; + +ObjectCtor::ObjectCtor(Engine *engine) + : Function(engine) +{ +} + +FunctionCtor::FunctionCtor(Engine *engine) + : Function(engine) +{ +} + +ArrayCtor::ArrayCtor(Engine *engine) + : Function(engine) +{ +} + +StringCtor::StringCtor(Engine *engine) + : Function(engine) +{ +} + +BooleanCtor::BooleanCtor(Engine *engine) + : Function(engine) +{ +} + +NumberCtor::NumberCtor(Engine *engine) + : Function(engine) +{ +} + +DateCtor::DateCtor(Engine *engine) + : Function(engine) +{ +} + +RegExpCtor::RegExpCtor(Engine *engine) + : Function(engine) +{ +} + +const Value *ObjectCtor::invoke(const Value *, const ValueList &) const +{ + ObjectValue *object = engine()->newObject(); + object->setClassName("Object"); + object->setPrototype(engine()->objectPrototype()); + object->setProperty("length", engine()->numberValue()); + return object; +} + +const Value *FunctionCtor::invoke(const Value *, const ValueList &) const +{ + ObjectValue *object = engine()->newObject(); + object->setClassName("Function"); + object->setPrototype(engine()->functionPrototype()); + object->setProperty("length", engine()->numberValue()); + return object; +} + +const Value *ArrayCtor::invoke(const Value *thisObject, const ValueList &) const +{ + ObjectValue *object = const_cast<ObjectValue *>(value_cast<const ObjectValue *>(thisObject)); + if (! object || object == engine()->globalObject()) + object = engine()->newObject(); + + object->setClassName("Array"); + object->setPrototype(engine()->arrayPrototype()); + object->setProperty("length", engine()->numberValue()); + return object; +} + +const Value *StringCtor::invoke(const Value *thisObject, const ValueList &) const +{ + ObjectValue *object = const_cast<ObjectValue *>(value_cast<const ObjectValue *>(thisObject)); + if (! object || object == engine()->globalObject()) + object = engine()->newObject(); + + object->setClassName("String"); + object->setPrototype(engine()->stringPrototype()); + object->setProperty("length", engine()->numberValue()); + return object; +} + +const Value *BooleanCtor::invoke(const Value *, const ValueList &) const +{ + ObjectValue *object = engine()->newObject(); + object->setClassName("Boolean"); + object->setPrototype(engine()->booleanPrototype()); + return object; +} + +const Value *NumberCtor::invoke(const Value *, const ValueList &) const +{ + ObjectValue *object = engine()->newObject(); + object->setClassName("Number"); + object->setPrototype(engine()->numberPrototype()); + return object; +} + +const Value *DateCtor::invoke(const Value *, const ValueList &) const +{ + ObjectValue *object = engine()->newObject(); + object->setClassName("Date"); + object->setPrototype(engine()->datePrototype()); + return object; +} + +const Value *RegExpCtor::invoke(const Value *, const ValueList &) const +{ + ObjectValue *object = engine()->newObject(); + object->setClassName("RegExp"); + object->setPrototype(engine()->regexpPrototype()); + object->setProperty("source", engine()->stringValue()); + object->setProperty("global", engine()->booleanValue()); + object->setProperty("ignoreCase", engine()->booleanValue()); + object->setProperty("multiline", engine()->booleanValue()); + object->setProperty("lastIndex", engine()->numberValue()); + return object; +} + +} // end of anonymous namespace + //////////////////////////////////////////////////////////////////////////////// // ValueVisitor //////////////////////////////////////////////////////////////////////////////// -ValueVisitor::ValueVisitor() {} -ValueVisitor::~ValueVisitor() {} -void ValueVisitor::visit(const NullValue *) {} -void ValueVisitor::visit(const UndefinedValue *) {} -void ValueVisitor::visit(const NumberValue *) {} -void ValueVisitor::visit(const BooleanValue *) {} -void ValueVisitor::visit(const StringValue *) {} -void ValueVisitor::visit(const ObjectValue *) {} -void ValueVisitor::visit(const FunctionValue *) {} +ValueVisitor::ValueVisitor() +{ +} + +ValueVisitor::~ValueVisitor() +{ +} + +void ValueVisitor::visit(const NullValue *) +{ +} + +void ValueVisitor::visit(const UndefinedValue *) +{ +} + +void ValueVisitor::visit(const NumberValue *) +{ +} + +void ValueVisitor::visit(const BooleanValue *) +{ +} + +void ValueVisitor::visit(const StringValue *) +{ +} + +void ValueVisitor::visit(const ObjectValue *) +{ +} + +void ValueVisitor::visit(const FunctionValue *) +{ +} //////////////////////////////////////////////////////////////////////////////// // Value //////////////////////////////////////////////////////////////////////////////// -Value::Value() {} -Value::~Value() {} -const NullValue *Value::asNullValue() const { return 0; } -const UndefinedValue *Value::asUndefinedValue() const { return 0; } -const NumberValue *Value::asNumberValue() const { return 0; } -const BooleanValue *Value::asBooleanValue() const { return 0; } -const StringValue *Value::asStringValue() const { return 0; } -const ObjectValue *Value::asObjectValue() const { return 0; } -const FunctionValue *Value::asFunctionValue() const { return 0; } +Value::Value() +{ +} + +Value::~Value() +{ +} + +const NullValue *Value::asNullValue() const +{ + return 0; +} + +const UndefinedValue *Value::asUndefinedValue() const +{ + return 0; +} + +const NumberValue *Value::asNumberValue() const +{ + return 0; +} + +const BooleanValue *Value::asBooleanValue() const +{ + return 0; +} + +const StringValue *Value::asStringValue() const +{ + return 0; +} + +const ObjectValue *Value::asObjectValue() const +{ + return 0; +} + +const FunctionValue *Value::asFunctionValue() const +{ + return 0; +} //////////////////////////////////////////////////////////////////////////////// // Environment //////////////////////////////////////////////////////////////////////////////// -Environment::Environment() {} -Environment::~Environment() {} -const Environment *Environment::parent() const { return 0; } +Environment::Environment() +{ +} + +Environment::~Environment() +{ +} + +const Environment *Environment::parent() const +{ + return 0; +} const Value *Environment::lookup(const QString &name) const { @@ -86,39 +344,117 @@ const Value *Environment::lookupMember(const QString &name) const { //////////////////////////////////////////////////////////////////////////////// // Values //////////////////////////////////////////////////////////////////////////////// -const NullValue *NullValue::asNullValue() const { return this; } -void NullValue::accept(ValueVisitor *visitor) const { visitor->visit(this); } - -const UndefinedValue *UndefinedValue::asUndefinedValue() const { return this; } -void UndefinedValue::accept(ValueVisitor *visitor) const { visitor->visit(this); } - -const NumberValue *NumberValue::asNumberValue() const { return this; } -void NumberValue::accept(ValueVisitor *visitor) const { visitor->visit(this); } - -const BooleanValue *BooleanValue::asBooleanValue() const { return this; } -void BooleanValue::accept(ValueVisitor *visitor) const { visitor->visit(this); } - -const StringValue *StringValue::asStringValue() const { return this; } -void StringValue::accept(ValueVisitor *visitor) const { visitor->visit(this); } - -ObjectValue::ObjectValue(Engine *engine): _engine(engine), _prototype(0), _scope(0) {} -Engine *ObjectValue::engine() const { return _engine; } -QString ObjectValue::className() const { return _className; } -void ObjectValue::setClassName(const QString &className) { _className = className; } -const ObjectValue *ObjectValue::prototype() const { return _prototype; } -const ObjectValue *ObjectValue::scope() const { return _scope; } -void ObjectValue::setScope(const ObjectValue *scope) { _scope = scope; } -ObjectValue::MemberIterator ObjectValue::firstMember() const { return _members.begin(); } -ObjectValue::MemberIterator ObjectValue::lastMember() const { return _members.end(); } -void ObjectValue::setProperty(const QString &name, const Value *value) { _members[name] = value; } -void ObjectValue::removeProperty(const QString &name) { _members.remove(name); } -const ObjectValue *ObjectValue::asObjectValue() const { return this; } -void ObjectValue::accept(ValueVisitor *visitor) const { visitor->visit(this); } - -const Value *ObjectValue::property(const QString &name) const { - if (name == QLatin1String("__proto__")) - return _prototype; +const NullValue *NullValue::asNullValue() const +{ + return this; +} + +void NullValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} + +const UndefinedValue *UndefinedValue::asUndefinedValue() const +{ + return this; +} + +void UndefinedValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} +const NumberValue *NumberValue::asNumberValue() const +{ + return this; +} + +void NumberValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} + +const BooleanValue *BooleanValue::asBooleanValue() const +{ + return this; +} + +void BooleanValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} + +const StringValue *StringValue::asStringValue() const +{ + return this; +} + +void StringValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} + +ObjectValue::ObjectValue(Engine *engine) + : _engine(engine), _prototype(0), _scope(0) +{ +} + +ObjectValue::~ObjectValue() +{ +} + +Engine *ObjectValue::engine() const +{ + return _engine; +} + +QString ObjectValue::className() const +{ + return _className; +} + +void ObjectValue::setClassName(const QString &className) +{ + _className = className; +} + +const ObjectValue *ObjectValue::prototype() const +{ + return _prototype; +} + +const ObjectValue *ObjectValue::scope() const +{ + return _scope; +} + +void ObjectValue::setScope(const ObjectValue *scope) +{ + _scope = scope; +} + +void ObjectValue::setProperty(const QString &name, const Value *value) +{ + _members[name] = value; +} + +void ObjectValue::removeProperty(const QString &name) +{ + _members.remove(name); +} + +const ObjectValue *ObjectValue::asObjectValue() const +{ + return this; +} + +void ObjectValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} + +const Value *ObjectValue::property(const QString &name) const +{ return lookupMember(name); } @@ -126,13 +462,13 @@ void ObjectValue::setPrototype(const ObjectValue *prototype) { QSet<const ObjectValue *> processed; - if (! prototype || isValidPrototype(prototype, &processed)) + if (! prototype || checkPrototype(prototype, &processed)) _prototype = prototype; else qWarning() << "**** invalid prototype:"; } -bool ObjectValue::isValidPrototype(const ObjectValue *proto, QSet<const ObjectValue *> *processed) const +bool ObjectValue::checkPrototype(const ObjectValue *proto, QSet<const ObjectValue *> *processed) const { const int previousSize = processed->size(); processed->insert(this); @@ -141,7 +477,7 @@ bool ObjectValue::isValidPrototype(const ObjectValue *proto, QSet<const ObjectVa if (this == proto) return false; - if (prototype() && ! prototype()->isValidPrototype(proto, processed)) + if (prototype() && ! prototype()->checkPrototype(proto, processed)) return false; return true; @@ -150,48 +486,116 @@ bool ObjectValue::isValidPrototype(const ObjectValue *proto, QSet<const ObjectVa return false; } -const Value *ObjectValue::member(const QString &name) const +void ObjectValue::processMembers(MemberProcessor *processor) const +{ + QHashIterator<QString, const Value *> it(_members); + + while (it.hasNext()) { + it.next(); + + if (! processor->processMember(it.key(), it.value())) + break; + } +} + +const Value *ObjectValue::member(const QString &name) const +{ + QHash<QString, const Value *>::const_iterator it = _members.find(name); + + if (it != _members.end()) + return it.value(); + else + return 0; +} + +const Environment *ObjectValue::parent() const +{ + return _scope; +} + +const Value *ObjectValue::lookupMember(const QString &name) const +{ + if (const Value *m = member(name)) + return m; + + if (_prototype) { + if (const Value *m = _prototype->lookup(name)) + return m; + } + + return 0; +} + +FunctionValue::FunctionValue(Engine *engine) + : ObjectValue(engine) +{ +} + +FunctionValue::~FunctionValue() +{ +} + +const Value *FunctionValue::construct(const ValueList &actuals) const +{ + ObjectValue *thisObject = engine()->newObject(); + return invoke(thisObject, actuals); +} + +const Value *FunctionValue::call(const ValueList &actuals) const +{ + return invoke(engine()->nullValue(), actuals); +} + +const Value *FunctionValue::call(const ObjectValue *thisObject, const ValueList &actuals) const +{ + return invoke(thisObject, actuals); +} + +int FunctionValue::argumentCount() const +{ + return 0; +} + +const FunctionValue *FunctionValue::asFunctionValue() const +{ + return this; +} + +void FunctionValue::accept(ValueVisitor *visitor) const +{ + visitor->visit(this); +} + +Function::Function(Engine *engine) + : FunctionValue(engine), _returnValue(0) { - MemberIterator it = _members.find(name); - - if (it != _members.end()) - return it.value(); - else - return 0; + setClassName("Function"); } -const Environment *ObjectValue::parent() const +void Function::addArgument(const Value *argument) { - return _scope; + _arguments.push_back(argument); } -const Value *ObjectValue::lookupMember(const QString &name) const +const Value *Function::returnValue() const { - if (const Value *m = member(name)) - return m; - - if (_prototype) { - if (const Value *m = _prototype->lookup(name)) - return m; - } - - return 0; + return _returnValue; } -FunctionValue::FunctionValue(Engine *engine): ObjectValue(engine) {} -int FunctionValue::argumentCount() const { return 0; } -const FunctionValue *FunctionValue::asFunctionValue() const { return this; } -void FunctionValue::accept(ValueVisitor *visitor) const { visitor->visit(this); } +void Function::setReturnValue(const Value *returnValue) +{ + _returnValue = returnValue; +} +int Function::argumentCount() const +{ + return _arguments.size(); +} -Function::Function(Engine *engine): FunctionValue(engine), _returnValue(0) { setClassName("Function"); } -void Function::addArgument(const Value *argument) { _arguments.push_back(argument); } -Function::ArgumentIterator Function::firstArgument() const { return _arguments.begin(); } -Function::ArgumentIterator Function::lastArgument() const { return _arguments.end(); } -const Value *Function::returnValue() const { return _returnValue; } -void Function::setReturnValue(const Value *returnValue) { _returnValue = returnValue; } -int Function::argumentCount() const { return _arguments.size(); } -const Value *Function::argument(int index) const { return _arguments.at(index); } +const Value *Function::argument(int index) const +{ + return _arguments.at(index); +} const Value *Function::property(const QString &name) const { @@ -201,17 +605,21 @@ const Value *Function::property(const QString &name) const return FunctionValue::property(name); } -const Value *Function::call(const Value *thisValue, const QList<const Value *> &) const +const Value *Function::invoke(const Value *thisObject, const ValueList &) const { - return thisValue; // ### FIXME it should return undefined + return thisObject; // ### FIXME it should return undefined } //////////////////////////////////////////////////////////////////////////////// // typing environment //////////////////////////////////////////////////////////////////////////////// -ConvertToNumber::ConvertToNumber(Engine *engine): _engine(engine), _result(0) {} +ConvertToNumber::ConvertToNumber(Engine *engine) + : _engine(engine), _result(0) +{ +} -const Value *ConvertToNumber::operator()(const Value *value) { +const Value *ConvertToNumber::operator()(const Value *value) +{ const Value *previousValue = switchResult(0); if (value) @@ -220,15 +628,20 @@ const Value *ConvertToNumber::operator()(const Value *value) { return switchResult(previousValue); } -const Value *ConvertToNumber::switchResult(const Value *value) { +const Value *ConvertToNumber::switchResult(const Value *value) +{ const Value *previousResult = _result; _result = value; return previousResult; } -ConvertToString::ConvertToString(Engine *engine): _engine(engine), _result(0) {} +ConvertToString::ConvertToString(Engine *engine) + : _engine(engine), _result(0) +{ +} -const Value *ConvertToString::operator()(const Value *value) { +const Value *ConvertToString::operator()(const Value *value) +{ const Value *previousValue = switchResult(0); if (value) @@ -237,7 +650,8 @@ const Value *ConvertToString::operator()(const Value *value) { return switchResult(previousValue); } -const Value *ConvertToString::switchResult(const Value *value) { +const Value *ConvertToString::switchResult(const Value *value) +{ const Value *previousResult = _result; _result = value; return previousResult; @@ -248,7 +662,8 @@ ConvertToObject::ConvertToObject(Engine *engine) { } -const Value *ConvertToObject::operator()(const Value *value) { +const Value *ConvertToObject::operator()(const Value *value) +{ const Value *previousValue = switchResult(0); if (value) @@ -257,7 +672,8 @@ const Value *ConvertToObject::operator()(const Value *value) { return switchResult(previousValue); } -const Value *ConvertToObject::switchResult(const Value *value) { +const Value *ConvertToObject::switchResult(const Value *value) +{ const Value *previousResult = _result; _result = value; return previousResult; @@ -273,19 +689,25 @@ void ConvertToObject::visit(const UndefinedValue *) _result = _engine->nullValue(); } -void ConvertToObject::visit(const NumberValue *) +void ConvertToObject::visit(const NumberValue *value) { - _result = _engine->call(_engine->numberCtor()); + ValueList actuals; + actuals.append(value); + _result = _engine->numberCtor()->construct(actuals); } -void ConvertToObject::visit(const BooleanValue *) +void ConvertToObject::visit(const BooleanValue *value) { - _result = _engine->call(_engine->booleanCtor()); + ValueList actuals; + actuals.append(value); + _result = _engine->booleanCtor()->construct(actuals); } -void ConvertToObject::visit(const StringValue *) +void ConvertToObject::visit(const StringValue *value) { - _result = _engine->call(_engine->stringCtor()); + ValueList actuals; + actuals.append(value); + _result = _engine->stringCtor()->construct(actuals); } void ConvertToObject::visit(const ObjectValue *object) @@ -308,104 +730,46 @@ QString TypeId::operator()(const Value *value) return _result; } -void TypeId::visit(const NullValue *) { _result = QLatin1String("null"); } -void TypeId::visit(const UndefinedValue *) { _result = QLatin1String("undefined"); } -void TypeId::visit(const NumberValue *) { _result = QLatin1String("number"); } -void TypeId::visit(const BooleanValue *) { _result = QLatin1String("boolean"); } -void TypeId::visit(const StringValue *) { _result = QLatin1String("string"); } - -void TypeId::visit(const ObjectValue *object) { - _result = object->className(); - - if (_result.isEmpty()) - _result = QLatin1String("object"); -} - -void TypeId::visit(const FunctionValue *object) { - _result = object->className(); - - if (_result.isEmpty()) - _result = QLatin1String("Function"); -} - -//////////////////////////////////////////////////////////////////////////////// -// constructors -//////////////////////////////////////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -// constructors -//////////////////////////////////////////////////////////////////////////////// -class ObjectCtor: public Function -{ -public: - ObjectCtor(Engine *engine); - - virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; -}; - -class FunctionCtor: public Function +void TypeId::visit(const NullValue *) { -public: - FunctionCtor(Engine *engine); - - virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; -}; + _result = QLatin1String("null"); +} -class ArrayCtor: public Function +void TypeId::visit(const UndefinedValue *) { -public: - ArrayCtor(Engine *engine); - - virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; -}; + _result = QLatin1String("undefined"); +} -class StringCtor: public Function +void TypeId::visit(const NumberValue *) { -public: - StringCtor(Engine *engine); - - virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; -}; + _result = QLatin1String("number"); +} -class BooleanCtor: public Function +void TypeId::visit(const BooleanValue *) { -public: - BooleanCtor(Engine *engine); - - virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; -}; + _result = QLatin1String("boolean"); +} -class NumberCtor: public Function +void TypeId::visit(const StringValue *) { -public: - NumberCtor(Engine *engine); - - virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; -}; + _result = QLatin1String("string"); +} -class DateCtor: public Function +void TypeId::visit(const ObjectValue *object) { -public: - DateCtor(Engine *engine); + _result = object->className(); - virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; -}; + if (_result.isEmpty()) + _result = QLatin1String("object"); +} -class RegExpCtor: public Function +void TypeId::visit(const FunctionValue *object) { -public: - RegExpCtor(Engine *engine); - - virtual const Value *call(const Value *thisValue, const QList<const Value *> &actuals) const; -}; + _result = object->className(); -ObjectCtor::ObjectCtor(Engine *engine): Function(engine) {} -FunctionCtor::FunctionCtor(Engine *engine): Function(engine) {} -ArrayCtor::ArrayCtor(Engine *engine): Function(engine) {} -StringCtor::StringCtor(Engine *engine): Function(engine) {} -BooleanCtor::BooleanCtor(Engine *engine): Function(engine) {} -NumberCtor::NumberCtor(Engine *engine): Function(engine) {} -DateCtor::DateCtor(Engine *engine): Function(engine) {} -RegExpCtor::RegExpCtor(Engine *engine): Function(engine) {} + if (_result.isEmpty()) + _result = QLatin1String("Function"); +} Engine::Engine() : _objectPrototype(0), @@ -434,20 +798,43 @@ Engine::Engine() initializePrototypes(); } -Engine::~Engine() { +Engine::~Engine() +{ QList<ObjectValue *>::iterator it = _objects.begin(); for (; it != _objects.end(); ++it) delete *it; } -const NullValue *Engine::nullValue() const { return &_nullValue; } -const UndefinedValue *Engine::undefinedValue() const { return &_undefinedValue; } -const NumberValue *Engine::numberValue() const { return &_numberValue; } -const BooleanValue *Engine::booleanValue() const { return &_booleanValue; } -const StringValue *Engine::stringValue() const { return &_stringValue; } +const NullValue *Engine::nullValue() const +{ + return &_nullValue; +} + +const UndefinedValue *Engine::undefinedValue() const +{ + return &_undefinedValue; +} + +const NumberValue *Engine::numberValue() const +{ + return &_numberValue; +} + +const BooleanValue *Engine::booleanValue() const +{ + return &_booleanValue; +} + +const StringValue *Engine::stringValue() const +{ + return &_stringValue; +} -const Value *Engine::newArrayValue() { return call(arrayCtor()); } +const Value *Engine::newArray() +{ + return arrayCtor()->construct(); +} ObjectValue *Engine::newObject() { @@ -469,38 +856,119 @@ Function *Engine::newFunction() { return function; } -ObjectValue *Engine::globalObject() const { return _globalObject; } -ObjectValue *Engine::objectPrototype() const { return _objectPrototype; } -ObjectValue *Engine::functionPrototype() const { return _functionPrototype; } -ObjectValue *Engine::numberPrototype() const { return _numberPrototype; } -ObjectValue *Engine::booleanPrototype() const { return _booleanPrototype; } -ObjectValue *Engine::stringPrototype() const { return _stringPrototype; } -ObjectValue *Engine::arrayPrototype() const { return _arrayPrototype; } -ObjectValue *Engine::datePrototype() const { return _datePrototype; } -ObjectValue *Engine::regexpPrototype() const { return _regexpPrototype; } -const FunctionValue *Engine::objectCtor() const { return _objectCtor; } -const FunctionValue *Engine::functionCtor() const { return _functionCtor; } -const FunctionValue *Engine::arrayCtor() const { return _arrayCtor; } -const FunctionValue *Engine::stringCtor() const { return _stringCtor; } -const FunctionValue *Engine::booleanCtor() const { return _booleanCtor; } -const FunctionValue *Engine::numberCtor() const { return _numberCtor; } -const FunctionValue *Engine::dateCtor() const { return _dateCtor; } -const FunctionValue *Engine::regexpCtor() const { return _regexpCtor; } -const ObjectValue *Engine::mathObject() const { return _mathObject; } -const Value *Engine::convertToBool(const Value *value) { return _convertToNumber(value); } // ### implement convert to bool -const Value *Engine::convertToNumber(const Value *value) { return _convertToNumber(value); } -const Value *Engine::convertToString(const Value *value) { return _convertToString(value); } -const Value *Engine::convertToObject(const Value *value) { return _convertToObject(value); } -QString Engine::typeId(const Value *value) { return _typeId(value); } +ObjectValue *Engine::globalObject() const +{ + return _globalObject; +} + +ObjectValue *Engine::objectPrototype() const +{ + return _objectPrototype; +} + +ObjectValue *Engine::functionPrototype() const +{ + return _functionPrototype; +} + +ObjectValue *Engine::numberPrototype() const +{ + return _numberPrototype; +} + +ObjectValue *Engine::booleanPrototype() const +{ + return _booleanPrototype; +} + +ObjectValue *Engine::stringPrototype() const +{ + return _stringPrototype; +} + +ObjectValue *Engine::arrayPrototype() const +{ + return _arrayPrototype; +} + +ObjectValue *Engine::datePrototype() const +{ + return _datePrototype; +} + +ObjectValue *Engine::regexpPrototype() const +{ + return _regexpPrototype; +} + +const FunctionValue *Engine::objectCtor() const +{ + return _objectCtor; +} + +const FunctionValue *Engine::functionCtor() const +{ + return _functionCtor; +} + +const FunctionValue *Engine::arrayCtor() const +{ + return _arrayCtor; +} + +const FunctionValue *Engine::stringCtor() const +{ + return _stringCtor; +} + +const FunctionValue *Engine::booleanCtor() const +{ + return _booleanCtor; +} + +const FunctionValue *Engine::numberCtor() const +{ + return _numberCtor; +} + +const FunctionValue *Engine::dateCtor() const +{ + return _dateCtor; +} + +const FunctionValue *Engine::regexpCtor() const +{ + return _regexpCtor; +} + +const ObjectValue *Engine::mathObject() const +{ + return _mathObject; +} + +const Value *Engine::convertToBool(const Value *value) +{ + return _convertToNumber(value); // ### implement convert to bool +} + +const Value *Engine::convertToNumber(const Value *value) +{ + return _convertToNumber(value); +} + +const Value *Engine::convertToString(const Value *value) +{ + return _convertToString(value); +} -const Value *Engine::call(const FunctionValue *function, const QList<const Value *> &actuals) +const Value *Engine::convertToObject(const Value *value) { - return call(function, globalObject(), actuals); + return _convertToObject(value); } -const Value *Engine::call(const FunctionValue *function, const ObjectValue *thisValue, const QList<const Value *> &actuals) +QString Engine::typeId(const Value *value) { - return function->call(thisValue, actuals); + return _typeId(value); } void Engine::addFunction(ObjectValue *object, const QString &name, const Value *result, int argumentCount) @@ -578,7 +1046,7 @@ void Engine::initializePrototypes() addFunction(_objectCtor, "getPrototypeOf", 1); addFunction(_objectCtor, "getOwnPropertyDescriptor", 2); - addFunction(_objectCtor, "getOwnPropertyNames", newArrayValue(), 1); + addFunction(_objectCtor, "getOwnPropertyNames", newArray(), 1); addFunction(_objectCtor, "create", 1); addFunction(_objectCtor, "defineProperty", 3); addFunction(_objectCtor, "defineProperties", 2); @@ -588,11 +1056,11 @@ void Engine::initializePrototypes() addFunction(_objectCtor, "isSealed", booleanValue(), 1); addFunction(_objectCtor, "isFrozen", booleanValue(), 1); addFunction(_objectCtor, "isExtensible", booleanValue(), 1); - addFunction(_objectCtor, "keys", newArrayValue(), 1); + addFunction(_objectCtor, "keys", newArray(), 1); addFunction(_objectPrototype, "toString", stringValue(), 0); addFunction(_objectPrototype, "toLocaleString", stringValue(), 0); - addFunction(_objectPrototype, "valueOf", 0); // ### FIXME it should return thisValue + addFunction(_objectPrototype, "valueOf", 0); // ### FIXME it should return thisObject addFunction(_objectPrototype, "hasOwnProperty", booleanValue(), 1); addFunction(_objectPrototype, "isPrototypeOf", booleanValue(), 1); addFunction(_objectPrototype, "propertyIsEnumerable", booleanValue(), 1); @@ -642,11 +1110,11 @@ void Engine::initializePrototypes() addFunction(_stringPrototype, "indexOf", numberValue(), 2); addFunction(_stringPrototype, "lastIndexOf", numberValue(), 2); addFunction(_stringPrototype, "localeCompare", booleanValue(), 1); - addFunction(_stringPrototype, "match", newArrayValue(), 1); + addFunction(_stringPrototype, "match", newArray(), 1); addFunction(_stringPrototype, "replace", stringValue(), 2); addFunction(_stringPrototype, "search", numberValue(), 1); addFunction(_stringPrototype, "slice", stringValue(), 2); - addFunction(_stringPrototype, "split", newArrayValue(), 2); + addFunction(_stringPrototype, "split", newArray(), 2); addFunction(_stringPrototype, "substring", stringValue(), 2); addFunction(_stringPrototype, "toLowerCase", stringValue(), 0); addFunction(_stringPrototype, "toLocaleLowerCase", stringValue(), 0); @@ -757,7 +1225,7 @@ void Engine::initializePrototypes() // set up the default Boolean prototype _regexpPrototype->setProperty("constructor", _regexpCtor); - addFunction(_regexpPrototype, "exec", newArrayValue(), 1); + addFunction(_regexpPrototype, "exec", newArray(), 1); addFunction(_regexpPrototype, "test", booleanValue(), 1); addFunction(_regexpPrototype, "toString", stringValue(), 0); @@ -773,9 +1241,9 @@ void Engine::initializePrototypes() _globalObject->setProperty("RegExp", regexpCtor()); } -const Value *FunctionValue::call(const Value *thisValue, const QList<const Value *> & /*actuals*/) const +const Value *FunctionValue::invoke(const Value *thisObject, const ValueList & /*actuals*/) const { - return thisValue; // ### FIXME: it should return undefined + return thisObject; // ### FIXME: it should return undefined } const Value *FunctionValue::argument(int /*index*/) const @@ -788,84 +1256,6 @@ const Value *FunctionValue::returnValue() const return engine()->undefinedValue(); } -const Value *ObjectCtor::call(const Value *, const QList<const Value *> &) const -{ - ObjectValue *object = engine()->newObject(); - object->setClassName("Object"); - object->setPrototype(engine()->objectPrototype()); - object->setProperty("length", engine()->numberValue()); - return object; -} - -const Value *FunctionCtor::call(const Value *, const QList<const Value *> &) const -{ - ObjectValue *object = engine()->newObject(); - object->setClassName("Function"); - object->setPrototype(engine()->functionPrototype()); - object->setProperty("length", engine()->numberValue()); - return object; -} - -const Value *ArrayCtor::call(const Value *thisValue, const QList<const Value *> &) const -{ - ObjectValue *object = const_cast<ObjectValue *>(value_cast<const ObjectValue *>(thisValue)); - if (! object || object == engine()->globalObject()) - object = engine()->newObject(); - - object->setClassName("Array"); - object->setPrototype(engine()->arrayPrototype()); - object->setProperty("length", engine()->numberValue()); - return object; -} - -const Value *StringCtor::call(const Value *thisValue, const QList<const Value *> &) const -{ - ObjectValue *object = const_cast<ObjectValue *>(value_cast<const ObjectValue *>(thisValue)); - if (! object || object == engine()->globalObject()) - object = engine()->newObject(); - - object->setClassName("String"); - object->setPrototype(engine()->stringPrototype()); - object->setProperty("length", engine()->numberValue()); - return object; -} - -const Value *BooleanCtor::call(const Value *, const QList<const Value *> &) const -{ - ObjectValue *object = engine()->newObject(); - object->setClassName("Boolean"); - object->setPrototype(engine()->booleanPrototype()); - return object; -} - -const Value *NumberCtor::call(const Value *, const QList<const Value *> &) const -{ - ObjectValue *object = engine()->newObject(); - object->setClassName("Number"); - object->setPrototype(engine()->numberPrototype()); - return object; -} - -const Value *DateCtor::call(const Value *, const QList<const Value *> &) const -{ - ObjectValue *object = engine()->newObject(); - object->setClassName("Date"); - object->setPrototype(engine()->datePrototype()); - return object; -} - -const Value *RegExpCtor::call(const Value *, const QList<const Value *> &) const -{ - ObjectValue *object = engine()->newObject(); - object->setClassName("RegExp"); - object->setPrototype(engine()->regexpPrototype()); - object->setProperty("source", engine()->stringValue()); - object->setProperty("global", engine()->booleanValue()); - object->setProperty("ignoreCase", engine()->booleanValue()); - object->setProperty("multiline", engine()->booleanValue()); - object->setProperty("lastIndex", engine()->numberValue()); - return object; -} //////////////////////////////////////////////////////////////////////////////// // convert to number @@ -898,14 +1288,14 @@ void ConvertToNumber::visit(const StringValue *) void ConvertToNumber::visit(const ObjectValue *object) { if (const FunctionValue *valueOfMember = value_cast<const FunctionValue *>(object->lookup("valueOf"))) { - _result = value_cast<const NumberValue *>(valueOfMember->call(object)); // ### invoke convert-to-number? + _result = value_cast<const NumberValue *>(valueOfMember->invoke(object)); // ### invoke convert-to-number? } } void ConvertToNumber::visit(const FunctionValue *object) { if (const FunctionValue *valueOfMember = value_cast<const FunctionValue *>(object->lookup("valueOf"))) { - _result = value_cast<const NumberValue *>(valueOfMember->call(object)); // ### invoke convert-to-number? + _result = value_cast<const NumberValue *>(valueOfMember->invoke(object)); // ### invoke convert-to-number? } } @@ -940,13 +1330,13 @@ void ConvertToString::visit(const StringValue *value) void ConvertToString::visit(const ObjectValue *object) { if (const FunctionValue *toStringMember = value_cast<const FunctionValue *>(object->lookup("toString"))) { - _result = value_cast<const StringValue *>(toStringMember->call(object)); // ### invoke convert-to-string? + _result = value_cast<const StringValue *>(toStringMember->invoke(object)); // ### invoke convert-to-string? } } void ConvertToString::visit(const FunctionValue *object) { if (const FunctionValue *toStringMember = value_cast<const FunctionValue *>(object->lookup("toString"))) { - _result = value_cast<const StringValue *>(toStringMember->call(object)); // ### invoke convert-to-string? + _result = value_cast<const StringValue *>(toStringMember->invoke(object)); // ### invoke convert-to-string? } } diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index cf7710264c00cff5ac5db59c6aac21167995da7c..3f96369829d25f1a0c43d8f72722702a4876b2c8 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -53,6 +53,8 @@ class StringValue; class ObjectValue; class FunctionValue; +typedef QList<const Value *> ValueList; + //////////////////////////////////////////////////////////////////////////////// // Value visitor //////////////////////////////////////////////////////////////////////////////// @@ -152,7 +154,6 @@ public: virtual const Value *lookupMember(const QString &name) const; }; - //////////////////////////////////////////////////////////////////////////////// // Value nodes //////////////////////////////////////////////////////////////////////////////// @@ -191,10 +192,24 @@ public: virtual void accept(ValueVisitor *visitor) const; }; +class QMLJS_EXPORT MemberProcessor +{ + MemberProcessor(const MemberProcessor &other); + void operator = (const MemberProcessor &other); + +public: + MemberProcessor() {} + virtual ~MemberProcessor() {} + + // Returns false to stop the processor. + virtual bool processMember(const QString &name, const Value *value) = 0; +}; + class QMLJS_EXPORT ObjectValue: public Value, public Environment { public: ObjectValue(Engine *engine); + virtual ~ObjectValue(); Engine *engine() const; @@ -207,15 +222,12 @@ public: const ObjectValue *scope() const; void setScope(const ObjectValue *scope); - typedef QHash<QString, const Value *>::const_iterator MemberIterator; - - MemberIterator firstMember() const; - MemberIterator lastMember() const; + virtual void processMembers(MemberProcessor *processor) const; + virtual const Value *member(const QString &name) const; virtual const Value *property(const QString &name) const; virtual void setProperty(const QString &name, const Value *value); virtual void removeProperty(const QString &name); - virtual const Value *member(const QString &name) const; // Environment interface virtual const Environment *parent() const; @@ -226,7 +238,7 @@ public: virtual void accept(ValueVisitor *visitor) const; private: - bool isValidPrototype(const ObjectValue *prototype, QSet<const ObjectValue *> *processed) const; + bool checkPrototype(const ObjectValue *prototype, QSet<const ObjectValue *> *processed) const; private: Engine *_engine; @@ -240,14 +252,25 @@ class QMLJS_EXPORT FunctionValue: public ObjectValue { public: FunctionValue(Engine *engine); + virtual ~FunctionValue(); + + // [[construct]] + const Value *construct(const ValueList &actuals = ValueList()) const; + + // [[call]] + const Value *call(const ValueList &actuals = ValueList()) const; + + const Value *call(const ObjectValue *thisObject, + const ValueList &actuals = ValueList()) const; + virtual const Value *returnValue() const; virtual int argumentCount() const; - virtual const Value *argument(int /*index*/) const; + virtual const Value *argument(int index) const; - virtual const Value *call(const Value *thisValue, - const QList<const Value *> & /*actuals*/ = QList<const Value *>()) const; + virtual const Value *invoke(const Value *thisObject, + const ValueList &actuals = ValueList()) const; // Value interface virtual const FunctionValue *asFunctionValue() const; @@ -259,13 +282,7 @@ class QMLJS_EXPORT Function: public FunctionValue public: Function(Engine *engine); - void addArgument(const Value *argument); - - typedef QList<const Value *>::const_iterator ArgumentIterator; - - ArgumentIterator firstArgument() const; - ArgumentIterator lastArgument() const; - + void addArgument(const Value *argument); void setReturnValue(const Value *returnValue); // ObjectValue interface @@ -275,10 +292,10 @@ public: virtual const Value *returnValue() const; virtual int argumentCount() const; virtual const Value *argument(int index) const; - virtual const Value *call(const Value * /*thisValue*/, const QList<const Value *> & /*actuals*/) const; + virtual const Value *invoke(const Value *thisObject, const ValueList &actuals) const; private: - QList<const Value *> _arguments; + ValueList _arguments; const Value *_returnValue; }; @@ -388,7 +405,7 @@ public: const BooleanValue *booleanValue() const; const StringValue *stringValue() const; - const Value *newArrayValue(); // ### remove me + const Value *newArray(); // ### remove me ObjectValue *newObject(); Function *newFunction(); @@ -424,10 +441,6 @@ public: const Value *convertToObject(const Value *value); QString typeId(const Value *value); - const Value *call(const FunctionValue *function, const QList<const Value *> &actuals = QList<const Value *>()); - const Value *call(const FunctionValue *function, const ObjectValue *thisValue, - const QList<const Value *> &actuals = QList<const Value *>()); - private: void initializePrototypes(); diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp index 8cce3c3c4d6bf80d0f74c22fc68b07267c5b6d2a..eff8925820ba044911c52a22df427c4f3d75521b 100644 --- a/src/plugins/qmljseditor/qmlcodecompletion.cpp +++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp @@ -300,7 +300,7 @@ protected: }; -class EnumerateProperties +class EnumerateProperties: private Interpreter::MemberProcessor { QSet<const Interpreter::ObjectValue *> _processed; QHash<QString, const Interpreter::Value *> _properties; @@ -315,6 +315,12 @@ public: } private: + virtual bool processMember(const QString &name, const Interpreter::Value *value) + { + _properties.insert(name, value); + return true; + } + void enumerateProperties(const Interpreter::Value *value) { if (! value) @@ -332,9 +338,7 @@ private: _processed.insert(object); enumerateProperties(object->prototype()); - for (Interpreter::ObjectValue::MemberIterator it = object->firstMember(); it != object->lastMember(); ++it) { - _properties.insert(it.key(), it.value()); - } + object->processMembers(this); } };